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);
541 fprintf (stderr, "%s: could not resolve host: %s\n",
542 progname, target->name);
546 memcpy (&iaddr->sin_addr, hent->h_addr_list[0],
547 sizeof(iaddr->sin_addr));
551 unsigned int a, b, c, d;
552 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
553 fprintf (stderr, "%s: %s => %d.%d.%d.%d\n",
554 progname, target->name, a, b, c, d);
562 print_host (FILE *out, unsigned long ip, const char *name)
565 unsigned int a, b, c, d;
566 unpack_addr (ip, &a, &b, &c, &d); /* ip is in network order */
567 sprintf (ips, "%u.%u.%u.%u", a, b, c, d);
568 if (!name || !*name) name = "<unknown>";
569 fprintf (out, "%-16s %s\n", ips, name);
574 * Create a target for a host.
577 * name - The name of the host.
580 * A newly allocated target or null if the host could not be resolved.
587 /* Local Variables */
589 ping_target *target = NULL;
591 /* Create the target */
593 if ((target = calloc(1, sizeof(ping_target))) == NULL) {
594 fprintf(stderr, "%s: Out of Memory\n", progname);
595 goto target_init_error;
597 if ((target->name = strdup(name)) == NULL) {
598 fprintf(stderr, "%s: Out of Memory\n", progname);
599 goto target_init_error;
602 /* Lookup the host */
604 if (! lookupHost(target))
605 goto target_init_error;
607 /* Don't ever use loopback (127.0.0.x) hosts */
609 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
610 unsigned long ip = iaddr->sin_addr.s_addr;
612 if ((ntohl (ip) & 0xFFFFFF00L) == 0x7f000000L) /* 127.0.0.x */
615 fprintf (stderr, "%s: ignoring loopback host %s\n",
616 progname, target->name);
617 goto target_init_error;
621 /* Don't ever use broadcast (255.x.x.x) hosts */
623 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
624 unsigned long ip = iaddr->sin_addr.s_addr;
625 if ((ntohl (ip) & 0xFF000000L) == 0xFF000000L) /* 255.x.x.x */
628 fprintf (stderr, "%s: ignoring broadcast host %s\n",
629 progname, target->name);
630 goto target_init_error;
638 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
639 unsigned long ip = iaddr->sin_addr.s_addr;
640 fprintf (stderr, "%s: added ", progname);
641 print_host (stderr, ip, target->name);
646 /* Handle errors here */
655 * Generate a list of ping targets from the entries in a file.
658 * fname - The name of the file. This file is expected to be in the same
659 * format as /etc/hosts.
662 * A list of targets to ping or null if an error occured.
666 readPingHostsFile(char *fname)
668 /* Local Variables */
673 ping_target *list = NULL;
677 /* Make sure we in fact have a file to process */
679 if ((fname == NULL) || (fname[0] == '\0')) {
680 fprintf(stderr, "%s: invalid ping host file name\n", progname);
686 if ((fp = fopen(fname, "r")) == NULL) {
688 sprintf(msg, "%s: unable to open host file %s", progname, fname);
694 fprintf (stderr, "%s: reading file %s\n", progname, fname);
696 /* Read the file line by line */
698 while ((p = fgets(buf, LINE_MAX, fp)) != NULL) {
701 * Parse the line skipping those that start with '#'.
702 * The rest of the lines in the file should be in the same
703 * format as a /etc/hosts file. We are only concerned with
704 * the first two field, the IP address and the name
707 while ((*p == ' ') || (*p == '\t'))
712 /* Get the name and address */
715 if ((addr = strtok(buf, " ,;\t\n")) != NULL)
716 name = strtok(NULL, " ,;\t\n");
720 /* Check to see if the addr looks like an addr. If not, assume
721 the addr is a name and there is no addr. This way, we can
722 handle files whose lines have "xx.xx.xx.xx hostname" as their
723 first two tokens, and also files that have a hostname as their
724 first token (like .ssh/known_hosts and .rhosts.)
728 if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c))
735 /* If the name is all digits, it's not a name. */
739 for (s = name; *s; s++)
740 if (*s < '0' || *s > '9')
745 fprintf (stderr, "%s: skipping bogus name \"%s\" (%s)\n",
746 progname, name, addr);
751 /* Create a new target using first the name then the address */
756 if (new == NULL && addr != NULL)
759 /* Add it to the list if we got one */
767 /* Close the file and return the list */
775 delete_duplicate_hosts (ping_target *list)
777 ping_target *head = list;
780 for (rest = head; rest; rest = rest->next)
782 struct sockaddr_in *i1 = (struct sockaddr_in *) &(rest->address);
783 unsigned long ip1 = i1->sin_addr.s_addr;
785 static ping_target *rest2;
786 for (rest2 = rest; rest2; rest2 = rest2->next)
788 if (rest2 && rest2->next)
790 struct sockaddr_in *i2 = (struct sockaddr_in *)
791 &(rest2->next->address);
792 unsigned long ip2 = i2->sin_addr.s_addr;
798 fprintf (stderr, "%s: deleted duplicate: ", progname);
799 print_host (stderr, ip2, rest2->next->name);
801 rest2->next = rest2->next->next;
814 * Generate a list ping targets consisting of all of the entries on
815 * the same subnet. 'base' ip is in network order; 0 means localhost.
818 * A list of all of the hosts on this net.
822 subnetHostsList(unsigned long n_base, int subnet_width)
824 unsigned long h_mask; /* host order */
825 unsigned long h_base; /* host order */
827 /* Local Variables */
829 char hostname[BUFSIZ];
830 char address[BUFSIZ];
831 struct hostent *hent;
835 ping_target *list = NULL;
837 if (subnet_width < 24)
840 "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n"
841 " or more (255 hosts max.)\n",
842 progname, (unsigned long) (1L << (32 - subnet_width)) - 1);
845 else if (subnet_width > 30)
847 fprintf (stderr, "%s: a subnet of %d bits doesn't make sense:"
848 " try \"subnet/24\" or \"subnet/29\".\n",
849 progname, subnet_width);
855 fprintf (stderr, "%s: adding %d-bit subnet\n", progname, subnet_width);
857 /* Get our hostname */
859 if (gethostname(hostname, BUFSIZ)) {
860 fprintf(stderr, "%s: unable to get local hostname\n", progname);
864 /* Get our IP address and convert it to a string */
866 if ((hent = gethostbyname(hostname)) == NULL) {
867 fprintf(stderr, "%s: unable to lookup our IP address\n", progname);
870 strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0])));
872 /* Construct targets for all addresses in this subnet */
875 for (i = 0; i < subnet_width; i++)
876 h_mask |= (1L << (31-i));
878 /* If no base IP specified, assume localhost. */
880 n_base = pack_addr (hent->h_addr_list[0][0],
881 hent->h_addr_list[0][1],
882 hent->h_addr_list[0][2],
883 hent->h_addr_list[0][3]);
884 h_base = ntohl (n_base);
886 if (h_base == 0x7F000001L) /* 127.0.0.1 in host order */
888 unsigned int a, b, c, d;
889 unpack_addr (n_base, &a, &b, &c, &d);
891 "%s: unable to determine local subnet address: \"%s\"\n"
892 " resolves to loopback address %u.%u.%u.%u.\n",
893 progname, hostname, a, b, c, d);
897 for (i = 255; i >= 0; i--) {
898 unsigned int a, b, c, d;
899 int ip = (h_base & 0xFFFFFF00L) | i; /* host order */
901 if ((ip & h_mask) != (h_base & h_mask)) /* not in mask range at all */
903 if ((ip & ~h_mask) == 0) /* broadcast address */
905 if ((ip & ~h_mask) == ~h_mask) /* broadcast address */
908 unpack_addr (htonl (ip), &a, &b, &c, &d);
909 sprintf (address, "%u.%u.%u.%u", a, b, c, d);
913 unsigned int aa, ab, ac, ad;
914 unsigned int ma, mb, mc, md;
915 unpack_addr (htonl (h_base & h_mask), &aa, &ab, &ac, &ad);
916 unpack_addr (htonl (h_mask), &ma, &mb, &mc, &md);
918 "%s: subnet: %s (%u.%u.%u.%u & %u.%u.%u.%u / %d)\n",
925 p = address + strlen(address) + 1;
928 new = newHost(address);
941 * Initialize the ping sensor.
944 * A newly allocated ping_info structure or null if an error occured.
947 static ping_target *parse_mode (Bool ping_works_p);
953 Bool socket_initted_p = False;
955 /* Local Variables */
957 ping_info *pi = NULL; /* The new ping_info struct */
958 ping_target *pt; /* Used to count the targets */
960 /* Create the ping info structure */
962 if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) {
963 fprintf(stderr, "%s: Out of memory\n", progname);
964 goto ping_init_error;
967 /* Create the ICMP socket. Do this before dropping privs.
969 Raw sockets can only be opened by root (or setuid root), so we
970 only try to do this when the effective uid is 0.
972 We used to just always try, and notice the failure. But apparently
973 that causes "SELinux" to log spurious warnings when running with the
974 "strict" policy. So to avoid that, we just don't try unless we
977 if (geteuid() == 0 &&
978 (pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0) {
979 socket_initted_p = True;
987 pi->pid = getpid() & 0xFFFF;
989 pi->timeout = get_integer_resource("pingTimeout", "PingTimeout");
991 /* Generate a list of targets */
993 pi->targets = parse_mode (socket_initted_p);
994 pi->targets = delete_duplicate_hosts (pi->targets);
1000 fprintf (stderr, "%s: Target list:\n", progname);
1001 for (t = pi->targets; t; t = t->next)
1003 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(t->address);
1004 unsigned long ip = iaddr->sin_addr.s_addr;
1005 fprintf (stderr, "%s: ", progname);
1006 print_host (stderr, ip, t->name);
1010 /* Make sure there is something to ping */
1012 if (pi->targets == NULL) {
1013 goto ping_init_error;
1016 /* Count the targets */
1020 while (pt != NULL) {
1029 /* Handle initialization errors here */
1042 * pi - The ping information strcuture.
1043 * host - The name or IP address of the host to ping (in ascii).
1047 sendping(ping_info *pi, ping_target *pt)
1050 /* Local Variables */
1057 * Note, we will send the character name of the host that we are
1058 * pinging in the packet so that we don't have to keep track of the
1059 * name or do an address lookup when it comes back.
1062 int pcktsiz = sizeof(struct ICMP) + sizeof(struct timeval) +
1063 strlen(pt->name) + 1;
1065 /* Create the ICMP packet */
1067 if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0)
1068 return; /* Out of memory */
1069 icmph = (struct ICMP *) packet;
1070 ICMP_TYPE(icmph) = ICMP_ECHO;
1071 ICMP_CODE(icmph) = 0;
1072 ICMP_CHECKSUM(icmph) = 0;
1073 ICMP_ID(icmph) = pi->pid;
1074 ICMP_SEQ(icmph) = pi->seq++;
1075 # ifdef GETTIMEOFDAY_TWO_ARGS
1076 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)],
1077 (struct timezone *) 0);
1079 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)]);
1082 strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)],
1084 ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz);
1088 if ((result = sendto(pi->icmpsock, packet, pcktsiz, 0,
1089 &pt->address, sizeof(pt->address))) != pcktsiz) {
1091 char errbuf[BUFSIZ];
1092 sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name);
1099 * Catch a signal and do nothing.
1102 * sig - The signal that was caught.
1112 * Compute the checksum on a ping packet.
1115 * packet - A pointer to the packet to compute the checksum for.
1116 * size - The size of the packet.
1119 * The computed checksum
1124 checksum(u_short *packet, int size)
1127 /* Local Variables */
1129 register int nleft = size;
1130 register u_short *w = packet;
1131 register int sum = 0;
1135 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1136 * sequential 16 bit words to it, and at the end, fold back all the
1137 * carry bits from the top 16 bits into the lower 16 bits.
1145 /* mop up an odd byte, if necessary */
1148 *(u_char *)(&answer) = *(u_char *)w ;
1149 *(1 + (u_char *)(&answer)) = 0;
1153 /* add back carry outs from top 16 bits to low 16 bits */
1155 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1156 sum += (sum >> 16); /* add carry */
1157 answer = ~sum; /* truncate to 16 bits */
1165 * Look for ping replies.
1167 * Retrieve all outstanding ping replies.
1170 * si - Information about the sonar.
1171 * pi - Ping information.
1172 * ttl - The time each bogie is to live on the screen
1175 * A Bogie list of all the machines that replied.
1179 getping(sonar_info *si, ping_info *pi)
1182 /* Local Variables */
1184 struct sockaddr from;
1185 unsigned int fromlen; /* Posix says socklen_t, but that's not portable */
1187 u_char packet[1024];
1189 struct timeval *then;
1196 struct sigaction sa;
1197 struct itimerval it;
1201 /* Set up a signal to interupt our wait for a packet */
1203 sigemptyset(&sa.sa_mask);
1205 sa.sa_handler = sigcatcher;
1206 if (sigaction(SIGALRM, &sa, 0) == -1) {
1208 sprintf(msg, "%s: unable to trap SIGALRM", progname);
1213 /* Set up a timer to interupt us if we don't get a packet */
1215 it.it_interval.tv_sec = 0;
1216 it.it_interval.tv_usec = 0;
1217 it.it_value.tv_sec = 0;
1218 it.it_value.tv_usec = pi->timeout;
1220 setitimer(ITIMER_REAL, &it, NULL);
1222 /* Wait for a result packet */
1224 fromlen = sizeof(from);
1225 while (! timer_expired) {
1226 tv.tv_usec=pi->timeout;
1229 /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */
1232 memset (&rfds, 0, sizeof(rfds));
1234 FD_SET(pi->icmpsock,&rfds);
1235 /* only wait a little while, in case we raced with the timer expiration.
1236 From Valentijn Sessink <valentyn@openoffice.nl> */
1237 if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) {
1238 result = recvfrom(pi->icmpsock, packet, sizeof(packet),
1239 0, &from, &fromlen);
1241 /* Check the packet */
1243 # ifdef GETTIMEOFDAY_TWO_ARGS
1244 gettimeofday(&now, (struct timezone *) 0);
1248 ip = (struct ip *) packet;
1249 iphdrlen = IP_HDRLEN(ip) << 2;
1250 icmph = (struct ICMP *) &packet[iphdrlen];
1251 then = (struct timeval *) &packet[iphdrlen + sizeof(struct ICMP)];
1254 /* Was the packet a reply?? */
1256 if (ICMP_TYPE(icmph) != ICMP_ECHOREPLY) {
1257 /* Ignore anything but ICMP Replies */
1258 continue; /* Nope */
1261 /* Was it for us? */
1263 if (ICMP_ID(icmph) != pi->pid) {
1264 /* Ignore packets not set from us */
1265 continue; /* Nope */
1268 /* Copy the name of the bogie */
1271 strdup((char *) &packet[iphdrlen +
1272 + sizeof(struct ICMP)
1273 + sizeof(struct timeval)])) == NULL) {
1274 fprintf(stderr, "%s: Out of memory\n", progname);
1278 # if 0 /* Don't need to do this -- the host names are already as
1279 resolved as they're going to get. (We stored the resolved
1280 name in the outgoing ping packet, so that same string just
1284 /* If the name is an IP addr, try to resolve it. */
1288 if (4 == sscanf(name, " %d.%d.%d.%d %c",
1289 &iip[0], &iip[1], &iip[2], &iip[3], &c))
1291 struct sockaddr_in iaddr;
1293 iaddr.sin_addr.s_addr = pack_addr (iip[0],iip[1],iip[2],iip[3]);
1295 h = gethostbyaddr ((const char *) &iaddr.sin_addr.s_addr,
1296 sizeof(iaddr.sin_addr.s_addr),
1301 if (h && h->h_name && *h->h_name)
1304 name = strdup (h->h_name);
1310 /* Create the new Bogie and add it to the list we are building */
1312 if ((new = newBogie(name, 0, si->current, si->TTL)) == NULL)
1318 float msec = delta(then, &now) / 1000.0;
1322 if (new->desc) free (new->desc);
1323 new->desc = (char *) malloc (30);
1324 if (msec > 99) sprintf (new->desc, " %.0f ms ", msec);
1325 else if (msec > 9) sprintf (new->desc, " %.1f ms ", msec);
1326 else if (msec > 1) sprintf (new->desc, " %.2f ms ", msec);
1327 else sprintf (new->desc, " %.3f ms ", msec);
1330 if (debug_p && times_p) /* print ping-like stuff to stdout */
1332 struct sockaddr_in *iaddr = (struct sockaddr_in *) &from;
1333 unsigned int a, b, c, d;
1335 char *s = strdup (new->desc);
1336 char *s2 = s, *s3 = s;
1337 while (*s2 == ' ') s2++;
1338 s3 = strchr (s2, ' ');
1341 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
1342 sprintf (ipstr, "%d.%d.%d.%d", a, b, c, d);
1345 "%3d bytes from %28s: "
1346 "icmp_seq=%-4d ttl=%d time=%s ms\n",
1350 ICMP_SEQ(icmph), si->TTL, s2);
1354 /* Don't put anyone *too* close to the center of the screen. */
1357 new->distance = msec * 10;
1371 * si - Sonar Information.
1372 * pi - Ping Information.
1375 * A list of hosts that replied to pings or null if there were none.
1379 ping(sonar_info *si, void *vpi)
1383 * This tries to distribute the targets evely around the field of the
1387 ping_info *pi = (ping_info *) vpi;
1388 static ping_target *ptr = NULL;
1390 int tick = si->current * -1 + 1;
1391 if ((ptr == NULL) && (tick == 1))
1394 if (pi->numtargets <= 90) {
1395 int xdrant = 90 / pi->numtargets;
1396 if ((tick % xdrant) == 0) {
1397 if (ptr != (ping_target *) 0) {
1403 } else if (pi->numtargets > 90) {
1404 if (ptr != (ping_target *) 0) {
1410 /* Get the results */
1412 return getping(si, pi);
1415 #endif /* HAVE_PING */
1418 * Calculate the difference between two timevals in microseconds.
1421 * then - The older timeval.
1422 * now - The newer timeval.
1425 * The difference between the two in microseconds.
1429 delta(struct timeval *then, struct timeval *now)
1431 return (((now->tv_sec - then->tv_sec) * 1000000) +
1432 (now->tv_usec - then->tv_usec));
1436 * Initialize the simulation mode.
1443 /* Local Variables */
1448 /* Create the simulation info structure */
1450 if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) {
1451 fprintf(stderr, "%s: Out of memory\n", progname);
1457 si->numA = get_integer_resource("teamACount", "TeamACount");
1458 if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target)))
1461 fprintf(stderr, "%s: Out of Memory\n", progname);
1464 si->teamAID = get_string_resource("teamAName", "TeamAName");
1465 for (i = 0; i < si->numA; i++) {
1466 if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4))
1469 fprintf(stderr, "%s: Out of Memory\n", progname);
1472 sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1);
1473 si->teamA[i].nexttick = random() % 90;
1474 si->teamA[i].nextdist = random() % 100;
1475 si->teamA[i].movedonsweep = -1;
1480 si->numB = get_integer_resource("teamBCount", "TeamBCount");
1481 if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target)))
1484 fprintf(stderr, "%s: Out of Memory\n", progname);
1487 si->teamBID = get_string_resource("teamBName", "TeamBName");
1488 for (i = 0; i < si->numB; i++) {
1489 if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4))
1492 fprintf(stderr, "%s: Out of Memory\n", progname);
1495 sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1);
1496 si->teamB[i].nexttick = random() % 90;
1497 si->teamB[i].nextdist = random() % 100;
1498 si->teamB[i].movedonsweep = -1;
1507 * Creates and returns a drawing mask for the scope:
1508 * mask out anything outside of the disc.
1511 scope_mask (Display *dpy, Window win, sonar_info *si)
1514 Pixmap mask = XCreatePixmap(dpy, win, si->width, si->height, 1);
1515 GC gc = XCreateGC (dpy, mask, 0, &gcv);
1516 XSetFunction (dpy, gc, GXclear);
1517 XFillRectangle (dpy, mask, gc, 0, 0, si->width, si->height);
1518 XSetFunction (dpy, gc, GXset);
1519 XFillArc(dpy, mask, gc, si->minx, si->miny,
1520 si->maxx - si->minx, si->maxy - si->miny,
1527 reshape (sonar_info *si)
1529 XWindowAttributes xgwa;
1531 XGetWindowAttributes(si->dpy, si->win, &xgwa);
1532 si->width = xgwa.width;
1533 si->height = xgwa.height;
1534 si->centrex = si->width / 2;
1535 si->centrey = si->height / 2;
1536 si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
1537 si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
1538 si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
1539 si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
1540 si->radius = si->maxx - si->centrex;
1542 /* Install the clip mask... */
1543 mask = scope_mask (si->dpy, si->win, si);
1544 XSetClipMask(si->dpy, si->text, mask);
1545 XSetClipMask(si->dpy, si->erase, mask);
1546 XFreePixmap (si->dpy, mask); /* it's been copied into the GCs */
1550 * Initialize the Sonar.
1553 * dpy - The X display.
1554 * win - The X window;
1557 * A sonar_info strcuture or null if memory allocation problems occur.
1561 init_sonar(Display *dpy, Window win)
1564 /* Local Variables */
1567 XWindowAttributes xwa;
1571 double s1, s2, v1, v2;
1573 /* Create the Sonar information structure */
1575 if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) {
1576 fprintf(stderr, "%s: Out of memory\n", progname);
1580 /* Initialize the structure for the current environment */
1586 XGetWindowAttributes(dpy, win, &xwa);
1587 si->cmap = xwa.colormap;
1594 if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font")))
1596 ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) {
1597 fprintf(stderr, "%s: can't load an appropriate font\n", progname);
1601 /* Get the delay between animation frames */
1603 si->delay = get_integer_resource ("delay", "Integer");
1605 if (si->delay < 0) si->delay = 0;
1606 si->TTL = get_integer_resource("ttl", "TTL");
1608 /* Create the Graphics Contexts that will be used to draw things */
1611 get_pixel_resource ("sweepColor", "SweepColor", dpy, si->cmap);
1612 si->hi = XCreateGC(dpy, win, GCForeground, &gcv);
1613 gcv.font = si->font->fid;
1614 si->text = XCreateGC(dpy, win, GCForeground|GCFont, &gcv);
1615 gcv.foreground = get_pixel_resource("scopeColor", "ScopeColor",
1617 si->erase = XCreateGC (dpy, win, GCForeground, &gcv);
1618 gcv.foreground = get_pixel_resource("gridColor", "GridColor",
1620 si->grid = XCreateGC (dpy, win, GCForeground, &gcv);
1624 /* Compute pixel values for fading text on the display */
1626 XParseColor(dpy, si->cmap,
1627 get_string_resource("textColor", "TextColor"), &start);
1628 XParseColor(dpy, si->cmap,
1629 get_string_resource("scopeColor", "ScopeColor"), &end);
1631 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1632 rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
1634 si->text_steps = get_integer_resource("textSteps", "TextSteps");
1635 if (si->text_steps < 0 || si->text_steps > 255)
1636 si->text_steps = 10;
1638 si->text_colors = (XColor *) calloc(si->text_steps, sizeof(XColor));
1639 make_color_ramp (dpy, si->cmap,
1642 si->text_colors, &si->text_steps,
1643 False, True, False);
1645 /* Compute the pixel values for the fading sweep */
1647 XParseColor(dpy, si->cmap,
1648 get_string_resource("sweepColor", "SweepColor"), &start);
1650 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1652 si->sweep_degrees = get_integer_resource("sweepDegrees", "Degrees");
1653 if (si->sweep_degrees <= 0) si->sweep_degrees = 20;
1654 if (si->sweep_degrees > 350) si->sweep_degrees = 350;
1656 si->sweep_segs = get_integer_resource("sweepSegments", "SweepSegments");
1657 if (si->sweep_segs < 1 || si->sweep_segs > 255)
1658 si->sweep_segs = 255;
1660 si->sweep_colors = (XColor *) calloc(si->sweep_segs, sizeof(XColor));
1661 make_color_ramp (dpy, si->cmap,
1664 si->sweep_colors, &si->sweep_segs,
1665 False, True, False);
1667 if (si->sweep_segs <= 0)
1676 * Update the location of a simulated bogie.
1680 updateLocation(sim_target *t)
1685 xtick = (int) (random() % 3) - 1;
1686 xdist = (int) (random() % 11) - 5;
1687 if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0))
1688 t->nexttick += xtick;
1690 t->nexttick -= xtick;
1691 if (((t->nextdist + xdist) < 100) && ((t->nextdist+xdist) >= 0))
1692 t->nextdist += xdist;
1694 t->nextdist -= xdist;
1698 * The simulator. This uses information in the sim_info to simulate a bunch
1699 * of bogies flying around on the screen.
1703 * TODO: It would be cool to have the two teams chase each other around and
1708 simulator(sonar_info *si, void *vinfo)
1711 /* Local Variables */
1717 sim_info *info = (sim_info *) vinfo;
1721 for (i = 0; i < info->numA; i++) {
1722 t = &info->teamA[i];
1723 if ((t->movedonsweep != si->sweepnum) &&
1724 (t->nexttick == (si->current * -1))) {
1725 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1730 t->movedonsweep = si->sweepnum;
1736 for (i = 0; i < info->numB; i++) {
1737 t = &info->teamB[i];
1738 if ((t->movedonsweep != si->sweepnum) &&
1739 (t->nexttick == (si->current * -1))) {
1740 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1745 t->movedonsweep = si->sweepnum;
1755 * Compute the X coordinate of the label.
1758 * si - The sonar info block.
1759 * label - The label that will be drawn.
1760 * x - The x coordinate of the bogie.
1763 * The x coordinate of the start of the label.
1767 computeStringX(sonar_info *si, const char *label, int x)
1770 int width = XTextWidth(si->font, label, strlen(label));
1771 return x - (width / 2);
1775 * Compute the Y coordinate of the label.
1778 * si - The sonar information.
1779 * y - The y coordinate of the bogie.
1782 * The y coordinate of the start of the label.
1786 computeStringY(sonar_info *si, int y)
1789 int fheight = si->font->ascent /* + si->font->descent */;
1794 * Draw a Bogie on the radar screen.
1797 * si - Sonar Information.
1798 * draw - A flag to indicate if the bogie should be drawn or erased.
1799 * name - The name of the bogie.
1800 * degrees - The number of degrees that it should apprear at.
1801 * distance - The distance the object is from the centre.
1802 * ttl - The time this bogie has to live.
1803 * age - The time this bogie has been around.
1807 DrawBogie(sonar_info *si, int draw, const char *name, const char *desc,
1808 int degrees, int distance, int ttl, int age)
1811 /* Local Variables */
1815 int ox = si->centrex;
1816 int oy = si->centrey;
1819 /* Compute the coordinates of the object */
1822 distance = (log((double) distance) / 10.0) * si->radius;
1823 x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578));
1824 y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578));
1826 /* Set up the graphics context */
1830 /* Here we attempt to compute the distance into the total life of
1831 * object that we currently are. This distance is used against
1832 * the total lifetime to compute a fraction which is the index of
1833 * the color to draw the bogie.
1836 if (si->current <= degrees)
1837 delta = (si->current - degrees) * -1;
1839 delta = 90 + (degrees - si->current);
1840 delta += (age * 90);
1841 index = (si->text_steps - 1) * ((float) delta / (90.0 * (float) ttl));
1843 XSetForeground(si->dpy, gc, si->text_colors[index].pixel);
1848 /* Draw (or erase) the Bogie */
1850 XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64);
1852 x += 3; /* move away from the dot */
1854 y = computeStringY(si, y);
1855 XDrawString(si->dpy, si->win, gc,
1856 computeStringX(si, name, x), y,
1857 name, strlen(name));
1861 y = computeStringY(si, y);
1862 XDrawString(si->dpy, si->win, gc,
1863 computeStringX(si, desc, x), y,
1864 desc, strlen(desc));
1870 * Draw the sonar grid.
1873 * si - Sonar information block.
1877 drawGrid(sonar_info *si)
1880 /* Local Variables */
1883 int width = si->maxx - si->minx;
1884 int height = si->maxy - si->miny;
1886 /* Draw the circles */
1888 XDrawArc(si->dpy, si->win, si->grid, si->minx - 10, si->miny - 10,
1889 width + 20, height + 20, 0, (360 * 64));
1891 XDrawArc(si->dpy, si->win, si->grid, si->minx, si->miny,
1892 width, height, 0, (360 * 64));
1894 XDrawArc(si->dpy, si->win, si->grid,
1895 (int) (si->minx + (.166 * width)),
1896 (int) (si->miny + (.166 * height)),
1897 (unsigned int) (.666 * width), (unsigned int)(.666 * height),
1900 XDrawArc(si->dpy, si->win, si->grid,
1901 (int) (si->minx + (.333 * width)),
1902 (int) (si->miny + (.333 * height)),
1903 (unsigned int) (.333 * width), (unsigned int) (.333 * height),
1906 /* Draw the radial lines */
1908 for (i = 0; i < 360; i += 10)
1910 XDrawLine(si->dpy, si->win, si->grid, si->centrex, si->centrey,
1911 (int) (si->centrex +
1912 (si->radius + 10) * (cos((double) i / 57.29578))),
1913 (int) (si->centrey -
1914 (si->radius + 10)*(sin((double) i / 57.29578))));
1916 XDrawLine(si->dpy, si->win, si->grid,
1917 (int) (si->centrex + si->radius *
1918 (cos((double) i / 57.29578))),
1919 (int) (si->centrey - si->radius *
1920 (sin((double) i / 57.29578))),
1921 (int) (si->centrex +
1922 (si->radius + 10) * (cos((double) i / 57.29578))),
1923 (int) (si->centrey -
1924 (si->radius + 10) * (sin((double) i / 57.29578))));
1928 * Update the Sonar scope.
1931 * si - The Sonar information.
1932 * bl - A list of bogies to add to the scope.
1936 Sonar(sonar_info *si, Bogie *bl)
1939 /* Local Variables */
1944 /* Check for expired tagets and remove them from the visible list */
1947 for (bp = si->visible; bp != NULL; bp = (bp ? bp->next : 0)) {
1950 * Remove it from the visible list if it's expired or we have
1951 * a new target with the same name.
1956 if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) ||
1957 (findNode(bl, bp->name) != NULL)) {
1958 DrawBogie(si, 0, bp->name, bp->desc, bp->tick,
1959 bp->distance, bp->ttl, bp->age);
1961 si->visible = bp->next;
1963 prev->next = bp->next;
1970 /* Draw the sweep */
1973 int seg_deg = (si->sweep_degrees * 64) / si->sweep_segs;
1974 int start_deg = si->current * 4 * 64;
1975 if (seg_deg <= 0) seg_deg = 1;
1976 for (i = 0; i < si->sweep_segs; i++) {
1977 XSetForeground(si->dpy, si->hi, si->sweep_colors[i].pixel);
1978 XFillArc(si->dpy, si->win, si->hi, si->minx, si->miny,
1979 si->maxx - si->minx, si->maxy - si->miny,
1980 start_deg + (i * seg_deg),
1984 /* Remove the trailing wedge the sonar */
1985 XFillArc(si->dpy, si->win, si->erase, si->minx, si->miny,
1986 si->maxx - si->minx, si->maxy - si->miny,
1987 start_deg + (i * seg_deg),
1991 /* Move the new targets to the visible list */
1993 for (bp = bl; bp != (Bogie *) 0; bp = bl) {
1995 bp->next = si->visible;
1999 /* Draw the visible targets */
2001 for (bp = si->visible; bp != NULL; bp = bp->next) {
2002 if (bp->age < bp->ttl) /* grins */
2003 DrawBogie(si, 1, bp->name, bp->desc,
2004 bp->tick, bp->distance, bp->ttl,bp->age);
2007 /* Redraw the grid */
2013 static ping_target *
2014 parse_mode (Bool ping_works_p)
2016 char *source = get_string_resource ("ping", "Ping");
2020 ping_target *hostlist = 0;
2022 if (!source) source = strdup("");
2024 if (!*source || !strcmp (source, "default"))
2027 if (ping_works_p) /* if root or setuid, ping will work. */
2028 source = strdup("subnet/29,/etc/hosts");
2031 source = strdup("simulation");
2035 end = source + strlen(source);
2042 unsigned int n0=0, n1=0, n2=0, n3=0, m=0;
2044 # endif /* HAVE_PING */
2048 *next != ',' && *next != ' ' && *next != '\t' && *next != '\n';
2055 fprintf (stderr, "%s: parsing %s\n", progname, token);
2057 if (!strcmp (token, "simulation"))
2063 "%s: this program must be setuid to root for `ping mode' to work.\n"
2064 " Running in `simulation mode' instead.\n",
2070 if ((4 == sscanf (token, "%u.%u.%u/%u %c", &n0,&n1,&n2, &m,&d)) ||
2071 (5 == sscanf (token, "%u.%u.%u.%u/%u %c", &n0,&n1,&n2,&n3,&m,&d)))
2073 /* subnet: A.B.C.D/M
2076 unsigned long ip = pack_addr (n0, n1, n2, n3);
2077 new = subnetHostsList(ip, m);
2079 else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d))
2083 new = newHost (token);
2085 else if (!strcmp (token, "subnet"))
2087 new = subnetHostsList(0, 24);
2089 else if (1 == sscanf (token, "subnet/%u %c", &m, &dummy))
2091 new = subnetHostsList(0, m);
2093 else if (*token == '.' || *token == '/' || !stat (token, &st))
2097 new = readPingHostsFile (token);
2101 /* not an existant file - must be a host name
2103 new = newHost (token);
2108 ping_target *nn = new;
2109 while (nn && nn->next)
2111 nn->next = hostlist;
2116 #endif /* HAVE_PING */
2119 while (token < end &&
2120 (*token == ',' || *token == ' ' ||
2121 *token == '\t' || *token == '\n'))
2130 handle_events (sonar_info *si)
2132 while (XPending (si->dpy))
2135 XNextEvent (si->dpy, &event);
2137 if (event.xany.type == ConfigureNotify)
2139 XClearWindow (si->dpy, si->win);
2143 screenhack_handle_event (si->dpy, &event);
2150 * Main screen saver hack.
2153 * dpy - The X display.
2154 * win - The X window.
2158 screenhack(Display *dpy, Window win)
2161 /* Local Variables */
2164 struct timeval start, finish;
2168 debug_p = get_boolean_resource ("debug", "Debug");
2169 resolve_p = get_boolean_resource ("resolve", "Resolve");
2170 times_p = get_boolean_resource ("showTimes", "ShowTimes");
2174 sensor_info = (void *) init_ping();
2175 # else /* !HAVE_PING */
2177 parse_mode (0); /* just to check argument syntax */
2178 # endif /* !HAVE_PING */
2183 if ((sensor_info = (void *) init_sim()) == NULL)
2187 if ((si = init_sonar(dpy, win)) == (sonar_info *) 0)
2195 /* Call the sensor and display the results */
2197 # ifdef GETTIMEOFDAY_TWO_ARGS
2198 gettimeofday(&start, (struct timezone *) 0);
2200 gettimeofday(&start);
2202 bl = sensor(si, sensor_info);
2205 /* Set up and sleep for the next one */
2207 si->current = (si->current - 1) % 90;
2208 if (si->current == 0)
2211 # ifdef GETTIMEOFDAY_TWO_ARGS
2212 gettimeofday(&finish, (struct timezone *) 0);
2214 gettimeofday(&finish);
2216 sleeptime = si->delay - delta(&start, &finish);