X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fsonar.c;h=00f7b3f6fc5e7d1a4da7ca874fe4b6b65212b83a;hb=96a411663168b0ba5432b407a83be55f3df0c802;hp=4b3aae08652d3cb9a5d0cc590d9e6efd1ecfeb39;hpb=f54438ea00f152166e68073e98000fd3a00f65cd;p=xscreensaver diff --git a/hacks/sonar.c b/hacks/sonar.c index 4b3aae08..00f7b3f6 100644 --- a/hacks/sonar.c +++ b/hacks/sonar.c @@ -28,7 +28,8 @@ * - plot the process table, by process size, cpu usage, or total time; * - plot the logged on users by idle time or cpu usage. * - * Copyright (C) 1998 by Stephen Martin (smartin@canada.com). + * Copyright (C) 1998, 2001 + * by Stephen Martin (smartin@vanderfleet-martin.net). * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that @@ -37,7 +38,7 @@ * software for any purpose. It is provided "as is" without express or * implied warranty. * - * $Revision: 1.7 $ + * $Revision: 1.29 $ * * Version 1.0 April 27, 1998. * - Initial version @@ -75,11 +76,10 @@ * - Now need to define HAVE_PING to compile in the ping stuff. */ -/* Define one of these, as appropriate. - We should make configure detect this, one of these days. +/* These are computed by configure now: + #define HAVE_ICMP + #define HAVE_ICMPHDR */ -/* #define HAVE_ICMP */ -/* #define HAVE_ICMPHDR */ /* Include Files */ @@ -87,6 +87,11 @@ #include #include #include +#include + +#include "screenhack.h" +#include "colors.h" +#include "hsv.h" #if defined(HAVE_ICMP) || defined(HAVE_ICMPHDR) # include @@ -107,18 +112,16 @@ # include #endif /* HAVE_ICMP || HAVE_ICMPHDR */ -#include "screenhack.h" -#include "colors.h" -#include "hsv.h" - -#include - /* Defines */ #undef MY_MIN #define MY_MIN(a,b) ((a)<(b)?(a - 50):(b - 10)) +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + /* Frigging icmp */ #if defined(HAVE_ICMP) @@ -141,6 +144,18 @@ # undef HAVE_PING #endif + +#ifdef HAVE_PING +# if defined(__DECC) || defined(_IP_VHL) + /* This is how you do it on DEC C, and possibly some BSD systems. */ +# define IP_HDRLEN(ip) ((ip)->ip_vhl & 0x0F) +# else + /* This is how you do it on everything else. */ +# define IP_HDRLEN(ip) ((ip)->ip_hl) +# endif +#endif /* HAVE_PING */ + + /* Forward References */ #ifdef HAVE_PING @@ -148,12 +163,13 @@ static u_short checksum(u_short *, int); #endif static long delta(struct timeval *, struct timeval *); + /* Data Structures */ /* * The Bogie. * - * This represents an object that is visable on the scope. + * This represents an object that is visible on the scope. */ typedef struct Bogie { @@ -189,13 +205,18 @@ typedef struct { int width, height; /* Window dimensions */ int minx, miny, maxx, maxy, /* Bounds of the scope */ centrex, centrey, radius; /* Parts of the scope circle */ - Bogie *visable; /* List of visable objects */ + Bogie *visible; /* List of visible objects */ int current; /* Current position of sweep */ - + int sweepnum; /* The current id of the sweep */ int delay; /* how long between each frame of the anim */ + int TTL; /* The number of ticks that bogies are visible + on the screen before they fade away. */ } sonar_info; +static Bool debug_p = False; + + /* * Variables to support the differnt Sonar modes. */ @@ -207,13 +228,16 @@ void *sensor_info; /* Information about the sensor */ * A list of targets to ping. */ -#ifdef HAVE_PING typedef struct ping_target { char *name; /* The name of the target */ +#ifdef HAVE_PING struct sockaddr address; /* The address of the target */ +#endif /* HAVE_PING */ struct ping_target *next; /* The next one in the list */ } ping_target; + +#ifdef HAVE_PING /* * Ping Information. * @@ -233,7 +257,6 @@ typedef struct { static int timer_expired; - #endif /* HAVE_PING */ /* @@ -244,7 +267,7 @@ typedef struct sim_target { char *name; /* The name of the target */ int nexttick; /* The next tick that this will be seen */ int nextdist; /* The distance on that tick */ - int movedlasttick; /* Flag to indicate we just moved this one */ + int movedonsweep; /* The number of the sweep this last moved */ } sim_target; /* @@ -283,16 +306,15 @@ char *defaults [] = { "*textSteps: 80", /* npixels */ "*sweepSegments: 80", /* npixels */ -#ifdef HAVE_PING "*pingTimeout: 3000", - "*pingSource: file", - "*pingFile: /etc/hosts", - "*pingList: localhost", -#endif /* HAVE_PING */ + "*teamAName: F18", "*teamBName: MIG", "*teamACount: 4", "*teamBCount: 4", + + "*ping: default", + ".debug: false", 0 }; @@ -305,28 +327,20 @@ XrmOptionDescRec options [] = { {"-grid-color", ".gridColor", XrmoptionSepArg, 0 }, {"-text-color", ".textColor", XrmoptionSepArg, 0 }, {"-ttl", ".ttl", XrmoptionSepArg, 0 }, - {"-mode", ".mode", XrmoptionSepArg, 0 }, {"-font", ".font", XrmoptionSepArg, 0 }, #ifdef HAVE_PING {"-ping-timeout", ".pingTimeout", XrmoptionSepArg, 0 }, - {"-ping-source", ".pingSource", XrmoptionSepArg, 0 }, - {"-ping-file", ".pingFile", XrmoptionSepArg, 0 }, - {"-ping-list", ".pingList", XrmoptionSepArg, 0 }, #endif /* HAVE_PING */ {"-team-a-name", ".teamAName", XrmoptionSepArg, 0 }, {"-team-b-name", ".teamBName", XrmoptionSepArg, 0 }, {"-team-a-count", ".teamACount", XrmoptionSepArg, 0 }, {"-team-b-count", ".teamBCount", XrmoptionSepArg, 0 }, + + {"-ping", ".ping", XrmoptionSepArg, 0 }, + {"-debug", ".debug", XrmoptionNoArg, "True" }, { 0, 0, 0, 0 } }; -/* - * The number of ticks that bogies are visable on the screen before they - * fade away. - */ - -static int TTL; - /* * Create a new Bogie and set some initial values. * @@ -348,10 +362,11 @@ newBogie(char *name, int distance, int tick, int ttl) Bogie *new; + distance *= 1000; /* Allocate a bogie and initialize it */ if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) { - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); return NULL; } new->name = name; @@ -370,6 +385,7 @@ newBogie(char *name, int distance, int tick, int ttl) * b - The bogie to free. */ + static void freeBogie(Bogie *b) { @@ -433,34 +449,91 @@ findNode(Bogie *bl, char *name) static int lookupHost(ping_target *target) { + struct hostent *hent; + struct sockaddr_in *iaddr; - /* Local Variables */ + int iip[4]; + char c; - struct sockaddr_in *iaddr; + iaddr = (struct sockaddr_in *) &(target->address); + iaddr->sin_family = AF_INET; - /* Set up the target address we first assume that the name is the - IP address as a string */ + if (4 == sscanf(target->name, "%d.%d.%d.%d%c", + &iip[0], &iip[1], &iip[2], &iip[3], &c)) + { + /* It's an IP address. + */ + unsigned char ip[4]; - iaddr = (struct sockaddr_in *) &(target->address); - iaddr->sin_family = AF_INET; - if ((iaddr->sin_addr.s_addr = inet_addr(target->name)) == -1) { + ip[0] = iip[0]; + ip[1] = iip[1]; + ip[2] = iip[2]; + ip[3] = iip[3]; - /* Conversion of IP address failed, try to look the host up by name */ + if (ip[3] == 0) + { + if (debug_p > 1) + fprintf (stderr, "%s: ignoring bogus IP %s\n", + progname, target->name); + return 0; + } - struct hostent *hent = gethostbyname(target->name); - if (hent == NULL) { - fprintf(stderr, "Could not resolve host %s\n", target->name); - return 0; - } - memcpy(&iaddr->sin_addr, hent->h_addr_list[0], - sizeof(iaddr->sin_addr)); + iaddr->sin_addr.s_addr = ((ip[3] << 24) | + (ip[2] << 16) | + (ip[1] << 8) | + (ip[0])); + hent = gethostbyaddr ((const char *) ip, 4, AF_INET); + + if (debug_p > 1) + fprintf (stderr, "%s: %s => %s\n", + progname, target->name, + ((hent && hent->h_name && *hent->h_name) + ? hent->h_name : "")); + + if (hent && hent->h_name && *hent->h_name) + target->name = strdup (hent->h_name); } + else + { + /* It's a host name. + */ + hent = gethostbyname (target->name); + if (!hent) + { + fprintf (stderr, "%s: could not resolve host: %s\n", + progname, target->name); + return 0; + } + + memcpy (&iaddr->sin_addr, hent->h_addr_list[0], + sizeof(iaddr->sin_addr)); + + if (debug_p > 1) + fprintf (stderr, "%s: %s => %d.%d.%d.%d\n", + progname, target->name, + iaddr->sin_addr.s_addr & 255, + iaddr->sin_addr.s_addr >> 8 & 255, + iaddr->sin_addr.s_addr >> 16 & 255, + iaddr->sin_addr.s_addr >> 24 & 255); + } + return 1; +} - /* Done */ - return 1; +static void +print_host (FILE *out, unsigned long ip, const char *name) +{ + char ips[50]; + sprintf (ips, "%lu.%lu.%lu.%lu", + (ip) & 255, + (ip >> 8) & 255, + (ip >> 16) & 255, + (ip >> 24) & 255); + if (!name || !*name) name = ""; + fprintf (out, "%-16s %s\n", ips, name); } + /* * Create a target for a host. * @@ -482,11 +555,11 @@ newHost(char *name) /* Create the target */ if ((target = calloc(1, sizeof(ping_target))) == NULL) { - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); goto target_init_error; } if ((target->name = strdup(name)) == NULL) { - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); goto target_init_error; } @@ -495,8 +568,31 @@ newHost(char *name) if (! lookupHost(target)) goto target_init_error; + /* Don't ever use loopback (127.0.0) hosts */ + { + struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address); + unsigned long ip = iaddr->sin_addr.s_addr; + if ((ip & 255) == 127 && + ((ip >> 8) & 255) == 0 && + ((ip >> 16) & 255) == 0) + { + if (debug_p) + fprintf (stderr, "%s: ignoring loopback host %s\n", + progname, target->name); + goto target_init_error; + } + } + /* Done */ + if (debug_p) + { + struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address); + unsigned long ip = iaddr->sin_addr.s_addr; + fprintf (stderr, "%s: added ", progname); + print_host (stderr, ip, target->name); + } + return target; /* Handle errors here */ @@ -521,7 +617,6 @@ target_init_error: static ping_target * readPingHostsFile(char *fname) { - /* Local Variables */ FILE *fp; @@ -534,7 +629,7 @@ readPingHostsFile(char *fname) /* Make sure we in fact have a file to process */ if ((fname == NULL) || (fname[0] == '\0')) { - fprintf(stderr, "Invalid ping host file name\n"); + fprintf(stderr, "%s: invalid ping host file name\n", progname); return NULL; } @@ -542,11 +637,14 @@ readPingHostsFile(char *fname) if ((fp = fopen(fname, "r")) == NULL) { char msg[1024]; - sprintf(msg, "Unable to open host file %s", fname); + sprintf(msg, "%s: unable to open host file %s", progname, fname); perror(msg); return NULL; } + if (debug_p) + fprintf (stderr, "%s: reading file %s\n", progname, fname); + /* Read the file line by line */ while ((p = fgets(buf, LINE_MAX, fp)) != NULL) { @@ -566,17 +664,48 @@ readPingHostsFile(char *fname) /* Get the name and address */ name = addr = NULL; - if ((addr = strtok(buf, " \t\n")) != NULL) - name = strtok(NULL, " \t\n"); + if ((addr = strtok(buf, " ,;\t\n")) != NULL) + name = strtok(NULL, " ,;\t\n"); else continue; + /* Check to see if the addr looks like an addr. If not, assume + the addr is a name and there is no addr. This way, we can + handle files whose lines have "xx.xx.xx.xx hostname" as their + first two tokens, and also files that have a hostname as their + first token (like .ssh/known_hosts and .rhosts.) + */ + { + int i; char c; + if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c)) + { + name = addr; + addr = NULL; + } + } + + /* If the name is all digits, it's not a name. */ + if (name) + { + const char *s; + for (s = name; *s; s++) + if (*s < '0' || *s > '9') + break; + if (! *s) + { + if (debug_p > 1) + fprintf (stderr, "%s: skipping bogus name \"%s\" (%s)\n", + progname, name, addr); + name = NULL; + } + } + /* Create a new target using first the name then the address */ new = NULL; if (name != NULL) new = newHost(name); - if (new == NULL) + if (new == NULL && addr != NULL) new = newHost(addr); /* Add it to the list if we got one */ @@ -593,47 +722,45 @@ readPingHostsFile(char *fname) return list; } -/* - * Generate a list of ping targets from the entries in a string. - * - * Args: - * list - A list of comma separated host names. - * - * Returns: - * A list of targets to ping or null if an error occured. - */ static ping_target * -readPingHostsList(char *list) +delete_duplicate_hosts (ping_target *list) { + ping_target *head = list; + ping_target *rest; - /* Local Variables */ - - char *host; - ping_target *hostlist = NULL; - ping_target *new; + for (rest = head; rest; rest = rest->next) + { + struct sockaddr_in *i1 = (struct sockaddr_in *) &(rest->address); + unsigned long ip1 = i1->sin_addr.s_addr; - /* Check that there is a list */ + static ping_target *rest2; + for (rest2 = rest; rest2; rest2 = rest2->next) + { + if (rest2 && rest2->next) + { + struct sockaddr_in *i2 = (struct sockaddr_in *) + &(rest2->next->address); + unsigned long ip2 = i2->sin_addr.s_addr; - if ((list == NULL) || (list[0] == '\0')) - return NULL; + if (ip1 == ip2) + { + if (debug_p) + { + fprintf (stderr, "%s: deleted duplicate: ", progname); + print_host (stderr, ip2, rest2->next->name); + } + rest2->next = rest2->next->next; + } + } + } + } - /* Loop through the hosts and add them to the list to return */ + return head; +} - host = strtok(list, ","); - while (host != NULL) { - new = newHost(host); - if (new != NULL) { - new->next = hostlist; - hostlist = new; - } - host = strtok(NULL, ","); - } - /* Done */ - return hostlist; -} /* * Generate a list ping targets consisting of all of the entries on @@ -644,8 +771,9 @@ readPingHostsList(char *list) */ static ping_target * -subnetHostsList(void) +subnetHostsList(int base, int subnet_width) { + unsigned long mask; /* Local Variables */ @@ -657,40 +785,102 @@ subnetHostsList(void) ping_target *new; ping_target *list = NULL; + if (subnet_width < 24) + { + fprintf (stderr, + "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n" + " or more (255 hosts max.)\n", + progname, (unsigned long) (1L << (32 - subnet_width)) - 1); + exit (1); + } + else if (subnet_width > 30) + { + fprintf (stderr, "%s: a subnet of %d bits doesn't make sense:" + " try \"subnet/24\" or \"subnet/29\".\n", + progname, subnet_width); + exit (1); + } + + + if (debug_p) + fprintf (stderr, "%s: adding %d-bit subnet\n", progname, subnet_width); + /* Get our hostname */ if (gethostname(hostname, BUFSIZ)) { - fprintf(stderr, "Unable to get local hostname\n"); + fprintf(stderr, "%s: unable to get local hostname\n", progname); return NULL; } /* Get our IP address and convert it to a string */ if ((hent = gethostbyname(hostname)) == NULL) { - fprintf(stderr, "Unable to lookup our IP address\n"); + fprintf(stderr, "%s: unable to lookup our IP address\n", progname); return NULL; } strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0]))); - /* Get a pointer to the last "." in the string */ + /* Construct targets for all addresses in this subnet */ + + mask = 0; + for (i = 0; i < subnet_width; i++) + mask |= (1L << (31-i)); - if ((p = strrchr(address, '.')) == NULL) { - fprintf(stderr, "Can't parse IP address %s\n", address); - return NULL; - } - p++; + /* If no base IP specified, assume localhost. */ + if (base == 0) + base = ((((unsigned char) hent->h_addr_list[0][0]) << 24) | + (((unsigned char) hent->h_addr_list[0][1]) << 16) | + (((unsigned char) hent->h_addr_list[0][2]) << 8) | + (((unsigned char) hent->h_addr_list[0][3]))); - /* Construct targets for all addresses in this subnet */ + if (base == ((127 << 24) | 1)) + { + fprintf (stderr, + "%s: unable to determine local subnet address: \"%s\"\n" + " resolves to loopback address %d.%d.%d.%d.\n", + progname, hostname, + (base >> 24) & 255, (base >> 16) & 255, + (base >> 8) & 255, (base ) & 255); + return NULL; + } - for (i = 254; i > 0; i--) { + for (i = 255; i >= 0; i--) { + int ip = (base & 0xFFFFFF00) | i; + + if ((ip & mask) != (base & mask)) /* not in the mask range at all */ + continue; + if ((ip & ~mask) == 0) /* broadcast address */ + continue; + if ((ip & ~mask) == ~mask) /* broadcast address */ + continue; + + sprintf (address, "%d.%d.%d.%d", + (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, (ip)&255); + + if (debug_p > 1) + fprintf(stderr, "%s: subnet: %s (%d.%d.%d.%d & %d.%d.%d.%d / %d)\n", + progname, + address, + (int) (base>>24)&255, + (int) (base>>16)&255, + (int) (base>> 8)&255, + (int) (base&mask&255), + (int) (mask>>24)&255, + (int) (mask>>16)&255, + (int) (mask>> 8)&255, + (int) (mask&255), + (int) subnet_width); + + p = address + strlen(address) + 1; sprintf(p, "%d", i); + new = newHost(address); if (new != NULL) { new->next = list; list = new; } } - + /* Done */ return list; @@ -703,74 +893,64 @@ subnetHostsList(void) * A newly allocated ping_info structure or null if an error occured. */ +static ping_target *parse_mode (Bool ping_works_p); + static ping_info * init_ping(void) { + Bool socket_initted_p = False; + /* Local Variables */ ping_info *pi = NULL; /* The new ping_info struct */ - char *src; /* The source of the ping hosts */ ping_target *pt; /* Used to count the targets */ /* Create the ping info structure */ if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) { - fprintf(stderr, "Out of memory\n"); + fprintf(stderr, "%s: Out of memory\n", progname); goto ping_init_error; } - /* Create the ICMP socket and turn off SUID */ + /* Create the ICMP socket */ - if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { - perror("Can't create ICMP socket"); - fprintf(stderr, - "%s: this program must be setuid to root for `ping mode' to work.\n", - progname); - goto ping_init_error; + if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0) { + socket_initted_p = True; } + + /* Disavow privs */ + setuid(getuid()); + + pi->pid = getpid() & 0xFFFF; pi->seq = 0; pi->timeout = get_integer_resource("pingTimeout", "PingTimeout"); /* Generate a list of targets */ - src = get_string_resource("pingSource", "PingSource"); - if (strcmp(src, "file") == 0) { - - /* - * The list of ping targets is to come from a file in - * /etc/hosts format - */ - - pi->targets = readPingHostsFile(get_string_resource("pingFile", - "PingFile")); - - } else if (strcmp(src, "list") == 0) { + pi->targets = parse_mode (socket_initted_p); + pi->targets = delete_duplicate_hosts (pi->targets); - /* The list of hosts is to come from the pinghostlist resource */ - pi->targets = readPingHostsList(get_string_resource("pingList", - "PingList")); - - } else if (strcmp(src, "subnet") == 0) { - - pi->targets = subnetHostsList(); - - } else { - - /* Unknown source */ - - fprintf(stderr, "Illegal pingSource: %s\n", src); - goto ping_init_error; - } + if (debug_p) + { + ping_target *t; + fprintf (stderr, "%s: Target list:\n", progname); + for (t = pi->targets; t; t = t->next) + { + struct sockaddr_in *iaddr = (struct sockaddr_in *) &(t->address); + unsigned long ip = iaddr->sin_addr.s_addr; + fprintf (stderr, "%s: ", progname); + print_host (stderr, ip, t->name); + } + } /* Make sure there is something to ping */ if (pi->targets == NULL) { - fprintf(stderr, "Nothing to ping"); - goto ping_init_error; + goto ping_init_error; } /* Count the targets */ @@ -794,6 +974,7 @@ ping_init_error: return NULL; } + /* * Ping a host. * @@ -831,8 +1012,13 @@ sendping(ping_info *pi, ping_target *pt) ICMP_CHECKSUM(icmph) = 0; ICMP_ID(icmph) = pi->pid; ICMP_SEQ(icmph) = pi->seq++; +# ifdef GETTIMEOFDAY_TWO_ARGS gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)], (struct timezone *) 0); +# else + gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)]); +# endif + strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)], pt->name); ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz); @@ -843,7 +1029,7 @@ sendping(ping_info *pi, ping_target *pt) &pt->address, sizeof(pt->address))) != pcktsiz) { #if 0 char errbuf[BUFSIZ]; - sprintf(errbuf, "Error sending ping to %s", pt->name); + sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name); perror(errbuf); #endif } @@ -930,13 +1116,13 @@ checksum(u_short *packet, int size) */ static Bogie * -getping(sonar_info *si, ping_info *pi, int ttl) +getping(sonar_info *si, ping_info *pi) { /* Local Variables */ struct sockaddr from; - int fromlen; + unsigned int fromlen; /* Posix says socklen_t, but that's not portable */ int result; u_char packet[1024]; struct timeval now; @@ -949,6 +1135,8 @@ getping(sonar_info *si, ping_info *pi, int ttl) char *name; struct sigaction sa; struct itimerval it; + fd_set rfds; + struct timeval tv; /* Set up a signal to interupt our wait for a packet */ @@ -956,7 +1144,9 @@ getping(sonar_info *si, ping_info *pi, int ttl) sa.sa_flags = 0; sa.sa_handler = sigcatcher; if (sigaction(SIGALRM, &sa, 0) == -1) { - perror("Unable to trap sigalarm"); + char msg[1024]; + sprintf(msg, "%s: unable to trap SIGALRM", progname); + perror(msg); exit(1); } @@ -972,15 +1162,31 @@ getping(sonar_info *si, ping_info *pi, int ttl) /* Wait for a result packet */ fromlen = sizeof(from); - while (! timer_expired && - (result = recvfrom(pi->icmpsock, packet, sizeof(packet), - 0, &from, &fromlen)) > 0) { + while (! timer_expired) { + tv.tv_usec=pi->timeout; + tv.tv_sec=0; +#if 0 + /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */ + FD_ZERO(&rfds); +#else + memset (&rfds, 0, sizeof(rfds)); +#endif + FD_SET(pi->icmpsock,&rfds); + /* only wait a little while, in case we raced with the timer expiration. + From Valentijn Sessink */ + if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) { + result = recvfrom(pi->icmpsock, packet, sizeof(packet), + 0, &from, &fromlen); /* Check the packet */ +# ifdef GETTIMEOFDAY_TWO_ARGS gettimeofday(&now, (struct timezone *) 0); +# else + gettimeofday(&now); +# endif ip = (struct ip *) packet; - iphdrlen = ip->ip_hl << 2; + iphdrlen = IP_HDRLEN(ip) << 2; icmph = (struct ICMP *) &packet[iphdrlen]; /* Was the packet a reply?? */ @@ -1003,7 +1209,7 @@ getping(sonar_info *si, ping_info *pi, int ttl) strdup((char *) &packet[iphdrlen + + sizeof(struct ICMP) + sizeof(struct timeval)])) == NULL) { - fprintf(stderr, "Out of memory\n"); + fprintf(stderr, "%s: Out of memory\n", progname); return bl; } @@ -1028,7 +1234,7 @@ getping(sonar_info *si, ping_info *pi, int ttl) /* Create the new Bogie and add it to the list we are building */ - if ((new = newBogie(name, 0, si->current, ttl)) == NULL) + if ((new = newBogie(name, 0, si->current, si->TTL)) == NULL) return bl; new->next = bl; bl = new; @@ -1040,6 +1246,7 @@ getping(sonar_info *si, ping_info *pi, int ttl) new->distance = delta(then, &now) / 100; if (new->distance == 0) new->distance = 2; /* HACK */ + } } /* Done */ @@ -1062,6 +1269,11 @@ static Bogie * ping(sonar_info *si, void *vpi) { + /* + * This tries to distribute the targets evely around the field of the + * sonar. + */ + ping_info *pi = (ping_info *) vpi; static ping_target *ptr = NULL; @@ -1087,7 +1299,7 @@ ping(sonar_info *si, void *vpi) /* Get the results */ - return getping(si, pi, TTL); + return getping(si, pi); } #endif /* HAVE_PING */ @@ -1126,7 +1338,7 @@ init_sim(void) /* Create the simulation info structure */ if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) { - fprintf(stderr, "Out of memory\n"); + fprintf(stderr, "%s: Out of memory\n", progname); return NULL; } @@ -1136,7 +1348,7 @@ init_sim(void) if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target))) == NULL) { free(si); - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); return NULL; } si->teamAID = get_string_resource("teamAName", "TeamAName"); @@ -1144,12 +1356,13 @@ init_sim(void) if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4)) == NULL) { free(si); - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); return NULL; } sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1); - si->teamA[i].nexttick = (int) (90.0 * random() / RAND_MAX); - si->teamA[i].nextdist = (int) (100.0 * random() / RAND_MAX); + si->teamA[i].nexttick = random() % 90; + si->teamA[i].nextdist = random() % 100; + si->teamA[i].movedonsweep = -1; } /* Team B */ @@ -1158,7 +1371,7 @@ init_sim(void) if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target))) == NULL) { free(si); - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); return NULL; } si->teamBID = get_string_resource("teamBName", "TeamBName"); @@ -1166,12 +1379,13 @@ init_sim(void) if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4)) == NULL) { free(si); - fprintf(stderr, "Out of Memory\n"); + fprintf(stderr, "%s: Out of Memory\n", progname); return NULL; } sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1); - si->teamB[i].nexttick = (int) (90.0 * random() / RAND_MAX); - si->teamB[i].nextdist = (int) (100.0 * random() / RAND_MAX); + si->teamB[i].nexttick = random() % 90; + si->teamB[i].nextdist = random() % 100; + si->teamB[i].movedonsweep = -1; } /* Done */ @@ -1179,6 +1393,26 @@ init_sim(void) return si; } +/* + * Creates and returns a drawing mask for the scope: + * mask out anything outside of the disc. + */ +static Pixmap +scope_mask (Display *dpy, Window win, sonar_info *si) +{ + XGCValues gcv; + Pixmap mask = XCreatePixmap(dpy, win, si->width, si->height, 1); + GC gc = XCreateGC (dpy, mask, 0, &gcv); + XSetFunction (dpy, gc, GXclear); + XFillRectangle (dpy, mask, gc, 0, 0, si->width, si->height); + XSetFunction (dpy, gc, GXset); + XFillArc(dpy, mask, gc, si->minx, si->miny, + si->maxx - si->minx, si->maxy - si->miny, + 0, 360 * 64); + return mask; +} + + /* * Initialize the Sonar. * @@ -1206,7 +1440,7 @@ init_sonar(Display *dpy, Window win) /* Create the Sonar information structure */ if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) { - fprintf(stderr, "Out of memory\n"); + fprintf(stderr, "%s: Out of memory\n", progname); return NULL; } @@ -1214,7 +1448,7 @@ init_sonar(Display *dpy, Window win) si->dpy = dpy; si->win = win; - si->visable = NULL; + si->visible = NULL; XGetWindowAttributes(dpy, win, &xwa); si->cmap = xwa.colormap; si->width = xwa.width; @@ -1227,20 +1461,23 @@ init_sonar(Display *dpy, Window win) si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10; si->radius = si->maxx - si->centrex; si->current = 0; + si->sweepnum = 0; /* Get the font */ if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font"))) == NULL) && ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) { - fprintf(stderr, "Can't load an appropriate font\n"); + fprintf(stderr, "%s: can't load an appropriate font\n", progname); return NULL; } /* Get the delay between animation frames */ si->delay = get_integer_resource ("delay", "Integer"); + if (si->delay < 0) si->delay = 0; + si->TTL = get_integer_resource("ttl", "TTL"); /* Create the Graphics Contexts that will be used to draw things */ @@ -1256,6 +1493,14 @@ init_sonar(Display *dpy, Window win) dpy, si->cmap); si->grid = XCreateGC (dpy, win, GCForeground, &gcv); + /* Install the clip mask... */ + { + Pixmap mask = scope_mask (dpy, win, si); + XSetClipMask(dpy, si->text, mask); + XSetClipMask(dpy, si->erase, mask); + XFreePixmap (dpy, mask); /* it's been copied into the GCs */ + } + /* Compute pixel values for fading text on the display */ XParseColor(dpy, si->cmap, @@ -1299,6 +1544,9 @@ init_sonar(Display *dpy, Window win) si->sweep_colors, &si->sweep_segs, False, True, False); + if (si->sweep_segs <= 0) + si->sweep_segs = 1; + /* Done */ return si; @@ -1314,9 +1562,8 @@ updateLocation(sim_target *t) int xdist, xtick; - t->movedlasttick = 1; - xtick = (int) (3.0 * random() / RAND_MAX) - 1; - xdist = (int) (11.0 * random() / RAND_MAX) - 5; + xtick = (int) (random() % 3) - 1; + xdist = (int) (random() % 11) - 5; if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0)) t->nexttick += xtick; else @@ -1353,29 +1600,30 @@ simulator(sonar_info *si, void *vinfo) for (i = 0; i < info->numA; i++) { t = &info->teamA[i]; - if (!t->movedlasttick && (t->nexttick == (si->current * -1))) { - new = newBogie(strdup(t->name), t->nextdist, si->current, TTL); + if ((t->movedonsweep != si->sweepnum) && + (t->nexttick == (si->current * -1))) { + new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL); if (list != NULL) new->next = list; list = new; updateLocation(t); - } else - t->movedlasttick = 0; + t->movedonsweep = si->sweepnum; + } } /* Team B */ for (i = 0; i < info->numB; i++) { t = &info->teamB[i]; - if (!t->movedlasttick && (t->nexttick == (si->current * -1))) { - new = newBogie(strdup(t->name), t->nextdist, si->current, TTL); + if ((t->movedonsweep != si->sweepnum) && + (t->nexttick == (si->current * -1))) { + new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL); if (list != NULL) new->next = list; list = new; - t->movedlasttick = 1; updateLocation(t); - } else - t->movedlasttick = 0; + t->movedonsweep = si->sweepnum; + } } /* Done */ @@ -1452,7 +1700,8 @@ DrawBogie(sonar_info *si, int draw, char *name, int degrees, /* Compute the coordinates of the object */ - distance = (log((double) distance) / 10.0) * si->radius; + if (distance != 0) + distance = (log((double) distance) / 10.0) * si->radius; x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578)); y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578)); @@ -1562,13 +1811,13 @@ Sonar(sonar_info *si, Bogie *bl) Bogie *bp, *prev; int i; - /* Check for expired tagets and remove them from the visable list */ + /* Check for expired tagets and remove them from the visible list */ prev = NULL; - for (bp = si->visable; bp != NULL; bp = bp->next) { + for (bp = si->visible; bp != NULL; bp = (bp ? bp->next : 0)) { /* - * Remove it from the visable list if it's expired or we have + * Remove it from the visible list if it's expired or we have * a new target with the same name. */ @@ -1579,10 +1828,11 @@ Sonar(sonar_info *si, Bogie *bl) DrawBogie(si, 0, bp->name, bp->tick, bp->distance, bp->ttl, bp->age); if (prev == NULL) - si->visable = bp->next; + si->visible = bp->next; else prev->next = bp->next; freeBogie(bp); + bp = prev; } else prev = bp; } @@ -1608,17 +1858,17 @@ Sonar(sonar_info *si, Bogie *bl) (4 * 64)); } - /* Move the new targets to the visable list */ + /* Move the new targets to the visible list */ for (bp = bl; bp != (Bogie *) 0; bp = bl) { bl = bl->next; - bp->next = si->visable; - si->visable = bp; + bp->next = si->visible; + si->visible = bp; } - /* Draw the visable targets */ + /* Draw the visible targets */ - for (bp = si->visable; bp != NULL; bp = bp->next) { + for (bp = si->visible; bp != NULL; bp = bp->next) { if (bp->age < bp->ttl) /* grins */ DrawBogie(si, 1, bp->name, bp->tick, bp->distance, bp->ttl,bp->age); } @@ -1628,6 +1878,124 @@ Sonar(sonar_info *si, Bogie *bl) drawGrid(si); } + +static ping_target * +parse_mode (Bool ping_works_p) +{ + char *source = get_string_resource ("ping", "Ping"); + char *token, *end; + char dummy; + + ping_target *hostlist = 0; + + if (!source) source = strdup(""); + + if (!*source || !strcmp (source, "default")) + { +# ifdef HAVE_PING + if (ping_works_p) /* if root or setuid, ping will work. */ + source = strdup("subnet/29,/etc/hosts"); + else +# endif + source = strdup("simulation"); + } + + token = source; + end = source + strlen(source); + while (token < end) + { + char *next; +# ifdef HAVE_PING + ping_target *new; + struct stat st; + unsigned int n0=0, n1=0, n2=0, n3=0, m=0; + char d; +# endif /* HAVE_PING */ + + for (next = token; + *next && + *next != ',' && *next != ' ' && *next != '\t' && *next != '\n'; + next++) + ; + *next = 0; + + + if (debug_p) + fprintf (stderr, "%s: parsing %s\n", progname, token); + + if (!strcmp (token, "simulation")) + return 0; + + if (!ping_works_p) + { + fprintf(stderr, + "%s: this program must be setuid to root for `ping mode' to work.\n" + " Running in `simulation mode' instead.\n", + progname); + return 0; + } + +#ifdef HAVE_PING + if ((4 == sscanf (token, "%u.%u.%u/%u %c", &n0,&n1,&n2, &m,&d)) || + (5 == sscanf (token, "%u.%u.%u.%u/%u %c", &n0,&n1,&n2,&n3,&m,&d))) + { + /* subnet: A.B.C.D/M + subnet: A.B.C/M + */ + unsigned long ip = (n0 << 24) | (n1 << 16) | (n2 << 8) | n3; + new = subnetHostsList(ip, m); + } + else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d)) + { + /* IP: A.B.C.D + */ + new = newHost (token); + } + else if (!strcmp (token, "subnet")) + { + new = subnetHostsList(0, 24); + } + else if (1 == sscanf (token, "subnet/%u %c", &m, &dummy)) + { + new = subnetHostsList(0, m); + } + else if (*token == '.' || *token == '/' || !stat (token, &st)) + { + /* file name + */ + new = readPingHostsFile (token); + } + else + { + /* not an existant file - must be a host name + */ + new = newHost (token); + } + + if (new) + { + ping_target *nn = new; + while (nn && nn->next) + nn = nn->next; + nn->next = hostlist; + hostlist = new; + + sensor = ping; + } +#endif /* HAVE_PING */ + + token = next + 1; + while (token < end && + (*token == ',' || *token == ' ' || + *token == '\t' || *token == '\n')) + token++; + } + + return hostlist; +} + + + /* * Main screen saver hack. * @@ -1646,73 +2014,57 @@ screenhack(Display *dpy, Window win) struct timeval start, finish; Bogie *bl; long sleeptime; - char *mode; - /* - * Initialize - * Adding new sensors would involve supporting more modes other than - * ping and initiailizing the sensor in the same way. - */ + debug_p = get_boolean_resource ("debug", "Debug"); - mode = get_string_resource("mode", "Mode"); + sensor = 0; +# ifdef HAVE_PING + sensor_info = (void *) init_ping(); +# else /* !HAVE_PING */ + sensor_info = 0; + parse_mode (0); /* just to check argument syntax */ +# endif /* !HAVE_PING */ - if (!mode || !*mode || !strcmp(mode, "default")) /* Pick a good default. */ + if (sensor == 0) { -#ifdef HAVE_PING - if (geteuid() == 0) /* we're root or setuid -- ping will work. */ - mode = "ping"; - else -#endif - mode = "simulation"; + sensor = simulator; + if ((sensor_info = (void *) init_sim()) == NULL) + exit(1); } -#ifdef HAVE_PING - if (strcmp(mode, "ping") == 0) { - sensor = ping; - if ((sensor_info = (void *) init_ping()) == (void *) 0) - { - fprintf (stderr, "%s: running in `simulation mode' instead.\n", - progname); - goto SIM; - } - } else -#endif /* HAVE_PING */ - if (strcmp(mode, "simulation") == 0) { -#ifdef HAVE_PING - SIM: -#endif - sensor = simulator; - if ((sensor_info = (void *) init_sim()) == NULL) - exit(1); - } else { - fprintf(stderr, "Unsupported Sonar mode: %s\n", mode); - fprintf(stderr, - "\tCurrently supported modes are `ping' and `simulation'\n"); - exit(1); - } if ((si = init_sonar(dpy, win)) == (sonar_info *) 0) exit(1); - - /* Sonar loop */ - TTL = get_integer_resource("ttl", "TTL"); + + /* Sonar loop */ while (1) { /* Call the sensor and display the results */ +# ifdef GETTIMEOFDAY_TWO_ARGS gettimeofday(&start, (struct timezone *) 0); +# else + gettimeofday(&start); +# endif bl = sensor(si, sensor_info); Sonar(si, bl); /* Set up and sleep for the next one */ si->current = (si->current - 1) % 90; + if (si->current == 0) + si->sweepnum++; XSync (dpy, False); +# ifdef GETTIMEOFDAY_TWO_ARGS gettimeofday(&finish, (struct timezone *) 0); +# else + gettimeofday(&finish); +# endif sleeptime = si->delay - delta(&start, &finish); screenhack_handle_events (dpy); if (sleeptime > 0L) usleep(sleeptime); + } }