home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume41 / rperf / part02 / rpc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-19  |  21.3 KB  |  881 lines

  1. /**
  2.  * This program may be copied, redistributed in any form,
  3.  * source or binary, and used for any purpose, provided
  4.  * this copyright notice is retained.
  5.  *
  6.  * @(#)rpc.c    3.1 12/15/93 (c) Copyright Brian P. Fitzgerald
  7.  * Rensselaer Polytechnic Institute
  8.  *
  9. **/
  10.  
  11. #include "common.h"
  12. #include "rperf.h"
  13.  
  14. static bool_t   bcst_timo;
  15.  
  16. static struct timeval call_timo = {25, 0};
  17.  
  18. bool_t(*xdr_statsproc[]) () =
  19. {
  20.     xdr_stats,
  21.     xdr_statsswtch,
  22.     xdr_statstime,
  23.     xdr_statsvar,
  24. };
  25.  
  26. char           *emfilehelp[] = {
  27.     "You may be trying to monitor too many hosts at once.",
  28.     "Consider increasing the system per-process hard limit",
  29.     "on open files, or else monitor fewer hosts.",
  30.     "If you are using broadcast mode, try the -b option.",
  31.     0
  32. };
  33.  
  34. char           *doclnt_call_help[] = {
  35.     "",
  36.     "client call debug mode.  key:",
  37.     "m made client\tc called client\t\tv4,v3,v2,v1 version called",
  38.     "- no call made\tM version mismatch\tx drop\t* down",
  39.     "",
  40.     0
  41. };
  42.  
  43. struct data    *dp;        /* link list head */
  44.  
  45. int             if_opackets_fixed = 1;
  46.  
  47. void
  48. destroy_array(a)
  49.     array          *a;
  50. {
  51.     if (a->val) {
  52.     free((char *) a->val);
  53.     a->val = (int *) NULL;
  54.     }
  55. }
  56.  
  57. /**
  58.  * copy n ints from p to a->val
  59. **/
  60. void
  61. copy_to_array(a, p, n)
  62.     array          *a;
  63.     int            *p;
  64.     unsigned int    n;
  65. {
  66.     int             i;
  67.  
  68.     if (n > a->len) {
  69.     (void) fprintf(stderr,
  70.                "copy_to_array: attempt to overwrite end of array\n");
  71.     exit(1);
  72.     }
  73.     if (!p) {
  74.     (void) fprintf(stderr,
  75.                "copy_to_array: no source array\n");
  76.     exit(1);
  77.     }
  78.     if (!a->val) {
  79.     (void) fprintf(stderr,
  80.                "copy_to_array: no destination array\n");
  81.     exit(1);
  82.     }
  83.     for (i = 0; i < n; i++)
  84.     a->val[i] = p[i];
  85.     return;
  86. }
  87.  
  88. /**
  89.  * allocate the value part of an array struct, size n
  90. **/
  91. void
  92. create_array(a, n)
  93.     array          *a;
  94.     unsigned int    n;
  95. {
  96.     a->len = n;
  97.     a->val = (int *) malloc((unsigned) n * sizeof(int));
  98.     if (a->val == NULL) {
  99.     perror("malloc");
  100.     exit(1);
  101.     }
  102.     return;
  103. }
  104.  
  105. /**
  106.  * convert and store the received data
  107. **/
  108. stats_default  *
  109. from_stats(s)
  110.     stats_all      *s;
  111. {
  112.     static stats_default r;
  113.  
  114.     bzero((char *) &r, sizeof(r));
  115.     create_array((array *) & r.cp_time, CPUSTATES);
  116.     copy_to_array((array *) & r.cp_time, s->s1.cp_time, CPUSTATES);
  117.     create_array((array *) & r.dk_xfer, DK_NDRIVE);
  118.     copy_to_array((array *) & r.dk_xfer, s->s1.dk_xfer, DK_NDRIVE);
  119.     r.v_pgpgin = s->s1.v_pgpgin;
  120.     r.v_pgpgout = s->s1.v_pgpgout;
  121.     r.v_pswpin = s->s1.v_pswpin;
  122.     r.v_pswpout = s->s1.v_pswpout;
  123.     r.v_intr = s->s1.v_intr;
  124.     r.if_ipackets = s->s1.if_ipackets;
  125.     r.if_ierrors = s->s1.if_ierrors;
  126.     r.if_opackets = s->s1.if_opackets;
  127.     r.if_oerrors = s->s1.if_oerrors;
  128.     r.if_collisions = s->s1.if_collisions;
  129.     if (gettimeofday((struct timeval *) & r.curtime,
  130.              (struct timezone *) NULL) == -1) {
  131.     perror("gettimeofday");
  132.     exit(1);
  133.     }
  134.     return &r;
  135. }
  136.  
  137. stats_default  *
  138. from_statsswtch(s)
  139.     stats_all      *s;
  140. {
  141.     int             i;
  142.     static stats_default r;
  143.  
  144.     bzero((char *) &r, sizeof(r));
  145.     create_array((array *) & r.cp_time, CPUSTATES);
  146.     copy_to_array((array *) & r.cp_time, s->s2.cp_time, CPUSTATES);
  147.     create_array((array *) & r.dk_xfer, DK_NDRIVE);
  148.     copy_to_array((array *) & r.dk_xfer, s->s2.dk_xfer, DK_NDRIVE);
  149.     r.v_pgpgin = s->s2.v_pgpgin;
  150.     r.v_pgpgout = s->s2.v_pgpgout;
  151.     r.v_pswpin = s->s2.v_pswpin;
  152.     r.v_pswpout = s->s2.v_pswpout;
  153.     r.v_intr = s->s2.v_intr;
  154.     r.if_ipackets = s->s2.if_ipackets;
  155.     r.if_ierrors = s->s2.if_ierrors;
  156.     r.if_opackets = s->s2.if_opackets;
  157.     r.if_oerrors = s->s2.if_oerrors;
  158.     r.if_collisions = s->s2.if_collisions;
  159.     r.v_swtch = s->s2.v_swtch;
  160.     for (i = 0; i < 3; i++)
  161.     r.avenrun[i] = s->s2.avenrun[i];
  162.     r.boottime = s->s2.boottime;
  163.     if (gettimeofday((struct timeval *) & r.curtime,
  164.              (struct timezone *) NULL) == -1) {
  165.     perror("gettimeofday");
  166.     exit(1);
  167.     }
  168.     return &r;
  169. }
  170.  
  171. stats_default  *
  172. from_statstime(s)
  173.     stats_all      *s;
  174. {
  175.     int             i;
  176.     static stats_default r;
  177.  
  178.     bzero((char *) &r, sizeof(r));
  179.     create_array((array *) & r.cp_time, CPUSTATES);
  180.     copy_to_array((array *) & r.cp_time, s->s3.cp_time, CPUSTATES);
  181.     create_array((array *) & r.dk_xfer, DK_NDRIVE);
  182.     copy_to_array((array *) & r.dk_xfer, s->s3.dk_xfer, DK_NDRIVE);
  183.     r.v_pgpgin = s->s3.v_pgpgin;
  184.     r.v_pgpgout = s->s3.v_pgpgout;
  185.     r.v_pswpin = s->s3.v_pswpin;
  186.     r.v_pswpout = s->s3.v_pswpout;
  187.     r.v_intr = s->s3.v_intr;
  188.     r.if_ipackets = s->s3.if_ipackets;
  189.     r.if_ierrors = s->s3.if_ierrors;
  190.     r.if_opackets = s->s3.if_opackets;
  191.     r.if_oerrors = s->s3.if_oerrors;
  192.     r.if_collisions = s->s3.if_collisions;
  193.     r.v_swtch = s->s3.v_swtch;
  194.     for (i = 0; i < 3; i++)
  195.     r.avenrun[i] = s->s3.avenrun[i];
  196.     r.boottime = s->s3.boottime;
  197.     r.curtime = s->s3.curtime;
  198.     return &r;
  199. }
  200.  
  201. stats_default  *
  202. from_statsvar(s)
  203.     stats_all      *s;
  204. {
  205.     int             i;
  206.     static stats_default r;
  207.  
  208.     bzero((char *) &r, sizeof(r));
  209.     create_array((array *) & r.cp_time, s->s4.cp_len);
  210.     copy_to_array((array *) & r.cp_time, s->s4.cp_val, s->s4.cp_len);
  211.     create_array((array *) & r.dk_xfer, s->s4.dk_len);
  212.     copy_to_array((array *) & r.dk_xfer, s->s4.dk_val, s->s4.dk_len);
  213.     r.v_pgpgin = s->s4.v_pgpgin;
  214.     r.v_pgpgout = s->s4.v_pgpgout;
  215.     r.v_pswpin = s->s4.v_pswpin;
  216.     r.v_pswpout = s->s4.v_pswpout;
  217.     r.v_intr = s->s4.v_intr;
  218.     r.if_ipackets = s->s4.if_ipackets;
  219.     r.if_ierrors = s->s4.if_ierrors;
  220.     r.if_opackets = s->s4.if_opackets;
  221.     r.if_oerrors = s->s4.if_oerrors;
  222.     r.if_collisions = s->s4.if_collisions;
  223.     r.v_swtch = s->s4.v_swtch;
  224.     for (i = 0; i < 3; i++)
  225.     r.avenrun[i] = s->s4.avenrun[i];
  226.     r.boottime = s->s4.boottime;
  227.     r.curtime = s->s4.curtime;
  228.     return &r;
  229. }
  230.  
  231. stats_default  *((*stats_convert[]) ()) =
  232. {
  233.     from_stats,
  234.     from_statsswtch,
  235.     from_statstime,
  236.     from_statsvar,
  237. };
  238.  
  239. /**
  240.  * free the cp_time and dk_xfer array in a stats_default struct
  241. **/
  242. void
  243. free_stats(s)
  244.     stats_default  *s;
  245. {
  246.     destroy_array((array *) & s->cp_time);
  247.     destroy_array((array *) & s->dk_xfer);
  248.     return;
  249. }
  250.  
  251. /**
  252.  * save the results in a data structure
  253.  * return 1 if the results were saved
  254.  * return 0 if the results were ignored
  255. **/
  256. int
  257. save_res(d, res)
  258.     struct data    *d;
  259.     stats_default  *res;
  260. {
  261.     if (d->nn == thiscount) {
  262.     free_stats(res);
  263.     return 0;        /* duplicate.  ignore */
  264.     }
  265.     d->no = d->nn;
  266.     d->nn = thiscount;
  267.     if (!d->ok_to_call)
  268.     (void) fprintf(stderr, " %s is back up ", d->host);
  269.     d->ok_to_call = 1;
  270.  
  271.     free_stats(&d->so);
  272.     d->so = d->sn;
  273.     d->sn = *res;
  274.     return 1;
  275. }
  276.  
  277. /**
  278.  * this function may be called after (*dpp)->addr
  279.  * has been filled with a valid in_addr
  280.  * return: 1=success, 0=fail
  281. **/
  282. int
  283. make_client(dpp)
  284.     struct data   **dpp;
  285. {
  286.     int             sock = RPC_ANYSOCK;
  287.     static int      emfilewarned;
  288.     struct sockaddr_in server_addr;
  289.     struct timeval  p_timo;
  290.  
  291.     p_timo.tv_sec = 3;
  292.     p_timo.tv_usec = 0;
  293.  
  294.     server_addr.sin_family = AF_INET;
  295.     server_addr.sin_port = 0;
  296.     server_addr.sin_addr = (*dpp)->addr;
  297.  
  298.     /**
  299.      * clntudp_create only determines whether the
  300.      * program is registered.  It does not actually check
  301.      * whether the host supports the requested version.
  302.      * see the pmap_getport man page.
  303.      **/
  304.     errno = 0;
  305.     (*dpp)->cl = clntudp_create(&server_addr,
  306.                 RSTATPROG,
  307.                 (*dpp)->clnt_vers,
  308.                 p_timo,
  309.                 &sock);
  310.  
  311.     if ((*dpp)->cl == NULL) {
  312.     if (rpc_createerr.cf_stat == RPC_SYSTEMERROR
  313.         && rpc_createerr.cf_error.re_errno == EMFILE) {
  314.         if (!emfilewarned) {
  315.         (void) fprintf(stderr, "Can't contact rstatd on %s.\n",
  316.                    (*dpp)->host);
  317.         (void) clnt_pcreateerror("clntudp_create");
  318.         (void) fprintf(stderr, "Open file descriptor limit now %d\n",
  319.                    set_max_nofiles());
  320.         msg(emfilehelp, stderr);
  321.         emfilewarned = 1;
  322.         }
  323.     } else {
  324.         (void) fprintf(stderr, "Can't contact rstatd on %s.  ",
  325.                (*dpp)->host);
  326.         (void) clnt_pcreateerror("clntudp_create");
  327.     }
  328.     return 0;
  329.     }
  330.     if (dbg_lvl >= 2) {
  331.     (void) putc('m', stderr);
  332.     (void) fflush(stderr);
  333.     }
  334.     return 1;
  335. }
  336.  
  337. /**
  338.  * for each host on the linked list that still needs data:
  339.  * loop over the rpc prog versions,
  340.  *    starting with the highest known version,
  341.  *    or highest previously successful version
  342.  *        make a client, if necessary
  343.  *        call the client
  344.  **/
  345. void
  346. doclnt_calls(vers_max)
  347.     u_long          vers_max;
  348. {
  349.     u_long          vers;
  350.     int             good = 0;
  351.     int             bad = 0;
  352.     static enum clnt_stat clnt_stat;
  353.     stats_default  *sn;
  354.     struct data   **dpp;
  355.     stats_all       resbuf;
  356.  
  357.     if (dbg_lvl >= 2)
  358.     msg(doclnt_call_help, stderr);
  359.  
  360.     for (dpp = &dp; *dpp;) {
  361.     if (dbg_lvl >= 2)
  362.         (void) fprintf(stderr, "%s\t%s\t",
  363.                inet_ntoa((*dpp)->addr), (*dpp)->host);
  364.     if ((*dpp)->nn == thiscount) {
  365.         dpp = &(*dpp)->datap;
  366.         if (dbg_lvl >= 2) {
  367.         (void) fputs("-\n", stderr);
  368.         }
  369.         continue;        /* already have data */
  370.     }
  371.     if (!(*dpp)->ok_to_call) {
  372.         dpp = &(*dpp)->datap;
  373.         if (dbg_lvl >= 2) {
  374.         (void) fputs("*\n", stderr);
  375.         }
  376.         continue;        /* probably down */
  377.     }
  378.     if (!(*dpp)->clnt_vers)
  379.         (*dpp)->clnt_vers = vers_max;    /* try first */
  380.  
  381.     for (vers = (*dpp)->clnt_vers; vers > 0; vers--) {
  382.         (*dpp)->clnt_vers = vers;
  383.         if (!(*dpp)->cl)
  384.         if (!make_client(dpp)) {
  385.             (*dpp)->ok_to_call = 0;
  386.             bad++;
  387.             break;    /* vers */
  388.         }
  389.         if (dbg_lvl >= 2) {
  390.         (void) fprintf(stderr, "v%d", vers);
  391.         (void) fflush(stderr);
  392.         }
  393.         bzero((char *) &resbuf, sizeof(resbuf));
  394.         clnt_stat = clnt_call((*dpp)->cl,
  395.                   RSTATPROC_STATS,
  396.                   xdr_void,
  397.                   NULL,
  398.                   XDR_STATSPROC((*dpp)->clnt_vers),
  399.                   (char *) &resbuf,
  400.                   call_timo);
  401.         if (clnt_stat == RPC_SUCCESS) {
  402.         sn = STATS_CONVERT((*dpp)->clnt_vers) (&resbuf);
  403.         /**
  404.          * 11/3/93 I have checked that
  405.          * xdr_free is needed here, so don't delete it
  406.         **/
  407.         xdr_free(XDR_STATSPROC((*dpp)->clnt_vers), (char *) &resbuf);
  408.         (void) save_res(*dpp, sn);
  409.  
  410.         if (!(*dpp)->no && !if_opackets_fixed && dbg_lvl >= 1) {
  411.             (void) fprintf(stderr,
  412.              "%s: rpc.rstatd vers %d does not report if_opackets\n",
  413.                    (*dpp)->host, (*dpp)->clnt_vers);
  414.         }
  415.         if_opackets_fixed = 1;
  416.  
  417.         if (dbg_lvl >= 2) {
  418.             (void) fputs("c\n", stderr);
  419.         }
  420.         good++;
  421.         dpp = &(*dpp)->datap;
  422.         break;        /* vers */
  423.         }
  424.         xdr_free(XDR_STATSPROC((*dpp)->clnt_vers), (char *) &resbuf);
  425.         if (clnt_stat == RPC_PROGVERSMISMATCH && vers > 1) {
  426.         if (dbg_lvl >= 2) {
  427.             (void) fputs("M ", stderr);
  428.             (void) fflush(stderr);
  429.         }
  430.         clnt_destroy((*dpp)->cl);
  431.         (*dpp)->cl = NULL;
  432.         continue;    /* vers-- */
  433.         }
  434.         (void) fprintf(stderr, "clnt_call: %s %s\n",
  435.                (*dpp)->host, clnt_sperrno(clnt_stat));
  436.         (*dpp)->ok_to_call = 0;
  437.         bad++;
  438.         break;        /* vers */
  439.     }            /* for(vers ... */
  440.     }                /* for dpp */
  441.  
  442.     if (dbg_lvl >= 1) {
  443.     (void) fprintf(stderr, "done clnt calls good=%d bad=%d\n", good, bad);
  444.     }
  445.     if (mode == MODE_CALL && !good) {
  446.     if (nhosts > 1) {
  447.         (void) fprintf(stderr, "None of the hosts replied.  Quitting.\n");
  448.     } else {
  449.         dpp = &dp;
  450.         (void) fprintf(stderr, "%s did not reply.  Quitting.\n", (*dpp)->host);
  451.     }
  452.     exit(1);
  453.     }
  454.     return;
  455. }
  456.  
  457. /**
  458.  * create a new data structure
  459. **/
  460. struct data    *
  461. new_host(addr, hostname)
  462.     struct in_addr *addr;
  463.     char           *hostname;
  464. {
  465.     struct data    *newdpp;
  466.  
  467.     newdpp = (struct data *) calloc(1, sizeof(struct data));
  468.     if (newdpp == NULL) {
  469.     perror("calloc");
  470.     exit(1);
  471.     }
  472.     newdpp->addr = *addr;
  473.     newdpp->host = strdup(hostname);
  474.     if (!newdpp->host) {
  475.     perror("strdup");
  476.     exit(1);
  477.     }
  478.     newdpp->host_dup = strdup(hostname);
  479.     if (!newdpp->host_dup) {
  480.     perror("strdup");
  481.     exit(1);
  482.     }
  483.     newdpp->ok_to_call = 1;
  484.     /**
  485.      * assume cp_time is cumulative since boot time
  486.      * until we find out otherwise
  487.     **/
  488.     newdpp->cp_kind = CP_TIME_CUM;
  489.     nhosts++;
  490.     if (mode == MODE_BCST) {
  491.     (void) putc('+', stderr);
  492.     (void) fflush(stderr);
  493.     }
  494.     return newdpp;
  495. }
  496.  
  497. void
  498. dump_hostent(entry)
  499.     struct hostent *entry;
  500. {
  501.     char          **app;
  502.     struct in_addr  in_addr;
  503.  
  504.     (void) fprintf(stderr, "Official name:\t%s\n", entry->h_name);
  505.     for (app = entry->h_aliases; *app; app++)
  506.     (void) fprintf(stderr, "Alias:\t\t%s\n", *app);
  507.  
  508.     for (app = entry->h_addr_list; *app; app++) {
  509.     bcopy(*app, (char *) &in_addr.s_addr, entry->h_length);
  510.     (void) fprintf(stderr, "Host address:\t%s\n", inet_ntoa(in_addr));
  511.     }
  512. }
  513.  
  514. void
  515. insert_dp(newdp)
  516.     struct data    *newdp;
  517. {
  518.     struct data   **dpp;
  519.     struct data    *tdp;
  520.  
  521.     tdp = NULL;
  522.     for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  523.     if (newdp->addr.s_addr == (*dpp)->addr.s_addr) {
  524.         /* already on the list */
  525.         (void) fprintf(stderr,
  526.                "This can't happen! %s already on list\n",
  527.                inet_ntoa(newdp->addr));
  528.         exit(1);
  529.     }
  530.     if (opts & O_SHOST ? strcmp(newdp->host, (*dpp)->host) < 0
  531.         : ntohl(newdp->addr.s_addr) < ntohl((*dpp)->addr.s_addr)) {
  532.         /* insert into list */
  533.         tdp = *dpp;
  534.         break;        /* break => insert into list */
  535.     }
  536.     }                /* fall-through => append to list */
  537.     *dpp = newdp;
  538.     (*dpp)->datap = tdp;
  539. }
  540.  
  541. void
  542. enter_item(itemkey, addr, datap)
  543.     char           *itemkey;
  544.     struct in_addr  addr;
  545.     struct data    *datap;
  546. {
  547.     hash_info      *hip;
  548.     ENTRY           item;
  549.  
  550.     /*
  551.      * caution: do not use inet_ntoa() in this routine
  552.      */
  553.  
  554.     hip = (hash_info *) malloc(sizeof(hash_info));
  555.     item.key = strdup(itemkey);
  556.     if (!item.key) {
  557.     perror("strdup");
  558.     exit(1);
  559.     }
  560.     hip->ident_addr = addr;
  561.     hip->datap = datap;
  562.     item.data = (char *) hip;
  563.     /* put name into table */
  564.     if (!hsearch(item, ENTER)) {
  565.     (void) fprintf(stderr, "Hash table full.\n");
  566.     exit(1);
  567.     }
  568.     if (dbg_lvl >= 2)
  569.     (void) fprintf(stderr, "ENTER %s. hip: ident_addr.s_addr=0x%08x datap=0x%08x\n",
  570.            itemkey, ntohl(hip->ident_addr.s_addr), (u_long) hip->datap);
  571. }
  572.  
  573. /**
  574.  * handle each reply to the broadcast
  575.  * return FALSE to permit more broadcasting
  576.  * return TRUE to terminate broadcasting (after alarm has timed out)
  577.  *
  578.  * my profuse thanks Joe Beauchamp (JRB@CSI.compuserve.com)
  579.  * for patiently assisting me with debugging this routine.
  580.  *
  581. **/
  582. /**
  583.  * You are about to enter ...
  584. **/
  585. bool_t
  586. each_result(resp, raddr, version)
  587.     stats_all      *resp;
  588.     struct sockaddr_in *raddr;
  589.     u_long          version;
  590. {
  591.     char           *hostname;
  592.     char           *dotquad1;
  593.     struct data    *resdp;
  594.     stats_default  *sn;
  595.     ENTRY          *found_item1;
  596.     hash_info      *fip;
  597.     struct hostent *host_entry;
  598.     char          **app;
  599.     struct in_addr  in_tmp;
  600.     ENTRY           item;
  601.  
  602.     /**
  603.                    *         *        *      *    *
  604.      *        *       *        *       *       *
  605.                        ... the coredump zone    *
  606.      *         *    *        *          *
  607.                 *        *        *        *
  608.     **/
  609.  
  610.     /**
  611.      * use strdup for dotquad1 because inet_ntoa uses static storage,
  612.      * which is overwritten each call
  613.      *
  614.     **/
  615.     dotquad1 = strdup(inet_ntoa(raddr->sin_addr));
  616.     if (!dotquad1) {
  617.     perror("strdup");
  618.     exit(1);
  619.     }
  620.     item.key = dotquad1;
  621.     found_item1 = hsearch(item, FIND);
  622.     if (found_item1) {        /* found_item1 */
  623.     /* already on the list */
  624.     fip = (hash_info *) found_item1->data;
  625.     in_tmp = fip->ident_addr;
  626.     if (in_tmp.s_addr) {
  627.         char           *dotquad2;
  628.         ENTRY          *found_item2;
  629.         /* machine has more than one network interface */
  630.         dotquad2 = inet_ntoa(in_tmp);
  631.         item.key = dotquad2;
  632.         found_item2 = hsearch(item, FIND);
  633.         if (!found_item2) {
  634.         (void) fprintf(stderr,
  635.                    "This can't happen! %s not in hash table\n",
  636.                    dotquad2);
  637.         exit(1);
  638.         }
  639.         fip = (hash_info *) found_item2->data;
  640.     }            /* in_tmp.s_addr */
  641.     resdp = fip->datap;
  642.     (void) putc('.', stderr);
  643.     (void) fflush(stderr);
  644.     } else {            /* ! found_item1 */
  645.     if (opts & O_NHOST) {
  646.         resdp = new_host(&raddr->sin_addr, dotquad1);
  647.         insert_dp(resdp);
  648.         in_tmp.s_addr = 0;
  649.         enter_item(dotquad1, in_tmp, resdp);
  650.     } else {        /* !opts & O_NHOST */
  651.         ENTRY          *found_item3;
  652.         host_entry = gethostbyaddr((char *) &raddr->sin_addr, 4, AF_INET);
  653.         if (host_entry) {
  654.         if (dbg_lvl >= 2)
  655.             dump_hostent(host_entry);
  656.  
  657.         hostname = host_entry->h_name;
  658.         if (!hostname) {
  659.             (void) fprintf(stderr,
  660.                    "gethostbyaddr: null hostname %s\n",
  661.                    dotquad1);
  662.             exit(1);
  663.         }
  664.         item.key = hostname;
  665.         } else {        /* !host_entry */
  666.         hostname = (char *) NULL;
  667.         if (dbg_lvl >= 1)
  668.             (void) fprintf(stderr,
  669.                    "gethostbyaddr failed %s\n", dotquad1);
  670.         item.key = dotquad1;
  671.         }            /* !host_entry */
  672.         found_item3 = hsearch(item, FIND);
  673.         if (found_item3) {
  674.         char           *dotquad2;
  675.         ENTRY          *found_item4;
  676.         fip = (hash_info *) found_item3->data;
  677.         in_tmp = fip->ident_addr;
  678.         enter_item(dotquad1, in_tmp, (struct data *) NULL);
  679.  
  680.         if (dbg_lvl >= 1)
  681.             (void) fprintf(stderr,
  682.                "duplicate reply from %s received on interface %s\n",
  683.                    hostname ? hostname : "(unknown)", dotquad1);
  684.         dotquad2 = inet_ntoa(in_tmp);
  685.         item.key = dotquad2;
  686.         found_item4 = hsearch(item, FIND);
  687.         if (!found_item4) {
  688.             (void) fprintf(stderr,
  689.                 "This can't happen! %s not in hash table\n",
  690.                    dotquad2);
  691.             exit(1);
  692.         }
  693.         fip = (hash_info *) found_item4->data;
  694.         resdp = fip->datap;
  695.         (void) putc('.', stderr);
  696.         (void) fflush(stderr);
  697.         } else {        /* ! found_item2 */
  698.         resdp = (struct data *) NULL;
  699.         if (host_entry) {
  700.             enter_item(hostname, raddr->sin_addr, (struct data *) NULL);
  701.             for (app = host_entry->h_addr_list; *app; app++) {
  702.             bcopy(*app, (char *) &in_tmp, host_entry->h_length);
  703.             if (in_tmp.s_addr == raddr->sin_addr.s_addr) {
  704.                 /* this is the normal branch */
  705.                 resdp = new_host(&raddr->sin_addr, hostname);
  706.                 insert_dp(resdp);
  707.                 in_tmp.s_addr = 0;
  708.                 enter_item(dotquad1, in_tmp, resdp);
  709.             } else {/* other addresses */
  710.                 /* save other addresses found in host table */
  711.                 char           *dotquad2;
  712.                 dotquad2 = inet_ntoa(in_tmp);
  713.                 if (dbg_lvl >= 1)
  714.                 (void) fprintf(stderr,
  715.                       "Saving address %s for host %s\n",
  716.                            dotquad2, hostname);
  717.                 enter_item(dotquad2, raddr->sin_addr,
  718.                        (struct data *) NULL);
  719.             }    /* other addresses */
  720.             }        /* for app */
  721.         } else {    /* !host_entry */
  722.             resdp = new_host(&raddr->sin_addr, dotquad1);
  723.             insert_dp(resdp);
  724.             in_tmp.s_addr = 0;
  725.             enter_item(dotquad1, in_tmp, resdp);
  726.         }        /* !host_entry */
  727.         }            /* ! found_item2 */
  728.     }            /* !opts & O_NHOST */
  729.     }                /* ! found_item1 */
  730.  
  731.     sn = STATS_CONVERT(version) (resp);
  732.     /**
  733.      * 11/3/93 I have checked that no memory leak occurs if I do not use
  734.      * xdr_free here. (Leave this comment here, so I don't forget about it.)
  735.     **/
  736.     if (!resdp) {
  737.     (void) fprintf(stderr,
  738.                "This shouldn't happen %s resdp = NULL\n", dotquad1);
  739.     exit(1);
  740.     }
  741.     if (save_res(resdp, sn))
  742.     resdp->bcst_vers = version;
  743.  
  744.     if (!resdp->no && !if_opackets_fixed && dbg_lvl >= 1) {
  745.     (void) fprintf(stderr,
  746.              "%s: rpc.rstatd vers %d does not report if_opackets\n",
  747.                resdp->host, resdp->bcst_vers);
  748.     }
  749.     if_opackets_fixed = 1;
  750.     free(dotquad1);
  751.  
  752.     return bcst_timo;
  753. }
  754.  
  755. bool_t
  756. each_result_orig(resp, raddr)
  757.     stats_all      *resp;
  758.     struct sockaddr_in *raddr;
  759. {
  760.     return each_result(resp, raddr, RSTATVERS_ORIG);
  761. }
  762.  
  763. bool_t
  764. each_result_swtch(resp, raddr)
  765.     stats_all      *resp;
  766.     struct sockaddr_in *raddr;
  767. {
  768.     return each_result(resp, raddr, RSTATVERS_SWTCH);
  769. }
  770.  
  771. bool_t
  772. each_result_time(resp, raddr)
  773.     stats_all      *resp;
  774.     struct sockaddr_in *raddr;
  775. {
  776.     return each_result(resp, raddr, RSTATVERS_TIME);
  777. }
  778.  
  779. bool_t
  780. each_result_var(resp, raddr)
  781.     stats_all      *resp;
  782.     struct sockaddr_in *raddr;
  783. {
  784.     return each_result(resp, raddr, RSTATVERS_VAR);
  785. }
  786.  
  787. bool_t(*each_result_vers[]) () =
  788. {
  789.     each_result_orig,
  790.     each_result_swtch,
  791.     each_result_time,
  792.     each_result_var,
  793. };
  794.  
  795. /**
  796.  * force end of broadcasting
  797. **/
  798. RETSIGTYPE
  799. bcst_done()
  800. {
  801.     bcst_timo = TRUE;
  802. }
  803.  
  804. /**
  805.  * calculate how long the alarm should be to get
  806.  * the desired interval
  807.  * example:  desire 30 sec.  use alarm(14)
  808. **/
  809. unsigned
  810. get_bcst_alarm(interval)
  811.     unsigned        interval;
  812. {
  813.     int             j, h = 0;
  814.  
  815.     if (interval <= 4)
  816.     return 1;
  817.     for (j = 4; j <= 64; j *= 2) {
  818.     h += j;
  819.     if (interval <= h)
  820.         break;
  821.     }
  822.     j /= 2;
  823.     return Min(h - j, interval) - j;
  824.     /* max is 60 */
  825. }
  826.  
  827. void
  828. do_broadcast(vers_max, interval)
  829.     u_long          vers_max;
  830.     unsigned        interval;    /* desired broadcast interval.  92 max */
  831. {
  832.     u_long          vers;
  833.     static u_long   vers_max_ok;
  834.     static enum clnt_stat clnt_stat;
  835.     stats_all       resbuf;
  836.  
  837.     if (!vers_max_ok)
  838.     vers_max_ok = vers_max;
  839.  
  840.     (void) fputs("broadcasting ", stderr);
  841.     for (vers = vers_max_ok; vers >= Min(vers_max_ok, RSTATVERS_TIME); vers--) {
  842.  
  843.     if (dbg_lvl >= 1)
  844.         (void) fprintf(stderr, " vers %d: ", vers);
  845.  
  846.     (void) signal(SIGALRM, bcst_done);
  847.     (void) alarm(get_bcst_alarm(interval));
  848.  
  849.     bcst_timo = FALSE;
  850.     (void) fflush(stderr);
  851.     bzero((char *) &resbuf, sizeof resbuf);
  852.     clnt_stat = clnt_broadcast(RSTATPROG,
  853.                    vers,
  854.                    RSTATPROC_STATS,
  855.                    xdr_void,
  856.                    (char *) NULL,
  857.                    XDR_STATSPROC(vers),
  858.                    (char *) &resbuf,
  859.                    EACH_RESULT(vers));
  860.     /**
  861.      * resultproc_t each_result in Solaris-2 (thanks
  862.      * cmc@apus.srg-ssr.ch (Colin M. Clark))
  863.     **/
  864.  
  865.     if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
  866.         (void) fprintf(stderr, "\nclnt_broadcast: %s\n",
  867.                clnt_sperrno(clnt_stat));
  868.         exit(1);
  869.     }
  870.     if (!nhosts) {
  871.         (void) fprintf(stderr,
  872.         "\nNo hosts found with rstatd version %d on this network\n",
  873.                vers);
  874.         vers_max_ok = vers - 1;
  875.         if (!vers_max_ok)
  876.         exit(1);
  877.     }
  878.     }
  879.     (void) putc('\n', stderr);
  880. }
  881.