ftp://netsw.org/x11/tools/desktop/xscreensaver-4.07.tar.gz
[xscreensaver] / hacks / sonar.c
index 0fa608aa5b257fcd59edb3ce3dbd676a72061835..c58f6aef69aedee357c8cabac933b2a3b893e117 100644 (file)
@@ -38,7 +38,7 @@
  * software for any purpose.  It is provided "as is" without express or 
  * implied warranty.
  *
- * $Revision: 1.19 $
+ * $Revision: 1.23 $
  *
  * Version 1.0 April 27, 1998.
  * - Initial version
@@ -230,7 +230,9 @@ void *sensor_info;                  /* Information about the sensor */
 
 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;
 
@@ -446,47 +448,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;
+
+  iaddr = (struct sockaddr_in *) &(target->address);
+  iaddr->sin_family = AF_INET;
+
+  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];
 
-    struct sockaddr_in *iaddr;
+      ip[0] = iip[0];
+      ip[1] = iip[1];
+      ip[2] = iip[2];
+      ip[3] = iip[3];
 
-    /* Set up the target address we first assume that the name is the
-       IP address as a string */
+      if (ip[3] == 0)
+        {
+          if (debug_p > 1)
+            fprintf (stderr, "%s:   ignoring bogus IP %s\n",
+                     progname, target->name);
+          return 0;
+        }
 
-    iaddr = (struct sockaddr_in *) &(target->address);
-    iaddr->sin_family = AF_INET;
-    if ((iaddr->sin_addr.s_addr = inet_addr(target->name)) >= 0) {
-      char ip[4];
-      ip[3] = iaddr->sin_addr.s_addr >> 24 & 255;
-      ip[2] = iaddr->sin_addr.s_addr >> 16 & 255;
-      ip[1] = iaddr->sin_addr.s_addr >>  8 & 255;
-      ip[0] = iaddr->sin_addr.s_addr       & 255;
+      iaddr->sin_addr.s_addr = ((ip[3] << 24) |
+                                (ip[2] << 16) |
+                                (ip[1] <<  8) |
+                                (ip[0]));
       hent = gethostbyaddr (ip, 4, AF_INET);
-      if (hent && hent->h_name && *hent->h_name) {
+
+      if (debug_p > 1)
+        fprintf (stderr, "%s:   %s => %s\n",
+                 progname, target->name,
+                 ((hent && hent->h_name && *hent->h_name)
+                  ? hent->h_name : "<unknown>"));
+
+      if (hent && hent->h_name && *hent->h_name)
         target->name = strdup (hent->h_name);
-        return 1;
-      }
     }
+  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;
+        }
 
-    /* Conversion of IP address failed, try to look the host up by name */
+      memcpy (&iaddr->sin_addr, hent->h_addr_list[0],
+              sizeof(iaddr->sin_addr));
 
-    hent = gethostbyname(target->name);
-    if (hent == NULL) {
-      fprintf(stderr, "%s: could not resolve host %s\n",
-              progname, target->name);
-      return 0;
+      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);
     }
-    memcpy(&iaddr->sin_addr, hent->h_addr_list[0],
-           sizeof(iaddr->sin_addr));
+  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 = "<unknown>";
+  fprintf (out, "%-16s %s\n", ips, name);
 }
 
+
 /*
  * Create a target for a host.
  *
@@ -521,15 +567,29 @@ 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 host %d.%d.%d.%d (%s)\n", progname,
-                 ip & 255, ip >> 8 & 255, ip >> 16 & 255, ip >> 24 & 255, 
-                 target->name);
+        fprintf (stderr, "%s:   added ", progname);
+        print_host (stderr, ip, target->name);
       }
 
     return target;
@@ -603,8 +663,8 @@ 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;
 
@@ -622,7 +682,22 @@ readPingHostsFile(char *fname)
               addr = NULL;
             }
         }
-        /*printf ("\"%s\" \"%s\"\n", name, addr);*/
+
+        /* 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 */
 
@@ -670,8 +745,10 @@ delete_duplicate_hosts (ping_target *list)
               if (ip1 == ip2)
                 {
                   if (debug_p)
-                    fprintf (stderr, "%s: deleted duplicate: %s\n",
-                             progname, rest2->next->name);
+                    {
+                      fprintf (stderr, "%s: deleted duplicate: ", progname);
+                      print_host (stderr, ip2, rest2->next->name);
+                    }
                   rest2->next = rest2->next->next;
                 }
             }
@@ -710,9 +787,9 @@ subnetHostsList(int base, int subnet_width)
     if (subnet_width < 24)
       {
         fprintf (stderr,
-    "%s: pinging %u hosts is a bad idea; please use a subnet mask of 24 bits\n"
+   "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n"
                  "       or more (255 hosts max.)\n",
-                 progname, (1L << (32 - subnet_width)) - 1);
+                 progname, (unsigned long) (1L << (32 - subnet_width)) - 1);
         exit (1);
       }
     else if (subnet_width > 30)
@@ -755,6 +832,17 @@ subnetHostsList(int base, int subnet_width)
               (((unsigned char) hent->h_addr_list[0][2]) <<  8) |
               (((unsigned char) hent->h_addr_list[0][3])));
 
+    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 = 255; i >= 0; i--) {
         int ip = (base & 0xFFFFFF00) | i;
       
@@ -772,9 +860,15 @@ subnetHostsList(int base, int subnet_width)
           fprintf(stderr, "%s:  subnet: %s (%d.%d.%d.%d & %d.%d.%d.%d / %d)\n",
                   progname,
                   address,
-                  (base>>24)&255, (base>>16)&255, (base>>8)&255, base&mask&255,
-                  (mask>>24)&255, (mask>>16)&255, (mask>>8)&255, mask&255,
-                  subnet_width);
+                  (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);
@@ -839,6 +933,19 @@ init_ping(void)
     pi->targets = delete_duplicate_hosts (pi->targets);
 
 
+    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) {
@@ -1022,6 +1129,8 @@ getping(sonar_info *si, ping_info *pi)
     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 */
 
@@ -1047,9 +1156,21 @@ getping(sonar_info *si, ping_info *pi)
     /* 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 <valentyn@openoffice.nl> */
+      if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) {
+        result = recvfrom(pi->icmpsock, packet, sizeof(packet),
+                      0, &from, &fromlen);
 
        /* Check the packet */
 
@@ -1115,6 +1236,7 @@ getping(sonar_info *si, ping_info *pi)
        new->distance = delta(then, &now) / 100;
        if (new->distance == 0)
                new->distance = 2; /* HACK */
+      }
     }
 
     /* Done */
@@ -1228,8 +1350,8 @@ init_sim(void)
            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;
     }
 
@@ -1251,8 +1373,8 @@ init_sim(void)
            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;
     }
 
@@ -1384,6 +1506,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;
@@ -1399,8 +1524,8 @@ updateLocation(sim_target *t)
 
     int xdist, xtick;
 
-    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
@@ -1721,6 +1846,7 @@ parse_mode (Bool ping_works_p)
 {
   char *source = get_string_resource ("ping", "Ping");
   char *token, *end;
+  char dummy;
 
   ping_target *hostlist = 0;
 
@@ -1741,10 +1867,12 @@ parse_mode (Bool ping_works_p)
   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 != '\t' && *next != '\n';
@@ -1768,6 +1896,7 @@ parse_mode (Bool ping_works_p)
           return 0;
         }
 
+#ifdef HAVE_PING
       if ((4 == sscanf (token, "%d.%d.%d/%d %c",    &n0,&n1,&n2,    &m,&d)) ||
           (5 == sscanf (token, "%d.%d.%d.%d/%d %c", &n0,&n1,&n2,&n3,&m,&d)))
         {
@@ -1787,7 +1916,7 @@ parse_mode (Bool ping_works_p)
         {
           new = subnetHostsList(0, 24);
         }
-      else if (1 == sscanf (token, "subnet/%d %c", &m))
+      else if (1 == sscanf (token, "subnet/%d %c", &m, &dummy))
         {
           new = subnetHostsList(0, m);
         }
@@ -1814,6 +1943,7 @@ parse_mode (Bool ping_works_p)
 
           sensor = ping;
         }
+#endif /* HAVE_PING */
 
       token = next + 1;
       while (token < end &&
@@ -1849,7 +1979,12 @@ screenhack(Display *dpy, Window win)
     debug_p = get_boolean_resource ("debug", "Debug");
 
     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 (sensor == 0)
       {