home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / strob103.zip / strobe.c < prev    next >
C/C++ Source or Header  |  1998-12-31  |  22KB  |  995 lines

  1. /*
  2.  * Strobe (c) 1995 Julian Assange (proff@suburbia.net),
  3.  * All rights reserved.
  4.  *
  5.  * $ cc strobe.c -o strobe
  6.  */
  7.  
  8. #define VERSION "1.03"
  9.  
  10. #ifdef __OS2__
  11. #  include <os2.h>
  12. #endif
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <sys/types.h>
  17. #include <sys/time.h>
  18. #include <unistd.h>
  19. #include <ctype.h>
  20. #include <fcntl.h>
  21. #include <sys/stat.h>
  22. #include <sys/socket.h>
  23. #ifdef _AIX
  24. #  include <sys/select.h>
  25. #endif
  26. #include <netinet/in.h>
  27. #include <arpa/inet.h>
  28. #include <netdb.h>
  29. #include <string.h>
  30. #include <errno.h>
  31.  
  32. #if defined(solaris) || defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__GCC__)
  33. #  define fvoid void
  34. #else
  35. #  define fvoid
  36. extern int optind;
  37. extern char *optarg;
  38. #endif
  39. #define bool char
  40.  
  41. #ifndef INADDR_NONE
  42. #  define INADDR_NONE ((unsigned long)-1)
  43. #endif
  44.  
  45. #define port_t (unsigned short)
  46.  
  47. /*
  48.  * the below should be set via the Makefile, but if not...
  49.  */
  50.  
  51. #ifndef ETC_SERVICES
  52. #  define ETC_SERVICES "%etc%\\services"
  53. #endif
  54. #ifndef STROBE_SERVICES
  55. #  define STROBE_SERVICES "strobe.services"
  56. #endif
  57. #ifndef LIB_STROBE_SERVICES
  58. #  define LIB_STROBE_SERVICES "%etc%\\strobe.services"
  59. #endif
  60.  
  61. int a_timeout = 20;
  62. char *a_output = NULL;
  63. char *a_services = "strobe.services";
  64. char *a_input = NULL;
  65. /* char *a_prescan = NULL; */
  66. int a_start = 1;
  67. int a_end = 65535;
  68. int a_sock_max = 64;
  69. int a_abort = 0;
  70. int a_bindport = 0;
  71. char *a_bindaddr= NULL;
  72. struct in_addr bindaddr;
  73. bool f_linear = 0;
  74. bool f_verbose = 0;
  75. bool f_verbose_stats = 0;
  76. bool f_fast = 0;
  77. bool f_stats = 0;
  78. bool f_quiet = 0;
  79. bool f_delete_dupes = 0;
  80. bool f_minimise = 0;
  81. bool f_dontgetpeername = 0;
  82.  
  83. int connects = 0;
  84. int hosts_done = 0;
  85. int attempts_done = 0;
  86. int attempts_outstanding = 0;
  87. struct timeval time_start;
  88.  
  89. fd_set set_sel;
  90. fd_set set_sel_r;
  91. fd_set set_sel_w;
  92.  
  93. int host_n;
  94. int Argc;
  95. char **Argv;
  96.  
  97. FILE *fh_input;
  98.  
  99. #define HO_ACTIVE 1
  100. #define HO_ABORT 2
  101. #define HO_COMPLETING 4
  102.  
  103. struct hosts_s
  104. {
  105.     char *name;
  106.     struct in_addr in_addr;
  107.     int port;
  108.     int portlist_ent;
  109.     struct timeval time_used;
  110.     struct timeval time_start;
  111.     int attempts;
  112.     int attempts_done;
  113.     int attempts_highest_done;
  114.     int connects;
  115.     time_t notice_abort;
  116.     int status;
  117. };
  118. struct hosts_s ho_initial;
  119. struct hosts_s *hosts;
  120.  
  121. #define HT_SOCKET 1
  122. #define HT_CONNECTING 2
  123.  
  124. struct htuple_s
  125. {
  126.     char *name;
  127.     struct in_addr in_addr;
  128.     int port;
  129.     int sfd;
  130.     int status;
  131.     struct timeval sock_start;
  132.     int timeout;
  133.     struct hosts_s *host;
  134. };
  135.  
  136. struct htuple_s ht_initial;
  137. struct htuple_s *attempt;
  138.  
  139. struct port_desc_s
  140. {
  141.     int port;
  142.     char *name;
  143.     char *portname;
  144.     struct port_desc_s *next;
  145.     struct port_desc_s *next_port;
  146. };
  147.  
  148. struct port_desc_s **port_descs;
  149.  
  150. int *portlist = NULL;
  151. int portlist_n = 0;
  152.  
  153. char *
  154. Srealloc (ptr, len)
  155.   char *ptr;
  156.   int len;
  157. {
  158.     char *p;
  159.     int retries = 10;
  160.     while (!(p = ptr? realloc (ptr, len): malloc(len)))
  161.     {
  162.         if (!--retries)
  163.         {
  164.         perror("malloc");
  165.         exit(1);
  166.     }
  167.     if (!f_quiet)
  168.        fprintf(stderr, "Smalloc: couldn't allocate %d bytes...sleeping\n", len);
  169.     sleep (2);
  170.     }
  171.     return p;
  172. }
  173.  
  174. char *
  175. Smalloc (len)
  176.   int len;
  177. {
  178.    return Srealloc (NULL, len);
  179. }
  180.  
  181. fvoid
  182. sock_block (sfd)
  183.   int sfd;
  184. {
  185.     int flags;
  186.     flags = (~O_NONBLOCK) & fcntl (sfd, F_GETFL);
  187.     fcntl (sfd, F_SETFL, flags);
  188. }
  189.  
  190. fvoid
  191. sock_unblock (sfd)
  192.   int sfd;
  193. {
  194.     int flags;
  195.     flags = O_NONBLOCK | fcntl (sfd, F_GETFL);
  196.     fcntl (sfd, F_SETFL, flags);
  197. }
  198.  
  199. int
  200. timeval_subtract (result, x, y) /* from gnu c-lib info.texi */
  201.   struct timeval *result, *x, *y;
  202. {
  203. /* Perform the carry for the later subtraction by updating y. */
  204. if (x->tv_usec < y->tv_usec) {
  205.  int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
  206.  y->tv_usec -= 1000000 * nsec;
  207.  y->tv_sec += nsec;
  208. }
  209. if (x->tv_usec - y->tv_usec > 1000000) {
  210.  int nsec = (y->tv_usec - x->tv_usec) / 1000000;
  211.  y->tv_usec += 1000000 * nsec;
  212.  y->tv_sec -= nsec;
  213. }
  214.  
  215. /* Compute the time remaining to wait.
  216.   `tv_usec' is certainly positive. */
  217. result->tv_sec = x->tv_sec - y->tv_sec;
  218. result->tv_usec = x->tv_usec - y->tv_usec;
  219.  
  220. /* Return 1 if result is negative. */
  221. return x->tv_sec < y->tv_sec;
  222. }
  223.  
  224. fvoid
  225. attempt_clear (h)
  226.   struct htuple_s *h;
  227. {
  228.     if (h->status & HT_SOCKET)
  229.     {
  230.     struct timeval tv1, tv2;
  231.     gettimeofday(&tv1, NULL);
  232.     timeval_subtract(&tv2, &tv1, &(h->sock_start));
  233.     h->host->time_used.tv_sec+=tv2.tv_sec;
  234.     if ((h->host->time_used.tv_usec+=tv2.tv_usec) >= 1000000)
  235.     {
  236.         h->host->time_used.tv_usec -= 1000000;
  237.         h->host->time_used.tv_sec++;
  238.     }
  239.         attempts_done++;
  240.     h->host->attempts_done++;
  241.     if (h->port > h->host->attempts_highest_done)
  242.         h->host->attempts_highest_done=h->port;
  243.     sock_unblock (h->sfd);
  244. /*    shutdown (h->sfd, 2); */
  245.     close (h->sfd);
  246.         if (FD_ISSET(h->sfd, &set_sel))
  247.     {
  248.          FD_CLR (h->sfd, &set_sel);
  249.          attempts_outstanding--;
  250.     }
  251.     }
  252.     *h = ht_initial;
  253. }
  254.  
  255. fvoid
  256. clear_all ()
  257. {
  258.     int n;
  259.     for (n = 0; n < a_sock_max; n++)
  260.     attempt_clear (&attempt[n]);
  261. }
  262.  
  263. fvoid
  264. attempt_init ()
  265. {
  266.     int n;
  267.     for (n = 0; n < a_sock_max; n++)
  268.     attempt[n] = ht_initial;
  269. }
  270.  
  271. fvoid
  272. hosts_init ()
  273. {
  274.     int n;
  275.     for (n = 0; n < a_sock_max; n++)
  276.     hosts[n] = ho_initial;
  277. }
  278.  
  279. fvoid
  280. fdsets_init ()
  281. {
  282.     FD_ZERO(&set_sel_r); /* yes, we have to do this, despite the later */
  283.     FD_ZERO(&set_sel_w); /* assisgnments */
  284.     FD_ZERO(&set_sel);
  285. }
  286.  
  287. int
  288. sc_connect (h)
  289.   struct htuple_s *h;
  290. {
  291.     struct sockaddr_in sa_in;
  292.     int sopts1 = 1;
  293.     struct linger slinger;
  294.     if ((h->sfd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
  295.     return 0;
  296.     memset(&sa_in, 0, sizeof(sa_in));
  297.     h->status |= HT_SOCKET;
  298.     gettimeofday(&(h->sock_start), NULL);
  299.     sock_unblock (h->sfd);
  300.     setsockopt (h->sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &sopts1, sizeof (sopts1));
  301.     setsockopt (h->sfd, SOL_SOCKET, SO_OOBINLINE, (char *) &sopts1, sizeof (sopts1));
  302.     slinger.l_onoff = 0;    /* off */
  303.     setsockopt (h->sfd, SOL_SOCKET, SO_LINGER, (char *) &slinger, sizeof (slinger));
  304.     sa_in.sin_family = AF_INET;
  305.     if (a_bindport)
  306.         sa_in.sin_port = a_bindport;
  307.     if (a_bindaddr)
  308.         sa_in.sin_addr = bindaddr;
  309.     if (a_bindaddr || a_bindport)
  310.         if (bind (h->sfd, (struct sockaddr *)&sa_in, sizeof(sa_in)) == -1)
  311.         {
  312.         fprintf(stderr, "couldn't bind %s : %d  ", a_bindaddr? a_bindaddr: "0.0.0.0", ntohs(a_bindport));
  313.         perror("");
  314.         if (errno == EACCES)
  315.             exit(1);
  316.         return 0;
  317.     }
  318.     sa_in.sin_addr = h->in_addr;
  319.     sa_in.sin_port = htons (h->port);
  320.  
  321.     if (connect (h->sfd, (struct sockaddr *) &sa_in, sizeof (sa_in)) == -1)
  322.     {
  323.     switch (errno)
  324.     {
  325.     case EINPROGRESS:
  326.     case EWOULDBLOCK:
  327.         break;
  328.     case ETIMEDOUT:
  329.     case ECONNREFUSED:
  330.     case EADDRNOTAVAIL:
  331.         if (f_verbose)
  332.         {
  333.         fprintf(stderr, "%s:%d ", h->name, h->port);
  334.         perror("");
  335.         }
  336.         h->host->attempts++;
  337.         attempt_clear (h);
  338.         return 1;
  339.     default:
  340.         if (!f_quiet)
  341.         {
  342.             fprintf(stderr, "%s:%d ", h->name, h->port);
  343.             perror ("");
  344.         }
  345.         attempt_clear (h);
  346.         return 0;
  347.     }
  348.     }
  349.     h->host->attempts++;
  350.     h->status |= HT_CONNECTING;
  351.     sock_block (h->sfd);
  352.     FD_SET(h->sfd, &set_sel);
  353.     attempts_outstanding++;
  354.     return 1;
  355. }
  356.  
  357. int
  358. gatherer_tcp (h)
  359.   struct htuple_s *h;
  360. {
  361.     struct port_desc_s *pd;
  362.     if (f_minimise)
  363.     printf ("%s\t%d\n", h->name, h->port);
  364.     else
  365.     {
  366.         if ((pd = port_descs[h->port]))
  367.         {
  368.                 printf ("%-30s %-16s %5d/tcp %s\n", h->name, pd->portname, h->port, pd->name);
  369.         while (!f_delete_dupes && !f_minimise && (pd=pd->next))
  370.             printf ("#%-29s %-16s %5d/tcp %s\n", h->name, pd->portname, h->port, pd->name);
  371.         }
  372.         else
  373.         printf ("%-30s %-16s %5d/tcp unassigned\n", h->name, "unknown", h->port);
  374.     }
  375.     h->host->connects++;
  376.     connects++;
  377.     attempt_clear (h);
  378.     return 1;
  379. }
  380.  
  381. bool
  382. gather ()
  383. {
  384.     struct timeval timeout;
  385.     struct htuple_s *h;
  386.     int n;
  387.     int selected;
  388.     time_t tim;
  389.  
  390.     if (!attempts_outstanding) return 1;
  391.     set_sel_r=set_sel_w=set_sel;
  392.     timeout.tv_sec = 0;
  393.     timeout.tv_usec = 250000; /* 1/4 of a second */
  394.  
  395.     selected = select (FD_SETSIZE, &set_sel_r, &set_sel_w, 0, &timeout);
  396.     /* Look for timeouts */
  397.  
  398.     tim = time (NULL);
  399.     for ( n = 0 ; n < a_sock_max; n++ )
  400.     {
  401.       h = &attempt[n];
  402.       if ((h->status & HT_SOCKET) &&
  403.       ((h->sock_start.tv_sec + h->timeout) < tim))
  404.      attempt_clear (h);
  405.     }
  406.  
  407.     switch (selected)
  408.     {
  409.     case -1:
  410.     perror ("select");
  411.     return 0;
  412.     case 0:
  413.     return 1;
  414.     }
  415.     for (n = 0; selected && (n < a_sock_max); n++)
  416.     {
  417.     h = &attempt[n];
  418.     if (h->status & HT_CONNECTING)
  419.     {
  420.         if (FD_ISSET (h->sfd, &set_sel_r) || FD_ISSET (h->sfd, &set_sel_w))
  421.         {
  422.         struct sockaddr_in in;
  423.         int len = sizeof (in);
  424.         selected--;
  425.         /* select() lies occasionaly
  426.                  */
  427.         if (!f_dontgetpeername) /* but solaris2.3 crashes occasionally ;-| */
  428.         {
  429.             if (getpeername (h->sfd, (struct sockaddr *) &in, &len) == 0)
  430.                     gatherer_tcp (h);
  431.             else
  432.                     attempt_clear (h);
  433.         }
  434.         else
  435.                 gatherer_tcp (h);
  436.         }
  437.     }
  438.     }
  439.     return 1;
  440. }
  441.  
  442. bool
  443. add_attempt (add)
  444.   struct htuple_s *add;
  445. {
  446.     struct htuple_s *h;
  447.     static time_t oldtime;
  448.     static int n;
  449.     for (;;)
  450.     {
  451.     for (; n < a_sock_max; n++)
  452.     {
  453.         h = &attempt[n];
  454.         if (!h->status)
  455.         goto foundfree;
  456.     }
  457.     n = 0;
  458.     gather ();
  459.     continue;
  460.       foundfree:
  461.     *h = *add;
  462.     if (!sc_connect (h))
  463.     {
  464.         gather ();
  465.         continue;
  466.     }
  467.     if ((oldtime + 1) < time (NULL))
  468.     {
  469.         oldtime = time (NULL);
  470.         gather ();
  471.     }
  472.     break;
  473.     }
  474.     return 1;
  475. }
  476.  
  477. int
  478. scatter (host, timeout)
  479.   struct hosts_s *host;
  480.   int timeout;
  481. {
  482.     static struct htuple_s add;
  483.     add = ht_initial;
  484.     add.host = host;
  485.     add.name = host->name;
  486.     add.in_addr = host->in_addr;
  487.     add.port = host->port;
  488.     add.timeout = timeout;
  489.     if (f_verbose)
  490.     fprintf (stderr, "attempting port=%d host=%s\n", add.port, add.name);
  491.     add_attempt (&add);
  492.     return 1;
  493. }
  494.  
  495. fvoid
  496. wait_end (t)
  497.   int t;
  498. {
  499.     time_t st;
  500.     st = time (NULL);
  501.     while ((st + t) > time (NULL))
  502.     {
  503.     gather ();
  504.     if (attempts_outstanding<1) break;
  505.     }
  506. }
  507.  
  508. struct in_addr
  509. resolve (name)
  510.   char *name;
  511. {
  512.     static struct in_addr in;
  513.     unsigned long l;
  514.     struct hostent *ent;
  515.     if ((l = inet_addr (name)) != INADDR_NONE)
  516.     {
  517.     in.s_addr = l;
  518.     return in;
  519.     }
  520.     if (!(ent = gethostbyname (name)))
  521.     {
  522.     perror (name);
  523.     in.s_addr = INADDR_NONE;
  524.     return in;
  525.     }
  526.     return *(struct in_addr *) ent->h_addr;
  527. }
  528.  
  529. char *
  530. next_host ()
  531. {
  532.     static char lbuf[512];
  533.     hosts_done++;
  534.     if (a_input)
  535.     {
  536.     int n;
  537. reread:
  538.     if (!fgets (lbuf, sizeof (lbuf), fh_input))
  539.     {
  540.         fclose (fh_input);
  541.             a_input = NULL;
  542.         return next_host();
  543.     }
  544.     if (strchr("# \t\n\r", lbuf[0])) goto reread;
  545.     n = strcspn (lbuf, " \t\n\r");
  546.     if (n)
  547.         lbuf[n] = '\0';
  548.     return lbuf;
  549.     }
  550.     if ( host_n >= Argc )
  551.       return NULL;
  552.  
  553.     return Argv[host_n++];
  554. }
  555.  
  556. bool
  557. host_init (h, name, nocheck)
  558.   struct hosts_s *h;
  559.   char *name;
  560.   bool nocheck;
  561. {
  562.     int n;
  563.     *h=ho_initial;
  564.     h->in_addr = resolve (name);
  565.     if (h->in_addr.s_addr == INADDR_NONE)
  566.     return 0;
  567.     if (!nocheck)
  568.         for (n=0; n<a_sock_max; n++)
  569.        {
  570.         if (hosts[n].name && hosts[n].in_addr.s_addr==h->in_addr.s_addr)
  571.         {
  572.         if (!f_quiet)
  573.             fprintf(stderr, "ip duplication: %s == %s (last host ignored)\n",
  574.                 hosts[n].name, name);
  575.         return 0;
  576.         }
  577.         }
  578.     h->name = (char *) Smalloc (strlen (name) + 1);
  579.     strcpy (h->name, name);
  580.     h->port = a_start;
  581.     h->status = HO_ACTIVE;
  582.     gettimeofday(&(h->time_start), NULL);
  583.     return 1;
  584. }
  585.  
  586. fvoid
  587. host_clear (h)
  588.   struct hosts_s *h;
  589. {
  590.     if (h->name)
  591.     {
  592.         free (h->name);
  593.     }
  594.     *h=ho_initial;
  595. }
  596.  
  597. fvoid
  598. host_stats (h)
  599.   struct hosts_s *h;
  600. {
  601.     struct timeval tv, tv2;
  602.     float t, st;
  603.     gettimeofday(&tv, NULL);
  604.     timeval_subtract(&tv2, &tv, &(h->time_start));
  605.     t = tv2.tv_sec+(float)tv2.tv_usec/1000000.0;
  606.     st = h->time_used.tv_sec+(float)h->time_used.tv_usec/1000000.0;
  607.     fprintf(stderr, "stats: host = %s trys = %d cons = %d time = %.2fs trys/s = %.2f trys/ss = %.2f\n",
  608.     h->name, h->attempts_done, h->connects, t, h->attempts_done/t, h->attempts_done/st);
  609. }
  610.  
  611. fvoid
  612. final_stats()
  613. {
  614.     struct timeval tv, tv2;
  615.     float t;
  616.     gettimeofday(&tv, NULL);
  617.     timeval_subtract(&tv2, &tv, &(time_start));
  618.     t = tv2.tv_sec+(float)tv2.tv_usec/1000000.0;
  619.     fprintf(stderr, "stats: hosts = %d trys = %d cons = %d time = %.2fs trys/s = %.2f\n",
  620.     hosts_done, attempts_done, connects, t, attempts_done/t);
  621. }
  622.  
  623. bool skip_host(h)
  624.   struct hosts_s *h;
  625. {
  626.     if (a_abort && !h->connects && (h->attempts_highest_done >= a_abort)) /* async pain */
  627.     {
  628.     if (h->status & HO_ABORT)
  629.     {
  630.         if ((time(NULL)-h->notice_abort)>a_timeout)
  631.         {
  632.         if (f_verbose)
  633.             fprintf(stderr, "skipping: %s (no connects in %d attempts)\n",
  634.             h->name, h->attempts_done);
  635.         return 1;
  636.         }
  637.     } else
  638.         {
  639.         h->notice_abort=time(NULL);
  640.         h->status|=HO_ABORT;
  641.     }
  642.     }
  643.     return 0;
  644. }
  645.  
  646. int
  647. next_port (h)
  648. struct hosts_s *h;
  649. {
  650.     int n;
  651.     for (n = h->port; ++n <= a_end;)
  652.     {
  653.         if (!f_fast) return n;
  654.     if (++h->portlist_ent>portlist_n) return -1;
  655.         return (portlist[h->portlist_ent-1]);
  656.     }
  657.     return -1;
  658. }
  659.  
  660. fvoid
  661. scan_ports_linear ()
  662. {
  663.     struct hosts_s host;
  664.     char *name;
  665.     while ((name = next_host ()))
  666.     {
  667.     if (!host_init(&host, name, 1)) continue;
  668.     for (;;)
  669.     {
  670.         scatter (&host, a_timeout);
  671.         if (skip_host(&host)) break;
  672.         if ((host.port = next_port(&host))==-1)
  673.         break;
  674.     }
  675.     wait_end (a_timeout);
  676.     if (f_verbose_stats)
  677.         host_stats (&host);
  678.     clear_all ();
  679.     host_clear(&host);
  680.     }
  681. }
  682.  
  683. /* Huristics:
  684.  *  o  fast connections have priority == maximise bandwidth i.e
  685.  *     a port in the hand is worth two in the bush
  686.  *
  687.  *  o  newer hosts have priority == lower ports checked more quickly
  688.  *
  689.  *  o  all hosts eventually get equal "socket time" == despite
  690.  *     priorities let no one host hog the sockets permanently
  691.  *
  692.  *  o  when host usage times are equal (typically on or shortly after
  693.  *     initial startup) distribute hosts<->sockets evenly rather than
  694.  *     play a game of chaotic bifurcatic ping-pong
  695.  */
  696.  
  697. fvoid
  698. scan_ports_paralell ()
  699. {
  700.     int n;
  701.     struct timeval smallest_val;
  702.     int smallest_cnt;
  703.     char *name;
  704.     struct hosts_s *h, *smallest = &hosts[0];
  705.     while (smallest)
  706.     {
  707.     smallest_val.tv_sec=0xfffffff;
  708.     smallest_val.tv_usec=0;
  709.     for (n = 0, smallest_cnt = 0xfffffff, smallest = NULL; n < a_sock_max; n++)
  710.     {
  711.         h = &hosts[n];
  712.  
  713.         if (((h->status & HO_COMPLETING) &&
  714.                  (h->attempts_done == h->attempts)) ||
  715.                 skip_host(h))
  716.         {
  717.         if (f_verbose_stats) host_stats (h);
  718.         host_clear (h);
  719.         }
  720.  
  721.         if (!h->name && ((name = next_host ())))
  722.         if (!host_init (h, name, 0))
  723.         {
  724.             host_clear (h);
  725.             continue;
  726.         }
  727.  
  728.         if (h->name)
  729.         {
  730.         if (((h->time_used.tv_sec < smallest_val.tv_sec) ||
  731.              ((h->time_used.tv_sec == smallest_val.tv_sec) &&
  732.               (h->time_used.tv_usec <= smallest_val.tv_usec))) &&
  733.             (((h->time_used.tv_sec != smallest_val.tv_sec) &&
  734.               (h->time_used.tv_usec != smallest_val.tv_usec)) ||
  735.              (h->attempts < smallest_cnt)))
  736.             {
  737.               smallest_cnt = h->attempts;
  738.             smallest_val = h->time_used;
  739.             smallest = h;
  740.          }
  741.         }
  742.     }
  743.  
  744.     if (smallest)
  745.     {
  746.         if (!(smallest->status & HO_COMPLETING))
  747.         {
  748.         scatter (smallest, a_timeout);
  749.         if ((smallest->port=next_port(smallest))==-1)
  750.                 smallest->status|=HO_COMPLETING;
  751.         }
  752.         else
  753.         gather();
  754.     }
  755.     }
  756. }
  757.  
  758. fvoid
  759. loaddescs ()
  760. {
  761.     FILE *fh;
  762.     char lbuf[1024];
  763.     char desc[256];
  764.     char portname[17];
  765.     unsigned int port;
  766.     char *fn;
  767.     char prot[4];
  768.     prot[3]='\0';
  769.     if (!(fh = fopen ((fn=a_services), "r")) &&
  770.         !(fh = fopen ((fn=LIB_STROBE_SERVICES), "r")) &&
  771.         !(fh = fopen ((fn=ETC_SERVICES), "r")))
  772.     {
  773.     perror (fn);
  774.     exit (1);
  775.     }
  776.     port_descs=(struct port_desc_s **) Smalloc(sizeof(struct port_descs_s *) * 65536);
  777.     memset(port_descs, 0, 65536);
  778.     while (fgets (lbuf, sizeof (lbuf), fh))
  779.     {
  780.     char *p;
  781.     struct port_desc_s *pd, *pdp;
  782.     if (strchr("*# \t\n", lbuf[0])) continue;
  783.     if (!(p = strchr (lbuf, '/'))) continue;
  784.     *p = ' ';
  785.     desc[0]='\0';
  786.     if (sscanf (lbuf, "%16s %u %3s %255[^\r\n]", portname, &port, prot, desc) <3 || strcmp (prot, "tcp") || (port > 65535))
  787.         continue;
  788.     pd = port_descs[port];
  789.     if (!pd)
  790.     {
  791.         portlist = (int *)Srealloc((char *)portlist, ++portlist_n*sizeof(int));
  792.         portlist[portlist_n-1]=port;
  793.     }
  794.     if (!f_minimise)
  795.     {
  796.         pdp = (struct port_desc_s *) Smalloc (sizeof (*pd) + strlen (desc) + 1 + strlen (portname) + 1);
  797.         if (pd)
  798.         {
  799.             for (; pd->next; pd = pd->next);
  800.             pd->next = pdp;
  801.             pd = pd->next;
  802.         } else
  803.         {
  804.             pd = pdp;
  805.             port_descs[port] = pd;
  806.         }
  807.         pd->next = NULL;
  808.         pd->name = (char *) (pd) + sizeof (*pd);
  809.         pd->portname = pd->name + strlen(desc)+1;
  810.         strcpy (pd->name, desc);
  811.         strcpy (pd->portname, portname);
  812.     } else
  813.         port_descs[port] = (struct port_desc_s *)-1;
  814.     }
  815.     if (f_minimise)
  816.         free (port_descs);
  817. }
  818.  
  819. fvoid
  820. usage ()
  821. {
  822.     fprintf (stderr, "\
  823. usage: %8s [options]\n\
  824. \t\t[-v(erbose)]\n\
  825. \t\t[-V(erbose_stats]\n\
  826. \t\t[-m(inimise)]\n\
  827. \t\t[-d(elete_dupes)]\n\
  828. \t\t[-g(etpeername_disable)]\n\
  829. \t\t[-s(tatistics)]\n\
  830. \t\t[-q(uiet)]\n\
  831. \t\t[-o output_file]\n\
  832. \t\t[-b begin_port_n]\n\
  833. \t\t[-e end_port_n]\n\
  834. \t\t[-p single_port_n]\n\
  835. \t\t[-P bind_port_n]\n\
  836. \t\t[-A bind_addr_n]\n\
  837. \t\t[-t timeout_n]\n\
  838. \t\t[-n num_sockets_n]\n\
  839. \t\t[-S services_file]\n\
  840. \t\t[-i hosts_input_file]\n\
  841. \t\t[-l(inear)]\n\
  842. \t\t[-f(ast)]\n\
  843. \t\t[-a abort_after_port_n]\n\
  844. \t\t[-M(ail_author)]\n\
  845. \t\t[host1 [...host_n]]\n", Argv[0]);
  846.     exit (1);
  847. }
  848. int
  849. main (argc, argv)
  850.   int argc;
  851.   char **argv;
  852. {
  853.     int c;
  854.     Argc = argc;
  855.     Argv = argv;
  856.  
  857.     while ((c = getopt (argc, argv, "o:dvVmgb:e:p:P:a:A:t:n:S:i:lfsqM")) != -1)
  858.     switch (c)
  859.     {
  860.     case 'o':
  861.         a_output = optarg;
  862.         break;
  863.     case 'd':
  864.         f_delete_dupes=1;
  865.         break;
  866.     case 'v':
  867.         f_verbose = 1;
  868.         break;
  869.     case 'V':
  870.         f_verbose_stats = 1;
  871.         break;
  872.     case 'm':
  873.         f_minimise = 1;
  874.         break;
  875.     case 'g':
  876.         f_dontgetpeername = 1;
  877.         break;
  878.     case 'b':
  879.         a_start = atoi (optarg);
  880.         break;
  881.     case 'e':
  882.         a_end = atoi (optarg);
  883.         break;
  884.     case 'P':
  885.         a_bindport = htons (atoi (optarg));
  886.         break;
  887.     case 'A':
  888.         a_bindaddr = optarg;
  889.         bindaddr = resolve (a_bindaddr);
  890.         if (bindaddr.s_addr == INADDR_NONE)
  891.         {
  892.             perror(a_bindaddr);
  893.         exit(1);
  894.         }
  895.             break;
  896.     case 'p':
  897.         a_start = a_end = atoi (optarg);
  898.         break;
  899.     case 'a':
  900.         a_abort = atoi (optarg);
  901.         break;
  902.     case 't':
  903.         a_timeout = atoi (optarg);
  904.         break;
  905.     case 'n':
  906.         a_sock_max = atoi (optarg);
  907.         break;
  908.     case 'S':
  909.         a_services = optarg;
  910.         break;
  911.     case 'i':
  912.         a_input = optarg;
  913.         break;
  914.     case 'l':
  915.         f_linear = 1;
  916.         break;
  917.     case 'f':
  918.         f_fast = 1;
  919.         break;
  920.     case 's':
  921.         f_stats = 1;
  922.         break;
  923.         case 'q':
  924.         f_quiet = 1;
  925.         break;
  926.     case 'M':
  927.         fprintf(stderr, "Enter mail to author below. End with ^D or .\n");
  928.         system("mail strobe@suburbia.net");
  929.         break;
  930.     case '?':
  931.     default:
  932.         fprintf (stderr, "unknown option %s\n", argv[optind-1]);
  933.         usage ();
  934.         /* NOT_REACHED */
  935.     }
  936.     host_n = optind;
  937.  
  938.     if (!f_quiet)
  939.         fprintf (stderr, "strobe %s (c) 1995 Julian Assange (proff@suburbia.net).\n", VERSION);
  940.     if (a_input)
  941.     {
  942.         if ( ! strcmp("-",a_input) ) { /* Use stdin as input file */
  943.         fh_input = stdin;
  944.       }
  945.     else {
  946.       if (!(fh_input = fopen (a_input, "r")))
  947.         {
  948.           perror (a_input);
  949.           exit (1);
  950.         }
  951.     }
  952.     } else
  953.     {
  954.       switch ( argc - host_n ) { /* Number of hosts found on command line */
  955.       case 0:
  956.     fh_input = stdin;
  957.     a_input = "stdin"; /* Needed in "next_host()" */
  958.     break;
  959.       case 1:
  960.     f_linear = 1;
  961.     break;
  962.       }
  963.     }
  964.  
  965.     if ((fh_input==stdin) && !f_quiet)
  966.       fprintf (stderr, "Reading host names from stdin...\n");
  967.  
  968.     if (a_output)
  969.     {
  970.         int fd;
  971.         if ((fd=open(a_output, O_WRONLY|O_CREAT|O_TRUNC, 0666))==-1)
  972.     {
  973.         perror(a_output);
  974.         exit(1);
  975.     }
  976.     dup2(fd, 1);
  977.     }
  978.     attempt = (struct htuple_s *) Smalloc (a_sock_max * sizeof (struct htuple_s));
  979.     attempt_init();
  980.     if (!f_linear)
  981.     {
  982.         hosts = (struct hosts_s *) Smalloc (a_sock_max * sizeof (struct hosts_s));
  983.         hosts_init();
  984.     }
  985.     if (!f_minimise || f_fast)
  986.         loaddescs ();
  987.     fdsets_init();
  988.     gettimeofday(&time_start, NULL);
  989.     f_linear ? scan_ports_linear ():
  990.             scan_ports_paralell ();
  991.     if (f_stats || f_verbose_stats)
  992.     final_stats();
  993.     exit (0);
  994. }
  995.