1 /* sonar.c --- Simulate a sonar screen.
3 * This is an implementation of a general purpose reporting tool in the
4 * format of a Sonar display. It is designed such that a sensor is read
5 * on every movement of a sweep arm and the results of that sensor are
6 * displayed on the screen. The location of the display points (targets) on the
7 * screen are determined by the current localtion of the sweep and a distance
8 * value associated with the target.
10 * Currently the only two sensors that are implemented are the simulator
11 * (the default) and the ping sensor. The simulator randomly creates a set
12 * of bogies that move around on the scope while the ping sensor can be
13 * used to display hosts on your network.
15 * The ping code is only compiled in if you define HAVE_ICMP or HAVE_ICMPHDR,
16 * because, unfortunately, different systems have different ways of creating
17 * these sorts of packets.
19 * Also: creating an ICMP socket is a privileged operation, so the program
20 * needs to be installed SUID root if you want to use the ping mode. If you
21 * check the code you will see that this privilige is given up immediately
22 * after the socket is created.
24 * It should be easy to extend this code to support other sorts of sensors.
26 * - search the output of "netstat" for the list of hosts to ping;
27 * - plot the contents of /proc/interrupts;
28 * - plot the process table, by process size, cpu usage, or total time;
29 * - plot the logged on users by idle time or cpu usage.
31 * Copyright (C) 1998, 2001
32 * by Stephen Martin (smartin@vanderfleet-martin.net).
33 * Permission to use, copy, modify, distribute, and sell this software and its
34 * documentation for any purpose is hereby granted without fee, provided that
35 * the above copyright notice appear in all copies and that both that
36 * copyright notice and this permission notice appear in supporting
37 * documentation. No representations are made about the suitability of this
38 * software for any purpose. It is provided "as is" without express or
43 * Version 1.0 April 27, 1998.
45 * - Submitted to RedHat Screensaver Contest
47 * Version 1.1 November 3, 1998.
48 * - Added simulation mode.
49 * - Added enhancements by Thomas Bahls <thommy@cs.tu-berlin.de>
50 * - Fixed huge memory leak.
51 * - Submitted to xscreensavers
54 * - All ping code is now ifdef-ed by the compile time symbol HAVE_PING;
55 * use -DHAVE_PING to include it when you compile.
56 * - Sweep now uses gradients.
57 * - Fixed portability problems with icmphdr on some systems.
58 * - removed lowColor option/resource.
59 * - changed copyright notice so that it could be included in the xscreensavers
62 * Version 1.3 November 16, 1998.
63 * - All ping code is now ifdef-ed by the compile time symbol PING use -DPING
64 * to include it when you compile.
65 * - Sweep now uses gradients.
66 * - Fixed portability problems with icmphdr on some systems.
67 * - removed lowcolour option/resource.
68 * - changed copyright notice so that it could be included in the xscreensavers
71 * Version 1.4 November 18, 1998.
72 * - More ping portability fixes.
74 * Version 1.5 November 19, 1998.
75 * - Synced up with jwz's changes.
76 * - Now need to define HAVE_PING to compile in the ping stuff.
79 /* These are computed by configure now:
92 #include "screenhack.h"
96 #if defined(HAVE_ICMP) || defined(HAVE_ICMPHDR)
101 # include <sys/types.h>
102 # include <sys/time.h>
103 # include <sys/ipc.h>
104 # include <sys/shm.h>
105 # include <sys/socket.h>
106 # include <netinet/in_systm.h>
107 # include <netinet/in.h>
108 # include <netinet/ip.h>
109 # include <netinet/ip_icmp.h>
110 # include <netinet/udp.h>
111 # include <arpa/inet.h>
113 #endif /* HAVE_ICMP || HAVE_ICMPHDR */
119 #define MY_MIN(a,b) ((a)<(b)?(a - 50):(b - 10))
122 # define LINE_MAX 2048
127 #if defined(HAVE_ICMP)
130 # define ICMP_TYPE(p) (p)->icmp_type
131 # define ICMP_CODE(p) (p)->icmp_code
132 # define ICMP_CHECKSUM(p) (p)->icmp_cksum
133 # define ICMP_ID(p) (p)->icmp_id
134 # define ICMP_SEQ(p) (p)->icmp_seq
135 #elif defined(HAVE_ICMPHDR)
137 # define ICMP icmphdr
138 # define ICMP_TYPE(p) (p)->type
139 # define ICMP_CODE(p) (p)->code
140 # define ICMP_CHECKSUM(p) (p)->checksum
141 # define ICMP_ID(p) (p)->un.echo.id
142 # define ICMP_SEQ(p) (p)->un.echo.sequence
149 # if defined(__DECC) || defined(_IP_VHL)
150 /* This is how you do it on DEC C, and possibly some BSD systems. */
151 # define IP_HDRLEN(ip) ((ip)->ip_vhl & 0x0F)
153 /* This is how you do it on everything else. */
154 # define IP_HDRLEN(ip) ((ip)->ip_hl)
156 #endif /* HAVE_PING */
159 /* Forward References */
162 static u_short checksum(u_short *, int);
164 static long delta(struct timeval *, struct timeval *);
167 /* Data Structures */
172 * This represents an object that is visible on the scope.
175 typedef struct Bogie {
176 char *name; /* The name of the thing being displayed */
177 char *desc; /* Beneath the name (e.g., ping time) */
178 int distance; /* The distance to this thing (0 - 100) */
179 int tick; /* The tick that it was found on */
180 int ttl; /* The time to live */
181 int age; /* How long it's been around */
182 struct Bogie *next; /* The next one in the list */
188 * This contains all of the runtime information about the sonar scope.
192 Display *dpy; /* The X display */
193 Window win; /* The window */
194 GC hi, /* The leading edge of the sweep */
195 lo, /* The trailing part of the sweep */
196 erase, /* Used to erase things */
197 grid, /* Used to draw the grid */
198 text; /* Used to draw text */
199 Colormap cmap; /* The colormap */
200 XFontStruct *font; /* The font to use for the labels */
201 int text_steps; /* How many steps to fade text. */
202 XColor *text_colors; /* Pixel values used to fade text */
203 int sweep_degrees; /* How much of the circle the sweep uses */
204 int sweep_segs; /* How many gradients in the sweep. */
205 XColor *sweep_colors; /* The sweep pixel values */
206 int width, height; /* Window dimensions */
207 int minx, miny, maxx, maxy, /* Bounds of the scope */
208 centrex, centrey, radius; /* Parts of the scope circle */
209 Bogie *visible; /* List of visible objects */
210 int current; /* Current position of sweep */
211 int sweepnum; /* The current id of the sweep */
212 int delay; /* how long between each frame of the anim */
214 int TTL; /* The number of ticks that bogies are visible
215 on the screen before they fade away. */
218 static Bool debug_p = False;
219 static Bool resolve_p = True;
220 static Bool times_p = True;
224 * Variables to support the differnt Sonar modes.
227 Bogie *(*sensor)(sonar_info *, void *); /* The current sensor */
228 void *sensor_info; /* Information about the sensor */
231 * A list of targets to ping.
234 typedef struct ping_target {
235 char *name; /* The name of the target */
237 struct sockaddr address; /* The address of the target */
238 #endif /* HAVE_PING */
239 struct ping_target *next; /* The next one in the list */
247 * This contains the information for the ping sensor.
251 int icmpsock; /* Socket for sending pings */
252 int pid; /* Our process ID */
253 int seq; /* Packet sequence number */
254 int timeout; /* Timeout value for pings */
255 ping_target *targets; /* List of targets to ping */
256 int numtargets; /* The number of targets to ping */
259 /* Flag to indicate that the timer has expired on us */
261 static int timer_expired;
263 #endif /* HAVE_PING */
266 * A list of targets for the simulator
269 typedef struct sim_target {
270 char *name; /* The name of the target */
271 int nexttick; /* The next tick that this will be seen */
272 int nextdist; /* The distance on that tick */
273 int movedonsweep; /* The number of the sweep this last moved */
277 * Simulator Information.
279 * This contains the information for the simulator mode.
283 sim_target *teamA; /* The bogies for the A team */
284 int numA; /* The number of bogies in team A */
285 char *teamAID; /* The identifier for bogies in team A */
286 sim_target *teamB; /* The bogies for the B team */
287 int numB; /* The number of bogies in team B */
288 char *teamBID; /* The identifier for bogies in team B */
291 /* Name of the Screensaver hack */
293 char *progclass="sonar";
295 /* Application Defaults */
297 char *defaults [] = {
298 ".background: #000000",
299 ".sweepColor: #00FF00",
301 "*scopeColor: #003300",
302 "*gridColor: #00AA00",
303 "*textColor: #FFFF00",
309 "*textSteps: 80", /* npixels */
310 "*sweepSegments: 80", /* npixels */
312 "*pingTimeout: 3000",
326 /* Options passed to this program */
328 XrmOptionDescRec options [] = {
329 {"-background", ".background", XrmoptionSepArg, 0 },
330 {"-sweep-color", ".sweepColor", XrmoptionSepArg, 0 },
331 {"-scope-color", ".scopeColor", XrmoptionSepArg, 0 },
332 {"-grid-color", ".gridColor", XrmoptionSepArg, 0 },
333 {"-text-color", ".textColor", XrmoptionSepArg, 0 },
334 {"-ttl", ".ttl", XrmoptionSepArg, 0 },
335 {"-font", ".font", XrmoptionSepArg, 0 },
337 {"-ping-timeout", ".pingTimeout", XrmoptionSepArg, 0 },
338 #endif /* HAVE_PING */
339 {"-team-a-name", ".teamAName", XrmoptionSepArg, 0 },
340 {"-team-b-name", ".teamBName", XrmoptionSepArg, 0 },
341 {"-team-a-count", ".teamACount", XrmoptionSepArg, 0 },
342 {"-team-b-count", ".teamBCount", XrmoptionSepArg, 0 },
344 {"-ping", ".ping", XrmoptionSepArg, 0 },
345 {"-no-dns", ".resolve", XrmoptionNoArg, "False" },
346 {"-no-times", ".showTimes", XrmoptionNoArg, "False" },
347 {"-debug", ".debug", XrmoptionNoArg, "True" },
352 * Create a new Bogie and set some initial values.
355 * name - The name of the bogie.
356 * distance - The distance value.
357 * tick - The tick value.
358 * ttl - The time to live value.
361 * The newly allocated bogie or null if a memory problem occured.
365 newBogie(char *name, int distance, int tick, int ttl)
368 /* Local Variables */
373 /* Allocate a bogie and initialize it */
375 if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) {
376 fprintf(stderr, "%s: Out of Memory\n", progname);
380 new->distance = distance;
384 new->next = (Bogie *) 0;
392 * b - The bogie to free.
399 if (b->name != (char *) 0)
405 * Find a bogie by name in a list.
407 * This does a simple linear search of the list for a given name.
410 * bl - The Bogie list to search.
411 * name - The name to look for.
414 * The requested Bogie or null if it wasn't found.
418 findNode(Bogie *bl, char *name)
421 /* Local Variables */
425 /* Abort if the list is empty or no name is given */
427 if ((name == NULL) || (bl == NULL))
430 /* Search the list for the desired name */
434 if (strcmp(p->name, name) == 0)
446 /* Packs an IP address quad into bigendian network order. */
448 pack_addr (unsigned int a, unsigned int b, unsigned int c, unsigned int d)
450 unsigned long i = (((a & 255) << 24) |
457 /* Unpacks an IP address quad from bigendian network order. */
459 unpack_addr (unsigned long addr,
460 unsigned int *a, unsigned int *b,
461 unsigned int *c, unsigned int *d)
464 *a = (addr >> 24) & 255;
465 *b = (addr >> 16) & 255;
466 *c = (addr >> 8) & 255;
472 * Lookup the address for a ping target;
475 * target - The ping_target fill in the address for.
478 * 1 if the host was successfully resolved, 0 otherwise.
482 lookupHost(ping_target *target)
484 struct hostent *hent;
485 struct sockaddr_in *iaddr;
490 iaddr = (struct sockaddr_in *) &(target->address);
491 iaddr->sin_family = AF_INET;
493 if (4 == sscanf (target->name, " %u.%u.%u.%u %c",
494 &ip[0], &ip[1], &ip[2], &ip[3], &c))
496 /* It's an IP address.
501 fprintf (stderr, "%s: ignoring bogus IP %s\n",
502 progname, target->name);
506 iaddr->sin_addr.s_addr = pack_addr (ip[0], ip[1], ip[2], ip[3]);
508 hent = gethostbyaddr ((const char *) &iaddr->sin_addr.s_addr,
509 sizeof(iaddr->sin_addr.s_addr),
515 fprintf (stderr, "%s: %s => %s\n",
516 progname, target->name,
517 ((hent && hent->h_name && *hent->h_name)
518 ? hent->h_name : "<unknown>"));
520 if (hent && hent->h_name && *hent->h_name)
521 target->name = strdup (hent->h_name);
529 /* don't waste time being confused by non-hostname tokens
530 in .ssh/known_hosts */
531 if (!strcmp (target->name, "ssh-rsa") ||
532 !strcmp (target->name, "ssh-dsa") ||
533 !strcmp (target->name, "ssh-dss") ||
534 strlen (target->name) >= 80)
537 hent = gethostbyname (target->name);
540 fprintf (stderr, "%s: could not resolve host: %s\n",
541 progname, target->name);
545 memcpy (&iaddr->sin_addr, hent->h_addr_list[0],
546 sizeof(iaddr->sin_addr));
550 unsigned int a, b, c, d;
551 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
552 fprintf (stderr, "%s: %s => %d.%d.%d.%d\n",
553 progname, target->name, a, b, c, d);
561 print_host (FILE *out, unsigned long ip, const char *name)
564 unsigned int a, b, c, d;
565 unpack_addr (ip, &a, &b, &c, &d); /* ip is in network order */
566 sprintf (ips, "%u.%u.%u.%u", a, b, c, d);
567 if (!name || !*name) name = "<unknown>";
568 fprintf (out, "%-16s %s\n", ips, name);
573 * Create a target for a host.
576 * name - The name of the host.
579 * A newly allocated target or null if the host could not be resolved.
586 /* Local Variables */
588 ping_target *target = NULL;
590 /* Create the target */
592 if ((target = calloc(1, sizeof(ping_target))) == NULL) {
593 fprintf(stderr, "%s: Out of Memory\n", progname);
594 goto target_init_error;
596 if ((target->name = strdup(name)) == NULL) {
597 fprintf(stderr, "%s: Out of Memory\n", progname);
598 goto target_init_error;
601 /* Lookup the host */
603 if (! lookupHost(target))
604 goto target_init_error;
606 /* Don't ever use loopback (127.0.0.x) hosts */
608 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
609 unsigned long ip = iaddr->sin_addr.s_addr;
611 if ((ntohl (ip) & 0xFFFFFF00L) == 0x7f000000L) /* 127.0.0 */
614 fprintf (stderr, "%s: ignoring loopback host %s\n",
615 progname, target->name);
616 goto target_init_error;
624 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
625 unsigned long ip = iaddr->sin_addr.s_addr;
626 fprintf (stderr, "%s: added ", progname);
627 print_host (stderr, ip, target->name);
632 /* Handle errors here */
641 * Generate a list of ping targets from the entries in a file.
644 * fname - The name of the file. This file is expected to be in the same
645 * format as /etc/hosts.
648 * A list of targets to ping or null if an error occured.
652 readPingHostsFile(char *fname)
654 /* Local Variables */
659 ping_target *list = NULL;
663 /* Make sure we in fact have a file to process */
665 if ((fname == NULL) || (fname[0] == '\0')) {
666 fprintf(stderr, "%s: invalid ping host file name\n", progname);
672 if ((fp = fopen(fname, "r")) == NULL) {
674 sprintf(msg, "%s: unable to open host file %s", progname, fname);
680 fprintf (stderr, "%s: reading file %s\n", progname, fname);
682 /* Read the file line by line */
684 while ((p = fgets(buf, LINE_MAX, fp)) != NULL) {
687 * Parse the line skipping those that start with '#'.
688 * The rest of the lines in the file should be in the same
689 * format as a /etc/hosts file. We are only concerned with
690 * the first two field, the IP address and the name
693 while ((*p == ' ') || (*p == '\t'))
698 /* Get the name and address */
701 if ((addr = strtok(buf, " ,;\t\n")) != NULL)
702 name = strtok(NULL, " ,;\t\n");
706 /* Check to see if the addr looks like an addr. If not, assume
707 the addr is a name and there is no addr. This way, we can
708 handle files whose lines have "xx.xx.xx.xx hostname" as their
709 first two tokens, and also files that have a hostname as their
710 first token (like .ssh/known_hosts and .rhosts.)
714 if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c))
721 /* If the name is all digits, it's not a name. */
725 for (s = name; *s; s++)
726 if (*s < '0' || *s > '9')
731 fprintf (stderr, "%s: skipping bogus name \"%s\" (%s)\n",
732 progname, name, addr);
737 /* Create a new target using first the name then the address */
742 if (new == NULL && addr != NULL)
745 /* Add it to the list if we got one */
753 /* Close the file and return the list */
761 delete_duplicate_hosts (ping_target *list)
763 ping_target *head = list;
766 for (rest = head; rest; rest = rest->next)
768 struct sockaddr_in *i1 = (struct sockaddr_in *) &(rest->address);
769 unsigned long ip1 = i1->sin_addr.s_addr;
771 static ping_target *rest2;
772 for (rest2 = rest; rest2; rest2 = rest2->next)
774 if (rest2 && rest2->next)
776 struct sockaddr_in *i2 = (struct sockaddr_in *)
777 &(rest2->next->address);
778 unsigned long ip2 = i2->sin_addr.s_addr;
784 fprintf (stderr, "%s: deleted duplicate: ", progname);
785 print_host (stderr, ip2, rest2->next->name);
787 rest2->next = rest2->next->next;
800 * Generate a list ping targets consisting of all of the entries on
801 * the same subnet. 'base' ip is in network order; 0 means localhost.
804 * A list of all of the hosts on this net.
808 subnetHostsList(unsigned long n_base, int subnet_width)
810 unsigned long h_mask; /* host order */
811 unsigned long h_base; /* host order */
813 /* Local Variables */
815 char hostname[BUFSIZ];
816 char address[BUFSIZ];
817 struct hostent *hent;
821 ping_target *list = NULL;
823 if (subnet_width < 24)
826 "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n"
827 " or more (255 hosts max.)\n",
828 progname, (unsigned long) (1L << (32 - subnet_width)) - 1);
831 else if (subnet_width > 30)
833 fprintf (stderr, "%s: a subnet of %d bits doesn't make sense:"
834 " try \"subnet/24\" or \"subnet/29\".\n",
835 progname, subnet_width);
841 fprintf (stderr, "%s: adding %d-bit subnet\n", progname, subnet_width);
843 /* Get our hostname */
845 if (gethostname(hostname, BUFSIZ)) {
846 fprintf(stderr, "%s: unable to get local hostname\n", progname);
850 /* Get our IP address and convert it to a string */
852 if ((hent = gethostbyname(hostname)) == NULL) {
853 fprintf(stderr, "%s: unable to lookup our IP address\n", progname);
856 strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0])));
858 /* Construct targets for all addresses in this subnet */
861 for (i = 0; i < subnet_width; i++)
862 h_mask |= (1L << (31-i));
864 /* If no base IP specified, assume localhost. */
866 n_base = pack_addr (hent->h_addr_list[0][0],
867 hent->h_addr_list[0][1],
868 hent->h_addr_list[0][2],
869 hent->h_addr_list[0][3]);
870 h_base = ntohl (n_base);
872 if (h_base == 0x7F000001L) /* 127.0.0.1 in host order */
874 unsigned int a, b, c, d;
875 unpack_addr (n_base, &a, &b, &c, &d);
877 "%s: unable to determine local subnet address: \"%s\"\n"
878 " resolves to loopback address %u.%u.%u.%u.\n",
879 progname, hostname, a, b, c, d);
883 for (i = 255; i >= 0; i--) {
884 unsigned int a, b, c, d;
885 int ip = (h_base & 0xFFFFFF00L) | i; /* host order */
887 if ((ip & h_mask) != (h_base & h_mask)) /* not in mask range at all */
889 if ((ip & ~h_mask) == 0) /* broadcast address */
891 if ((ip & ~h_mask) == ~h_mask) /* broadcast address */
894 unpack_addr (htonl (ip), &a, &b, &c, &d);
895 sprintf (address, "%u.%u.%u.%u", a, b, c, d);
899 unsigned int aa, ab, ac, ad;
900 unsigned int ma, mb, mc, md;
901 unpack_addr (htonl (h_base & h_mask), &aa, &ab, &ac, &ad);
902 unpack_addr (htonl (h_mask), &ma, &mb, &mc, &md);
904 "%s: subnet: %s (%u.%u.%u.%u & %u.%u.%u.%u / %d)\n",
911 p = address + strlen(address) + 1;
914 new = newHost(address);
927 * Initialize the ping sensor.
930 * A newly allocated ping_info structure or null if an error occured.
933 static ping_target *parse_mode (Bool ping_works_p);
939 Bool socket_initted_p = False;
941 /* Local Variables */
943 ping_info *pi = NULL; /* The new ping_info struct */
944 ping_target *pt; /* Used to count the targets */
946 /* Create the ping info structure */
948 if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) {
949 fprintf(stderr, "%s: Out of memory\n", progname);
950 goto ping_init_error;
953 /* Create the ICMP socket */
955 if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0) {
956 socket_initted_p = True;
964 pi->pid = getpid() & 0xFFFF;
966 pi->timeout = get_integer_resource("pingTimeout", "PingTimeout");
968 /* Generate a list of targets */
970 pi->targets = parse_mode (socket_initted_p);
971 pi->targets = delete_duplicate_hosts (pi->targets);
977 fprintf (stderr, "%s: Target list:\n", progname);
978 for (t = pi->targets; t; t = t->next)
980 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(t->address);
981 unsigned long ip = iaddr->sin_addr.s_addr;
982 fprintf (stderr, "%s: ", progname);
983 print_host (stderr, ip, t->name);
987 /* Make sure there is something to ping */
989 if (pi->targets == NULL) {
990 goto ping_init_error;
993 /* Count the targets */
1006 /* Handle initialization errors here */
1019 * pi - The ping information strcuture.
1020 * host - The name or IP address of the host to ping (in ascii).
1024 sendping(ping_info *pi, ping_target *pt)
1027 /* Local Variables */
1034 * Note, we will send the character name of the host that we are
1035 * pinging in the packet so that we don't have to keep track of the
1036 * name or do an address lookup when it comes back.
1039 int pcktsiz = sizeof(struct ICMP) + sizeof(struct timeval) +
1040 strlen(pt->name) + 1;
1042 /* Create the ICMP packet */
1044 if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0)
1045 return; /* Out of memory */
1046 icmph = (struct ICMP *) packet;
1047 ICMP_TYPE(icmph) = ICMP_ECHO;
1048 ICMP_CODE(icmph) = 0;
1049 ICMP_CHECKSUM(icmph) = 0;
1050 ICMP_ID(icmph) = pi->pid;
1051 ICMP_SEQ(icmph) = pi->seq++;
1052 # ifdef GETTIMEOFDAY_TWO_ARGS
1053 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)],
1054 (struct timezone *) 0);
1056 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)]);
1059 strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)],
1061 ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz);
1065 if ((result = sendto(pi->icmpsock, packet, pcktsiz, 0,
1066 &pt->address, sizeof(pt->address))) != pcktsiz) {
1068 char errbuf[BUFSIZ];
1069 sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name);
1076 * Catch a signal and do nothing.
1079 * sig - The signal that was caught.
1089 * Compute the checksum on a ping packet.
1092 * packet - A pointer to the packet to compute the checksum for.
1093 * size - The size of the packet.
1096 * The computed checksum
1101 checksum(u_short *packet, int size)
1104 /* Local Variables */
1106 register int nleft = size;
1107 register u_short *w = packet;
1108 register int sum = 0;
1112 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1113 * sequential 16 bit words to it, and at the end, fold back all the
1114 * carry bits from the top 16 bits into the lower 16 bits.
1122 /* mop up an odd byte, if necessary */
1125 *(u_char *)(&answer) = *(u_char *)w ;
1126 *(1 + (u_char *)(&answer)) = 0;
1130 /* add back carry outs from top 16 bits to low 16 bits */
1132 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1133 sum += (sum >> 16); /* add carry */
1134 answer = ~sum; /* truncate to 16 bits */
1142 * Look for ping replies.
1144 * Retrieve all outstanding ping replies.
1147 * si - Information about the sonar.
1148 * pi - Ping information.
1149 * ttl - The time each bogie is to live on the screen
1152 * A Bogie list of all the machines that replied.
1156 getping(sonar_info *si, ping_info *pi)
1159 /* Local Variables */
1161 struct sockaddr from;
1162 unsigned int fromlen; /* Posix says socklen_t, but that's not portable */
1164 u_char packet[1024];
1166 struct timeval *then;
1173 struct sigaction sa;
1174 struct itimerval it;
1178 /* Set up a signal to interupt our wait for a packet */
1180 sigemptyset(&sa.sa_mask);
1182 sa.sa_handler = sigcatcher;
1183 if (sigaction(SIGALRM, &sa, 0) == -1) {
1185 sprintf(msg, "%s: unable to trap SIGALRM", progname);
1190 /* Set up a timer to interupt us if we don't get a packet */
1192 it.it_interval.tv_sec = 0;
1193 it.it_interval.tv_usec = 0;
1194 it.it_value.tv_sec = 0;
1195 it.it_value.tv_usec = pi->timeout;
1197 setitimer(ITIMER_REAL, &it, NULL);
1199 /* Wait for a result packet */
1201 fromlen = sizeof(from);
1202 while (! timer_expired) {
1203 tv.tv_usec=pi->timeout;
1206 /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */
1209 memset (&rfds, 0, sizeof(rfds));
1211 FD_SET(pi->icmpsock,&rfds);
1212 /* only wait a little while, in case we raced with the timer expiration.
1213 From Valentijn Sessink <valentyn@openoffice.nl> */
1214 if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) {
1215 result = recvfrom(pi->icmpsock, packet, sizeof(packet),
1216 0, &from, &fromlen);
1218 /* Check the packet */
1220 # ifdef GETTIMEOFDAY_TWO_ARGS
1221 gettimeofday(&now, (struct timezone *) 0);
1225 ip = (struct ip *) packet;
1226 iphdrlen = IP_HDRLEN(ip) << 2;
1227 icmph = (struct ICMP *) &packet[iphdrlen];
1228 then = (struct timeval *) &packet[iphdrlen + sizeof(struct ICMP)];
1231 /* Was the packet a reply?? */
1233 if (ICMP_TYPE(icmph) != ICMP_ECHOREPLY) {
1234 /* Ignore anything but ICMP Replies */
1235 continue; /* Nope */
1238 /* Was it for us? */
1240 if (ICMP_ID(icmph) != pi->pid) {
1241 /* Ignore packets not set from us */
1242 continue; /* Nope */
1245 /* Copy the name of the bogie */
1248 strdup((char *) &packet[iphdrlen +
1249 + sizeof(struct ICMP)
1250 + sizeof(struct timeval)])) == NULL) {
1251 fprintf(stderr, "%s: Out of memory\n", progname);
1255 # if 0 /* Don't need to do this -- the host names are already as
1256 resolved as they're going to get. (We stored the resolved
1257 name in the outgoing ping packet, so that same string just
1261 /* If the name is an IP addr, try to resolve it. */
1265 if (4 == sscanf(name, " %d.%d.%d.%d %c",
1266 &iip[0], &iip[1], &iip[2], &iip[3], &c))
1268 struct sockaddr_in iaddr;
1270 iaddr.sin_addr.s_addr = pack_addr (iip[0],iip[1],iip[2],iip[3]);
1272 h = gethostbyaddr ((const char *) &iaddr.sin_addr.s_addr,
1273 sizeof(iaddr.sin_addr.s_addr),
1278 if (h && h->h_name && *h->h_name)
1281 name = strdup (h->h_name);
1287 /* Create the new Bogie and add it to the list we are building */
1289 if ((new = newBogie(name, 0, si->current, si->TTL)) == NULL)
1295 float msec = delta(then, &now) / 1000.0;
1299 if (new->desc) free (new->desc);
1300 new->desc = (char *) malloc (30);
1301 if (msec > 99) sprintf (new->desc, " %.0f ms ", msec);
1302 else if (msec > 9) sprintf (new->desc, " %.1f ms ", msec);
1303 else if (msec > 1) sprintf (new->desc, " %.2f ms ", msec);
1304 else sprintf (new->desc, " %.3f ms ", msec);
1307 if (debug_p && times_p) /* print ping-like stuff to stdout */
1309 struct sockaddr_in *iaddr = (struct sockaddr_in *) &from;
1310 unsigned int a, b, c, d;
1312 char *s = strdup (new->desc);
1313 char *s2 = s, *s3 = s;
1314 while (*s2 == ' ') s2++;
1315 s3 = strchr (s2, ' ');
1318 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
1319 sprintf (ipstr, "%d.%d.%d.%d", a, b, c, d);
1322 "%3d bytes from %28s: "
1323 "icmp_seq=%-4d ttl=%d time=%s ms\n",
1327 ICMP_SEQ(icmph), si->TTL, s2);
1331 /* Don't put anyone *too* close to the center of the screen. */
1334 new->distance = msec * 10;
1348 * si - Sonar Information.
1349 * pi - Ping Information.
1352 * A list of hosts that replied to pings or null if there were none.
1356 ping(sonar_info *si, void *vpi)
1360 * This tries to distribute the targets evely around the field of the
1364 ping_info *pi = (ping_info *) vpi;
1365 static ping_target *ptr = NULL;
1367 int tick = si->current * -1 + 1;
1368 if ((ptr == NULL) && (tick == 1))
1371 if (pi->numtargets <= 90) {
1372 int xdrant = 90 / pi->numtargets;
1373 if ((tick % xdrant) == 0) {
1374 if (ptr != (ping_target *) 0) {
1380 } else if (pi->numtargets > 90) {
1381 if (ptr != (ping_target *) 0) {
1387 /* Get the results */
1389 return getping(si, pi);
1392 #endif /* HAVE_PING */
1395 * Calculate the difference between two timevals in microseconds.
1398 * then - The older timeval.
1399 * now - The newer timeval.
1402 * The difference between the two in microseconds.
1406 delta(struct timeval *then, struct timeval *now)
1408 return (((now->tv_sec - then->tv_sec) * 1000000) +
1409 (now->tv_usec - then->tv_usec));
1413 * Initialize the simulation mode.
1420 /* Local Variables */
1425 /* Create the simulation info structure */
1427 if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) {
1428 fprintf(stderr, "%s: Out of memory\n", progname);
1434 si->numA = get_integer_resource("teamACount", "TeamACount");
1435 if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target)))
1438 fprintf(stderr, "%s: Out of Memory\n", progname);
1441 si->teamAID = get_string_resource("teamAName", "TeamAName");
1442 for (i = 0; i < si->numA; i++) {
1443 if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4))
1446 fprintf(stderr, "%s: Out of Memory\n", progname);
1449 sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1);
1450 si->teamA[i].nexttick = random() % 90;
1451 si->teamA[i].nextdist = random() % 100;
1452 si->teamA[i].movedonsweep = -1;
1457 si->numB = get_integer_resource("teamBCount", "TeamBCount");
1458 if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target)))
1461 fprintf(stderr, "%s: Out of Memory\n", progname);
1464 si->teamBID = get_string_resource("teamBName", "TeamBName");
1465 for (i = 0; i < si->numB; i++) {
1466 if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4))
1469 fprintf(stderr, "%s: Out of Memory\n", progname);
1472 sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1);
1473 si->teamB[i].nexttick = random() % 90;
1474 si->teamB[i].nextdist = random() % 100;
1475 si->teamB[i].movedonsweep = -1;
1484 * Creates and returns a drawing mask for the scope:
1485 * mask out anything outside of the disc.
1488 scope_mask (Display *dpy, Window win, sonar_info *si)
1491 Pixmap mask = XCreatePixmap(dpy, win, si->width, si->height, 1);
1492 GC gc = XCreateGC (dpy, mask, 0, &gcv);
1493 XSetFunction (dpy, gc, GXclear);
1494 XFillRectangle (dpy, mask, gc, 0, 0, si->width, si->height);
1495 XSetFunction (dpy, gc, GXset);
1496 XFillArc(dpy, mask, gc, si->minx, si->miny,
1497 si->maxx - si->minx, si->maxy - si->miny,
1504 reshape (sonar_info *si)
1506 XWindowAttributes xgwa;
1508 XGetWindowAttributes(si->dpy, si->win, &xgwa);
1509 si->width = xgwa.width;
1510 si->height = xgwa.height;
1511 si->centrex = si->width / 2;
1512 si->centrey = si->height / 2;
1513 si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
1514 si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
1515 si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
1516 si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
1517 si->radius = si->maxx - si->centrex;
1519 /* Install the clip mask... */
1520 mask = scope_mask (si->dpy, si->win, si);
1521 XSetClipMask(si->dpy, si->text, mask);
1522 XSetClipMask(si->dpy, si->erase, mask);
1523 XFreePixmap (si->dpy, mask); /* it's been copied into the GCs */
1527 * Initialize the Sonar.
1530 * dpy - The X display.
1531 * win - The X window;
1534 * A sonar_info strcuture or null if memory allocation problems occur.
1538 init_sonar(Display *dpy, Window win)
1541 /* Local Variables */
1544 XWindowAttributes xwa;
1548 double s1, s2, v1, v2;
1550 /* Create the Sonar information structure */
1552 if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) {
1553 fprintf(stderr, "%s: Out of memory\n", progname);
1557 /* Initialize the structure for the current environment */
1563 XGetWindowAttributes(dpy, win, &xwa);
1564 si->cmap = xwa.colormap;
1571 if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font")))
1573 ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) {
1574 fprintf(stderr, "%s: can't load an appropriate font\n", progname);
1578 /* Get the delay between animation frames */
1580 si->delay = get_integer_resource ("delay", "Integer");
1582 if (si->delay < 0) si->delay = 0;
1583 si->TTL = get_integer_resource("ttl", "TTL");
1585 /* Create the Graphics Contexts that will be used to draw things */
1588 get_pixel_resource ("sweepColor", "SweepColor", dpy, si->cmap);
1589 si->hi = XCreateGC(dpy, win, GCForeground, &gcv);
1590 gcv.font = si->font->fid;
1591 si->text = XCreateGC(dpy, win, GCForeground|GCFont, &gcv);
1592 gcv.foreground = get_pixel_resource("scopeColor", "ScopeColor",
1594 si->erase = XCreateGC (dpy, win, GCForeground, &gcv);
1595 gcv.foreground = get_pixel_resource("gridColor", "GridColor",
1597 si->grid = XCreateGC (dpy, win, GCForeground, &gcv);
1601 /* Compute pixel values for fading text on the display */
1603 XParseColor(dpy, si->cmap,
1604 get_string_resource("textColor", "TextColor"), &start);
1605 XParseColor(dpy, si->cmap,
1606 get_string_resource("scopeColor", "ScopeColor"), &end);
1608 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1609 rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
1611 si->text_steps = get_integer_resource("textSteps", "TextSteps");
1612 if (si->text_steps < 0 || si->text_steps > 255)
1613 si->text_steps = 10;
1615 si->text_colors = (XColor *) calloc(si->text_steps, sizeof(XColor));
1616 make_color_ramp (dpy, si->cmap,
1619 si->text_colors, &si->text_steps,
1620 False, True, False);
1622 /* Compute the pixel values for the fading sweep */
1624 XParseColor(dpy, si->cmap,
1625 get_string_resource("sweepColor", "SweepColor"), &start);
1627 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1629 si->sweep_degrees = get_integer_resource("sweepDegrees", "Degrees");
1630 if (si->sweep_degrees <= 0) si->sweep_degrees = 20;
1631 if (si->sweep_degrees > 350) si->sweep_degrees = 350;
1633 si->sweep_segs = get_integer_resource("sweepSegments", "SweepSegments");
1634 if (si->sweep_segs < 1 || si->sweep_segs > 255)
1635 si->sweep_segs = 255;
1637 si->sweep_colors = (XColor *) calloc(si->sweep_segs, sizeof(XColor));
1638 make_color_ramp (dpy, si->cmap,
1641 si->sweep_colors, &si->sweep_segs,
1642 False, True, False);
1644 if (si->sweep_segs <= 0)
1653 * Update the location of a simulated bogie.
1657 updateLocation(sim_target *t)
1662 xtick = (int) (random() % 3) - 1;
1663 xdist = (int) (random() % 11) - 5;
1664 if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0))
1665 t->nexttick += xtick;
1667 t->nexttick -= xtick;
1668 if (((t->nextdist + xdist) < 100) && ((t->nextdist+xdist) >= 0))
1669 t->nextdist += xdist;
1671 t->nextdist -= xdist;
1675 * The simulator. This uses information in the sim_info to simulate a bunch
1676 * of bogies flying around on the screen.
1680 * TODO: It would be cool to have the two teams chase each other around and
1685 simulator(sonar_info *si, void *vinfo)
1688 /* Local Variables */
1694 sim_info *info = (sim_info *) vinfo;
1698 for (i = 0; i < info->numA; i++) {
1699 t = &info->teamA[i];
1700 if ((t->movedonsweep != si->sweepnum) &&
1701 (t->nexttick == (si->current * -1))) {
1702 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1707 t->movedonsweep = si->sweepnum;
1713 for (i = 0; i < info->numB; i++) {
1714 t = &info->teamB[i];
1715 if ((t->movedonsweep != si->sweepnum) &&
1716 (t->nexttick == (si->current * -1))) {
1717 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1722 t->movedonsweep = si->sweepnum;
1732 * Compute the X coordinate of the label.
1735 * si - The sonar info block.
1736 * label - The label that will be drawn.
1737 * x - The x coordinate of the bogie.
1740 * The x coordinate of the start of the label.
1744 computeStringX(sonar_info *si, const char *label, int x)
1747 int width = XTextWidth(si->font, label, strlen(label));
1748 return x - (width / 2);
1752 * Compute the Y coordinate of the label.
1755 * si - The sonar information.
1756 * y - The y coordinate of the bogie.
1759 * The y coordinate of the start of the label.
1763 computeStringY(sonar_info *si, int y)
1766 int fheight = si->font->ascent /* + si->font->descent */;
1771 * Draw a Bogie on the radar screen.
1774 * si - Sonar Information.
1775 * draw - A flag to indicate if the bogie should be drawn or erased.
1776 * name - The name of the bogie.
1777 * degrees - The number of degrees that it should apprear at.
1778 * distance - The distance the object is from the centre.
1779 * ttl - The time this bogie has to live.
1780 * age - The time this bogie has been around.
1784 DrawBogie(sonar_info *si, int draw, const char *name, const char *desc,
1785 int degrees, int distance, int ttl, int age)
1788 /* Local Variables */
1792 int ox = si->centrex;
1793 int oy = si->centrey;
1796 /* Compute the coordinates of the object */
1799 distance = (log((double) distance) / 10.0) * si->radius;
1800 x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578));
1801 y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578));
1803 /* Set up the graphics context */
1807 /* Here we attempt to compute the distance into the total life of
1808 * object that we currently are. This distance is used against
1809 * the total lifetime to compute a fraction which is the index of
1810 * the color to draw the bogie.
1813 if (si->current <= degrees)
1814 delta = (si->current - degrees) * -1;
1816 delta = 90 + (degrees - si->current);
1817 delta += (age * 90);
1818 index = (si->text_steps - 1) * ((float) delta / (90.0 * (float) ttl));
1820 XSetForeground(si->dpy, gc, si->text_colors[index].pixel);
1825 /* Draw (or erase) the Bogie */
1827 XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64);
1829 x += 3; /* move away from the dot */
1831 y = computeStringY(si, y);
1832 XDrawString(si->dpy, si->win, gc,
1833 computeStringX(si, name, x), y,
1834 name, strlen(name));
1838 y = computeStringY(si, y);
1839 XDrawString(si->dpy, si->win, gc,
1840 computeStringX(si, desc, x), y,
1841 desc, strlen(desc));
1847 * Draw the sonar grid.
1850 * si - Sonar information block.
1854 drawGrid(sonar_info *si)
1857 /* Local Variables */
1860 int width = si->maxx - si->minx;
1861 int height = si->maxy - si->miny;
1863 /* Draw the circles */
1865 XDrawArc(si->dpy, si->win, si->grid, si->minx - 10, si->miny - 10,
1866 width + 20, height + 20, 0, (360 * 64));
1868 XDrawArc(si->dpy, si->win, si->grid, si->minx, si->miny,
1869 width, height, 0, (360 * 64));
1871 XDrawArc(si->dpy, si->win, si->grid,
1872 (int) (si->minx + (.166 * width)),
1873 (int) (si->miny + (.166 * height)),
1874 (unsigned int) (.666 * width), (unsigned int)(.666 * height),
1877 XDrawArc(si->dpy, si->win, si->grid,
1878 (int) (si->minx + (.333 * width)),
1879 (int) (si->miny + (.333 * height)),
1880 (unsigned int) (.333 * width), (unsigned int) (.333 * height),
1883 /* Draw the radial lines */
1885 for (i = 0; i < 360; i += 10)
1887 XDrawLine(si->dpy, si->win, si->grid, si->centrex, si->centrey,
1888 (int) (si->centrex +
1889 (si->radius + 10) * (cos((double) i / 57.29578))),
1890 (int) (si->centrey -
1891 (si->radius + 10)*(sin((double) i / 57.29578))));
1893 XDrawLine(si->dpy, si->win, si->grid,
1894 (int) (si->centrex + si->radius *
1895 (cos((double) i / 57.29578))),
1896 (int) (si->centrey - si->radius *
1897 (sin((double) i / 57.29578))),
1898 (int) (si->centrex +
1899 (si->radius + 10) * (cos((double) i / 57.29578))),
1900 (int) (si->centrey -
1901 (si->radius + 10) * (sin((double) i / 57.29578))));
1905 * Update the Sonar scope.
1908 * si - The Sonar information.
1909 * bl - A list of bogies to add to the scope.
1913 Sonar(sonar_info *si, Bogie *bl)
1916 /* Local Variables */
1921 /* Check for expired tagets and remove them from the visible list */
1924 for (bp = si->visible; bp != NULL; bp = (bp ? bp->next : 0)) {
1927 * Remove it from the visible list if it's expired or we have
1928 * a new target with the same name.
1933 if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) ||
1934 (findNode(bl, bp->name) != NULL)) {
1935 DrawBogie(si, 0, bp->name, bp->desc, bp->tick,
1936 bp->distance, bp->ttl, bp->age);
1938 si->visible = bp->next;
1940 prev->next = bp->next;
1947 /* Draw the sweep */
1950 int seg_deg = (si->sweep_degrees * 64) / si->sweep_segs;
1951 int start_deg = si->current * 4 * 64;
1952 if (seg_deg <= 0) seg_deg = 1;
1953 for (i = 0; i < si->sweep_segs; i++) {
1954 XSetForeground(si->dpy, si->hi, si->sweep_colors[i].pixel);
1955 XFillArc(si->dpy, si->win, si->hi, si->minx, si->miny,
1956 si->maxx - si->minx, si->maxy - si->miny,
1957 start_deg + (i * seg_deg),
1961 /* Remove the trailing wedge the sonar */
1962 XFillArc(si->dpy, si->win, si->erase, si->minx, si->miny,
1963 si->maxx - si->minx, si->maxy - si->miny,
1964 start_deg + (i * seg_deg),
1968 /* Move the new targets to the visible list */
1970 for (bp = bl; bp != (Bogie *) 0; bp = bl) {
1972 bp->next = si->visible;
1976 /* Draw the visible targets */
1978 for (bp = si->visible; bp != NULL; bp = bp->next) {
1979 if (bp->age < bp->ttl) /* grins */
1980 DrawBogie(si, 1, bp->name, bp->desc,
1981 bp->tick, bp->distance, bp->ttl,bp->age);
1984 /* Redraw the grid */
1990 static ping_target *
1991 parse_mode (Bool ping_works_p)
1993 char *source = get_string_resource ("ping", "Ping");
1997 ping_target *hostlist = 0;
1999 if (!source) source = strdup("");
2001 if (!*source || !strcmp (source, "default"))
2004 if (ping_works_p) /* if root or setuid, ping will work. */
2005 source = strdup("subnet/29,/etc/hosts");
2008 source = strdup("simulation");
2012 end = source + strlen(source);
2019 unsigned int n0=0, n1=0, n2=0, n3=0, m=0;
2021 # endif /* HAVE_PING */
2025 *next != ',' && *next != ' ' && *next != '\t' && *next != '\n';
2032 fprintf (stderr, "%s: parsing %s\n", progname, token);
2034 if (!strcmp (token, "simulation"))
2040 "%s: this program must be setuid to root for `ping mode' to work.\n"
2041 " Running in `simulation mode' instead.\n",
2047 if ((4 == sscanf (token, "%u.%u.%u/%u %c", &n0,&n1,&n2, &m,&d)) ||
2048 (5 == sscanf (token, "%u.%u.%u.%u/%u %c", &n0,&n1,&n2,&n3,&m,&d)))
2050 /* subnet: A.B.C.D/M
2053 unsigned long ip = pack_addr (n0, n1, n2, n3);
2054 new = subnetHostsList(ip, m);
2056 else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d))
2060 new = newHost (token);
2062 else if (!strcmp (token, "subnet"))
2064 new = subnetHostsList(0, 24);
2066 else if (1 == sscanf (token, "subnet/%u %c", &m, &dummy))
2068 new = subnetHostsList(0, m);
2070 else if (*token == '.' || *token == '/' || !stat (token, &st))
2074 new = readPingHostsFile (token);
2078 /* not an existant file - must be a host name
2080 new = newHost (token);
2085 ping_target *nn = new;
2086 while (nn && nn->next)
2088 nn->next = hostlist;
2093 #endif /* HAVE_PING */
2096 while (token < end &&
2097 (*token == ',' || *token == ' ' ||
2098 *token == '\t' || *token == '\n'))
2107 handle_events (sonar_info *si)
2109 while (XPending (si->dpy))
2112 XNextEvent (si->dpy, &event);
2114 if (event.xany.type == ConfigureNotify)
2116 XClearWindow (si->dpy, si->win);
2120 screenhack_handle_event (si->dpy, &event);
2127 * Main screen saver hack.
2130 * dpy - The X display.
2131 * win - The X window.
2135 screenhack(Display *dpy, Window win)
2138 /* Local Variables */
2141 struct timeval start, finish;
2145 debug_p = get_boolean_resource ("debug", "Debug");
2146 resolve_p = get_boolean_resource ("resolve", "Resolve");
2147 times_p = get_boolean_resource ("showTimes", "ShowTimes");
2151 sensor_info = (void *) init_ping();
2152 # else /* !HAVE_PING */
2154 parse_mode (0); /* just to check argument syntax */
2155 # endif /* !HAVE_PING */
2160 if ((sensor_info = (void *) init_sim()) == NULL)
2164 if ((si = init_sonar(dpy, win)) == (sonar_info *) 0)
2172 /* Call the sensor and display the results */
2174 # ifdef GETTIMEOFDAY_TWO_ARGS
2175 gettimeofday(&start, (struct timezone *) 0);
2177 gettimeofday(&start);
2179 bl = sensor(si, sensor_info);
2182 /* Set up and sleep for the next one */
2184 si->current = (si->current - 1) % 90;
2185 if (si->current == 0)
2188 # ifdef GETTIMEOFDAY_TWO_ARGS
2189 gettimeofday(&finish, (struct timezone *) 0);
2191 gettimeofday(&finish);
2193 sleeptime = si->delay - delta(&start, &finish);