http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / sonar.c
index 00f7b3f6fc5e7d1a4da7ca874fe4b6b65212b83a..6b1453398ce7e8a92d96c77622f3877ff363c65f 100644 (file)
@@ -38,7 +38,7 @@
  * software for any purpose.  It is provided "as is" without express or 
  * implied warranty.
  *
- * $Revision: 1.29 $
+ * $Revision: 1.37 $
  *
  * Version 1.0 April 27, 1998.
  * - Initial version
@@ -174,6 +174,7 @@ static long delta(struct timeval *, struct timeval *);
 
 typedef struct Bogie {
     char *name;                        /* The name of the thing being displayed */
+    char *desc;                        /* Beneath the name (e.g., ping time) */
     int distance;              /* The distance to this thing (0 - 100) */
     int tick;                  /* The tick that it was found on */
     int ttl;                   /* The time to live */
@@ -215,6 +216,8 @@ typedef struct {
 } sonar_info;
 
 static Bool debug_p = False;
+static Bool resolve_p = True;
+static Bool times_p = True;
 
 
 /* 
@@ -314,6 +317,8 @@ char *defaults [] = {
     "*teamBCount:      4",
 
     "*ping:           default",
+    "*resolve:        true",
+    "*showTimes:       true",
     ".debug:          false",
     0
 };
@@ -337,6 +342,8 @@ XrmOptionDescRec options [] = {
     {"-team-b-count",  ".teamBCount",  XrmoptionSepArg, 0 },
 
     {"-ping",          ".ping",        XrmoptionSepArg, 0 },
+    {"-no-dns",        ".resolve",     XrmoptionNoArg, "False" },
+    {"-no-times",      ".showTimes",   XrmoptionNoArg, "False" },
     {"-debug",         ".debug",       XrmoptionNoArg, "True" },
     { 0, 0, 0, 0 }
 };
@@ -436,6 +443,31 @@ findNode(Bogie *bl, char *name)
 
 #ifdef HAVE_PING
 
+/* Packs an IP address quad into bigendian network order. */
+static unsigned long
+pack_addr (unsigned int a, unsigned int b, unsigned int c, unsigned int d)
+{
+  unsigned long i = (((a & 255) << 24) |
+                     ((b & 255) << 16) |
+                     ((c & 255) <<  8) |
+                     ((d & 255)      ));
+  return htonl (i);
+}
+
+/* Unpacks an IP address quad from bigendian network order. */
+static void
+unpack_addr (unsigned long addr,
+             unsigned int *a, unsigned int *b,
+             unsigned int *c, unsigned int *d)
+{
+  addr = ntohl (addr);
+  *a = (addr >> 24) & 255;
+  *b = (addr >> 16) & 255;
+  *c = (addr >>  8) & 255;
+  *d = (addr      ) & 255;
+}
+
+
 /*
  * Lookup the address for a ping target;
  *
@@ -452,24 +484,17 @@ lookupHost(ping_target *target)
   struct hostent *hent;
   struct sockaddr_in *iaddr;
 
-  int iip[4];
+  unsigned int ip[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))
+  if (4 == sscanf (target->name, " %u.%u.%u.%u %c",
+                   &ip[0], &ip[1], &ip[2], &ip[3], &c))
     {
       /* It's an IP address.
        */
-      unsigned char ip[4];
-
-      ip[0] = iip[0];
-      ip[1] = iip[1];
-      ip[2] = iip[2];
-      ip[3] = iip[3];
-
       if (ip[3] == 0)
         {
           if (debug_p > 1)
@@ -478,11 +503,13 @@ lookupHost(ping_target *target)
           return 0;
         }
 
-      iaddr->sin_addr.s_addr = ((ip[3] << 24) |
-                                (ip[2] << 16) |
-                                (ip[1] <<  8) |
-                                (ip[0]));
-      hent = gethostbyaddr ((const char *) ip, 4, AF_INET);
+      iaddr->sin_addr.s_addr = pack_addr (ip[0], ip[1], ip[2], ip[3]);
+      if (resolve_p)
+        hent = gethostbyaddr ((const char *) &iaddr->sin_addr.s_addr,
+                              sizeof(iaddr->sin_addr.s_addr),
+                              AF_INET);
+      else
+        hent = 0;
 
       if (debug_p > 1)
         fprintf (stderr, "%s:   %s => %s\n",
@@ -497,6 +524,16 @@ lookupHost(ping_target *target)
     {
       /* It's a host name.
        */
+
+
+      /* don't waste time being confused by non-hostname tokens
+         in .ssh/known_hosts */
+      if (!strcmp (target->name, "ssh-rsa") ||
+          !strcmp (target->name, "ssh-dsa") ||
+          !strcmp (target->name, "ssh-dss") ||
+          strlen (target->name) >= 80)
+        return 0;
+
       hent = gethostbyname (target->name);
       if (!hent)
         {
@@ -509,12 +546,12 @@ lookupHost(ping_target *target)
               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);
+        {
+          unsigned int a, b, c, d;
+          unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
+          fprintf (stderr, "%s:   %s => %d.%d.%d.%d\n",
+                   progname, target->name, a, b, c, d);
+        }
     }
   return 1;
 }
@@ -524,11 +561,9 @@ 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);
+  unsigned int a, b, c, d;
+  unpack_addr (ip, &a, &b, &c, &d);            /* ip is in network order */
+  sprintf (ips, "%u.%u.%u.%u", a, b, c, d);
   if (!name || !*name) name = "<unknown>";
   fprintf (out, "%-16s %s\n", ips, name);
 }
@@ -568,13 +603,12 @@ newHost(char *name)
     if (! lookupHost(target))
        goto target_init_error;
 
-    /* Don't ever use loopback (127.0.0) hosts */
+    /* Don't ever use loopback (127.0.0.x) 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 ((ntohl (ip) & 0xFFFFFF00L) == 0x7f000000L)  /* 127.0.0 */
         {
           if (debug_p)
             fprintf (stderr, "%s:   ignoring loopback host %s\n",
@@ -764,16 +798,17 @@ delete_duplicate_hosts (ping_target *list)
 
 /*
  * Generate a list ping targets consisting of all of the entries on
- * the same subnet.
+ * the same subnet.  'base' ip is in network order; 0 means localhost.
  *
  * Returns:
  *    A list of all of the hosts on this net.
  */
 
 static ping_target *
-subnetHostsList(int base, int subnet_width) 
+subnetHostsList(unsigned long n_base, int subnet_width)
 {
-    unsigned long mask;
+    unsigned long h_mask;   /* host order */
+    unsigned long h_base;   /* host order */
 
     /* Local Variables */
 
@@ -822,54 +857,56 @@ subnetHostsList(int base, int subnet_width)
 
     /* Construct targets for all addresses in this subnet */
 
-    mask = 0;
+    h_mask = 0;
     for (i = 0; i < subnet_width; i++)
-      mask |= (1L << (31-i));
+      h_mask |= (1L << (31-i));
 
     /* 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])));
-
-    if (base == ((127 << 24) | 1))
+    if (n_base == 0)
+      n_base = pack_addr (hent->h_addr_list[0][0],
+                          hent->h_addr_list[0][1],
+                          hent->h_addr_list[0][2],
+                          hent->h_addr_list[0][3]);
+    h_base = ntohl (n_base);
+
+    if (h_base == 0x7F000001L)   /* 127.0.0.1 in host order */
       {
+        unsigned int a, b, c, d;
+        unpack_addr (n_base, &a, &b, &c, &d);
         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);
+                 "       resolves to loopback address %u.%u.%u.%u.\n",
+                 progname, hostname, a, b, c, d);
         return NULL;
       }
 
     for (i = 255; i >= 0; i--) {
-        int ip = (base & 0xFFFFFF00) | i;
+        unsigned int a, b, c, d;
+        int ip = (h_base & 0xFFFFFF00L) | i;     /* host order */
       
-        if ((ip & mask) != (base & mask))   /* not in the mask range at all */
+        if ((ip & h_mask) != (h_base & h_mask))  /* not in mask range at all */
           continue;
-        if ((ip & ~mask) == 0)              /* broadcast address */
+        if ((ip & ~h_mask) == 0)                 /* broadcast address */
           continue;
-        if ((ip & ~mask) == ~mask)          /* broadcast address */
+        if ((ip & ~h_mask) == ~h_mask)           /* broadcast address */
           continue;
 
-        sprintf (address, "%d.%d.%d.%d", 
-                 (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, (ip)&255);
+        unpack_addr (htonl (ip), &a, &b, &c, &d);
+        sprintf (address, "%u.%u.%u.%u", a, b, c, d);
 
         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);
+          {
+            unsigned int aa, ab, ac, ad;
+            unsigned int ma, mb, mc, md;
+            unpack_addr (htonl (h_base & h_mask), &aa, &ab, &ac, &ad);
+            unpack_addr (htonl (h_mask),          &ma, &mb, &mc, &md);
+            fprintf (stderr,
+                     "%s:  subnet: %s (%u.%u.%u.%u & %u.%u.%u.%u / %d)\n",
+                     progname, address,
+                     aa, ab, ac, ad,
+                     ma, mb, mc, md,
+                     subnet_width);
+          }
 
         p = address + strlen(address) + 1;
        sprintf(p, "%d", i);
@@ -1188,6 +1225,8 @@ getping(sonar_info *si, ping_info *pi)
        ip = (struct ip *) packet;
         iphdrlen = IP_HDRLEN(ip) << 2;
        icmph = (struct ICMP *) &packet[iphdrlen];
+       then  = (struct timeval *) &packet[iphdrlen + sizeof(struct ICMP)];
+
 
        /* Was the packet a reply?? */
 
@@ -1213,6 +1252,12 @@ getping(sonar_info *si, ping_info *pi)
            return bl;
        }
 
+# if 0  /* Don't need to do this -- the host names are already as
+           resolved as they're going to get.  (We stored the resolved
+           name in the outgoing ping packet, so that same string just
+           came back to us.)
+         */
+
         /* If the name is an IP addr, try to resolve it. */
         {
           int iip[4];
@@ -1220,10 +1265,16 @@ getping(sonar_info *si, ping_info *pi)
           if (4 == sscanf(name, " %d.%d.%d.%d %c",
                           &iip[0], &iip[1], &iip[2], &iip[3], &c))
             {
-              unsigned char ip[4];
+              struct sockaddr_in iaddr;
               struct hostent *h;
-              ip[0] = iip[0]; ip[1] = iip[1]; ip[2] = iip[2]; ip[3] = iip[3];
-              h = gethostbyaddr ((char *) ip, 4, AF_INET);
+              iaddr.sin_addr.s_addr = pack_addr (iip[0],iip[1],iip[2],iip[3]);
+              if (resolve_p)
+                h = gethostbyaddr ((const char *) &iaddr.sin_addr.s_addr,
+                                   sizeof(iaddr.sin_addr.s_addr),
+                                   AF_INET);
+              else
+                h = 0;
+
               if (h && h->h_name && *h->h_name)
                 {
                   free (name);
@@ -1231,6 +1282,7 @@ getping(sonar_info *si, ping_info *pi)
                 }
             }
         }
+# endif /* 0 */
 
        /* Create the new Bogie and add it to the list we are building */
 
@@ -1239,13 +1291,48 @@ getping(sonar_info *si, ping_info *pi)
        new->next = bl;
        bl = new;
 
-       /* Compute the round trip time */
+        {
+          float msec = delta(then, &now) / 1000.0;
+
+          if (times_p)
+            {
+              if (new->desc) free (new->desc);
+              new->desc = (char *) malloc (30);
+              if      (msec > 99) sprintf (new->desc, "    %.0f ms   ", msec);
+              else if (msec >  9) sprintf (new->desc, "    %.1f ms   ", msec);
+              else if (msec >  1) sprintf (new->desc, "    %.2f ms   ", msec);
+              else                sprintf (new->desc, "    %.3f ms   ", msec);
+            }
 
-       then =  (struct timeval *) &packet[iphdrlen +
-                                         sizeof(struct ICMP)];
-       new->distance = delta(then, &now) / 100;
-       if (new->distance == 0)
-               new->distance = 2; /* HACK */
+          if (debug_p && times_p)  /* print ping-like stuff to stdout */
+            {
+              struct sockaddr_in *iaddr = (struct sockaddr_in *) &from;
+              unsigned int a, b, c, d;
+              char ipstr[20];
+              char *s = strdup (new->desc);
+              char *s2 = s, *s3 = s;
+              while (*s2 == ' ') s2++;
+              s3 = strchr (s2, ' ');
+              if (s3) *s3 = 0;
+
+              unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
+              sprintf (ipstr, "%d.%d.%d.%d", a, b, c, d);
+
+              fprintf (stdout,
+                       "%3d bytes from %28s: "
+                       "icmp_seq=%-4d ttl=%d time=%s ms\n",
+                       result,
+                       name,
+                       /*ipstr,*/
+                       ICMP_SEQ(icmph), si->TTL, s2);
+              free (s);
+            }
+
+          /* Don't put anyone *too* close to the center of the screen. */
+          msec += 0.6;
+
+          new->distance = msec * 10;
+        }
       }
     }
 
@@ -1413,6 +1500,29 @@ scope_mask (Display *dpy, Window win, sonar_info *si)
 }
 
 
+static void
+reshape (sonar_info *si)
+{
+  XWindowAttributes xgwa;
+  Pixmap mask;
+  XGetWindowAttributes(si->dpy, si->win, &xgwa);
+  si->width = xgwa.width;
+  si->height = xgwa.height;
+  si->centrex = si->width / 2;
+  si->centrey = si->height / 2;
+  si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
+  si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
+  si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
+  si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
+  si->radius = si->maxx - si->centrex;
+
+  /* Install the clip mask... */
+  mask = scope_mask (si->dpy, si->win, si);
+  XSetClipMask(si->dpy, si->text, mask);
+  XSetClipMask(si->dpy, si->erase, mask);
+  XFreePixmap (si->dpy, mask); /* it's been copied into the GCs */
+}
+
 /*
  * Initialize the Sonar.
  *
@@ -1449,17 +1559,10 @@ init_sonar(Display *dpy, Window win)
     si->dpy = dpy;
     si->win = win;
     si->visible = NULL;
+
     XGetWindowAttributes(dpy, win, &xwa);
     si->cmap = xwa.colormap;
-    si->width = xwa.width;
-    si->height = xwa.height;
-    si->centrex = si->width / 2;
-    si->centrey = si->height / 2;
-    si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
-    si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
-    si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
-    si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
-    si->radius = si->maxx - si->centrex;
+
     si->current = 0;
     si->sweepnum = 0;
 
@@ -1493,13 +1596,7 @@ 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 */
-    }
+    reshape (si);
 
     /* Compute pixel values for fading text on the display */
 
@@ -1644,7 +1741,7 @@ simulator(sonar_info *si, void *vinfo)
  */
 
 static int
-computeStringX(sonar_info *si, char *label, int x) 
+computeStringX(sonar_info *si, const char *label, int x) 
 {
 
     int width = XTextWidth(si->font, label, strlen(label));
@@ -1662,14 +1759,12 @@ computeStringX(sonar_info *si, char *label, int x)
  *    The y coordinate of the start of the label.
  */
 
-/* TODO: Add smarts to keep label in sonar screen */
-
 static int
 computeStringY(sonar_info *si, int y) 
 {
 
-    int fheight = si->font->ascent + si->font->descent;
-    return y + 5 + fheight;
+    int fheight = si->font->ascent /* + si->font->descent */;
+    return y + fheight;
 }
 
 /*
@@ -1686,8 +1781,8 @@ computeStringY(sonar_info *si, int y)
  */
 
 static void
-DrawBogie(sonar_info *si, int draw, char *name, int degrees, 
-         int distance, int ttl, int age) 
+DrawBogie(sonar_info *si, int draw, const char *name, const char *desc,
+          int degrees, int distance, int ttl, int age) 
 {
 
     /* Local Variables */
@@ -1730,9 +1825,21 @@ DrawBogie(sonar_info *si, int draw, char *name, int degrees,
   /* Draw (or erase) the Bogie */
 
     XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64);
+
+    x += 3;  /* move away from the dot */
+    y += 7;
+    y = computeStringY(si, y);
     XDrawString(si->dpy, si->win, gc,
-               computeStringX(si, name, x),
-               computeStringY(si, y), name, strlen(name));
+                computeStringX(si, name, x), y,
+                name, strlen(name));
+
+    if (desc && *desc)
+      {
+        y = computeStringY(si, y);
+        XDrawString(si->dpy, si->win, gc,
+                    computeStringX(si, desc, x), y,
+                    desc, strlen(desc));
+      }
 }
 
 
@@ -1825,7 +1932,7 @@ Sonar(sonar_info *si, Bogie *bl)
 
        if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) ||
            (findNode(bl, bp->name) != NULL)) {
-           DrawBogie(si, 0, bp->name, bp->tick,
+           DrawBogie(si, 0, bp->name, bp->desc, bp->tick,
                      bp->distance, bp->ttl, bp->age);
            if (prev == NULL)
                si->visible = bp->next;
@@ -1870,7 +1977,8 @@ Sonar(sonar_info *si, Bogie *bl)
 
     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);
+          DrawBogie(si, 1, bp->name, bp->desc,
+                     bp->tick, bp->distance, bp->ttl,bp->age);
     }
 
     /* Redraw the grid */
@@ -1942,7 +2050,7 @@ parse_mode (Bool ping_works_p)
           /* subnet: A.B.C.D/M
              subnet: A.B.C/M
            */
-          unsigned long ip = (n0 << 24) | (n1 << 16) | (n2 << 8) | n3;
+          unsigned long ip = pack_addr (n0, n1, n2, n3);
           new = subnetHostsList(ip, m);
         }
       else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d))
@@ -1995,6 +2103,25 @@ parse_mode (Bool ping_works_p)
 }
 
 
+static void
+handle_events (sonar_info *si)
+{
+  while (XPending (si->dpy))
+    {
+      XEvent event;
+      XNextEvent (si->dpy, &event);
+
+      if (event.xany.type == ConfigureNotify)
+        {
+          XClearWindow (si->dpy, si->win);
+          reshape (si);
+        }
+
+      screenhack_handle_event (si->dpy, &event);
+    }
+}
+
+
 
 /*
  * Main screen saver hack.
@@ -2016,6 +2143,8 @@ screenhack(Display *dpy, Window win)
     long sleeptime;
 
     debug_p = get_boolean_resource ("debug", "Debug");
+    resolve_p = get_boolean_resource ("resolve", "Resolve");
+    times_p = get_boolean_resource ("showTimes", "ShowTimes");
 
     sensor = 0;
 # ifdef HAVE_PING
@@ -2062,7 +2191,7 @@ screenhack(Display *dpy, Window win)
        gettimeofday(&finish);
 # endif
        sleeptime = si->delay - delta(&start, &finish);
-        screenhack_handle_events (dpy);
+        handle_events (si);
        if (sleeptime > 0L)
            usleep(sleeptime);