summaryrefslogtreecommitdiffstats
path: root/query_load.c
blob: 584246f721d6c1acd8b3bd64669e47f0686e2912 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Cardinals.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#include "rxload_inet.h"

extern char *ProgramName;
extern char *remote_host, *remote_port;

extern void setbadcolor(), setgoodcolor();

extern void init_loadavg();
extern double get_loadavg();

void LocalInitLoadPoint() {
  init_loadavg();
}

void RemoteInitLoadPoint();

void LocalGetLoadPoint(w, closure, call_data)
     Widget    w;
     caddr_t   closure;
     caddr_t   call_data;
{
     double loadavg;

     loadavg = get_loadavg();
     *(double *)call_data = (loadavg < 0.0) ? 0.0 : loadavg;
}
  
void RemoteGetLoadPoint();

void (*GetLoadPoint)();

void InitLoadPoint()
{
  if ( remote_host ) {
    GetLoadPoint = RemoteGetLoadPoint;
    RemoteInitLoadPoint();
  } else {
    GetLoadPoint = LocalGetLoadPoint;
    /* LocalInitLoadPoint() is done anyway just-in-case */
  }
}

int sock = -1;

void RemoteInitLoadPoint()
{
  struct sockaddr_in remote_host_addr;
  struct servent *serv;
  struct hostent *host;

  bzero(&remote_host_addr, sizeof(remote_host_addr));

  if ( remote_port ) {
    serv = getservbyname(remote_port, "udp");
    if ( serv )
      remote_host_addr.sin_port = serv->s_port;
    else
      remote_host_addr.sin_port = htons(atoi(remote_port));
  } else {
    serv = getservbyname(DEFAULT_SERVICE, "udp");
    if ( serv )
      remote_host_addr.sin_port = serv->s_port;
    else
      remote_host_addr.sin_port = htons(DEFAULT_PORT);
  }

  host = gethostbyname(remote_host);
  if ( !host ) {
    herror(ProgramName);
    exit(1);
  }
  
  remote_host_addr.sin_family = AF_INET;
  bcopy(host->h_addr, &remote_host_addr.sin_addr, host->h_length);
  
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if ( sock < 0 ) {
    fprintf(stderr, "%s: could not create socket\n", ProgramName);
    exit(1);
  }
  if ( connect(sock, (struct sockaddr *) &remote_host_addr, sizeof(remote_host_addr)) < 0 ) {
    fprintf(stderr, "%s: could not connect socket\n", ProgramName);
    exit(1);
  }
}

void RemoteGetLoadPoint( w, closure, call_data )
     Widget   w;              /* unused */
     caddr_t  closure;        /* unused */
     caddr_t  call_data;      /* pointer to (double) return value */
{
  char buffer[65], seqid[9], *p;
  int i, j, n;
  long fdflags;
  double v;
  fd_set sockset;
  struct timeval timeout;
  Arg args[1];

  static int sequence = 100;	/* Start a little bit away from zero */

  *((double *)call_data) = 0.0;	/* In case of error */

  sprintf(seqid, "%08x", (sequence++) & 0xffffffff);

  /* Flush any already waiting packets */
  fdflags = fcntl(sock, F_GETFL);
  fdflags |= O_NDELAY;
  fcntl(sock, F_SETFL, fdflags);
  while ( recv(sock, buffer, 64, 0) > 0 );
  fdflags &= ~O_NDELAY;
  fcntl(sock, F_SETFL, fdflags);

  for ( i = 0 ; i < SOCK_TRIES ;  i++ ) {
    for ( j = 0 ; j < DGRAM_TRIES ; j++ ) {
      /* Send polling packet */
      bzero(buffer, 64);
      bcopy(seqid, buffer, 8);
      send(sock, buffer, 64, 0);
      
      /* Wait for reply */
    wait_for_packet:
      FD_ZERO(&sockset);
      FD_SET(sock, &sockset);
      timeout.tv_sec = DGRAM_TIMEOUT;
      timeout.tv_usec = 0;
      while ( select(sock+1, &sockset, NULL, NULL, &timeout) < 0 &&
	      errno == EINTR );
      
      /* Proces reply if available */
      if ( FD_ISSET(sock, &sockset) &&
	   (n = recv(sock, buffer, 64, 0)) > 8 ) {
	if ( bcmp(buffer, seqid, 8) ) {
	  /* We received a bogus packet, probably reply to a previously
	     abandoned query.  We discard this packet, but if we send out
	     a new query we may cause a packet storm on the network. */
	  goto wait_for_packet;
	}
	
	buffer[n] = '\0';
	
	if ( sscanf(buffer+8, "%lf", &v) == 1 ) {
	  *((double *)call_data) = v;
	  setgoodcolor();
	  return;
	}
      }
    }

    /* Consider the possibility the address may have changed: get the address
       anew and create a new socket */
    close(sock);
    RemoteInitLoadPoint();
  }

  setbadcolor();
  return;
}