home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / XARCHIE2.TAR / dirsend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-07  |  28.8 KB  |  1,053 lines

  1. /*
  2.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3.  *
  4.  * For copying and distribution information, please see the file
  5.  * <copyright.h>.
  6.  *
  7.  * v1.2.3 - 11/04/91 (bcn) - removed host comparison and replaced with check
  8.                   for connection id (undoes effect of v1.2.2.).
  9.  * v1.2.2 - 11/02/91 (gf)  - removed extra inet_ntoa() calls and stuff for
  10.                  multi-interface nets (lmjm@doc.imperial.ac.uk)
  11.  * v1.2.1 - 10/20/91 (gf)  - asynch implementation
  12.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  13.  * v1.1.2 - 08/30/91 (bpk) - added VMS support
  14.  * v1.1.1 - 08/29/91 (bcn) - changed backoff handling
  15.  * v1.1.0 - 08/13/91 (gf)  - added XArchie status calls
  16.  *
  17.  * gf: 20 Oct 1991:
  18.  *  Broken into pieces so that under X dirsend() doesn't block in select()
  19.  *  but rather uses Xt calls to allow continued event processing. If
  20.  *  XARCHIE is not defined, can still be used since processEvent() will
  21.  *  use select() in this case.
  22.  *
  23.  * lmjm: 2 Nov 1991:
  24.  *  I've found that dirsend.c checks to see if the ip address of the response
  25.  *  is the same as the ip address that it sent to.  With multiple interfaces
  26.  *  this is not always true and a valid response is rejected.
  27.  */
  28.  
  29. #include <copyright.h>
  30. #include <stdio.h>
  31. #include <errno.h>
  32.  
  33. #ifdef VMS
  34. # ifdef WALLONGONG
  35. #  include "twg$tcp:[netdist.include]netdb.h"
  36. # else /* Multinet */
  37. #  include "multinet_root:[multinet.include]netdb.h"
  38. # endif
  39. # include <vms.h>
  40. #else /* not VMS */
  41. # ifdef NEED_TIME_H
  42. #  include <time.h>
  43. # else
  44. #  include <sys/time.h>
  45. # endif
  46. # if defined(USG) || defined(UTS) || defined(_AIX)
  47. #  include <string.h>
  48. # else
  49. #  include <strings.h>
  50. # endif
  51. # include <netdb.h>
  52. # include <sys/types.h>
  53. # include <pmachine.h>
  54. # include <sys/socket.h>
  55. # ifdef NEED_SELECT_H
  56. #  include <sys/select.h>
  57. # endif /* NEED_SELECT_H */
  58. #endif /* !VMS */
  59. #include <netinet/in.h>
  60. #include <arpa/inet.h>
  61.  
  62. #include <pfs.h>
  63. #include <pprot.h>
  64. #include <pcompat.h>
  65. #include <perrno.h>
  66.  
  67. /* Gnu C currently fails to pass structures on Sparcs properly.  This directly
  68.    effects the calling of inet_ntoa().  To get around it, we use this hack;
  69.    take the address of what's being called to inet_ntoa, so it gets it
  70.    properly.  This won't be necessary with gcc 2.0.  */
  71. #if defined(sun) && defined(__GNUC__)
  72. # define SUN_GNU_FIX &
  73. #else
  74. # define SUN_GNU_FIX
  75. #endif
  76.  
  77. static int notprived = 0;
  78. extern int errno;
  79. extern int perrno;
  80. extern int rdgram_priority;
  81. #ifdef DEBUG
  82. extern int pfs_debug;
  83. #endif
  84. extern int pfs_disable_flag;
  85.  
  86. char    *nlsindex();
  87.  
  88. #define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  89.  
  90. static int        dir_udp_port = 0;    /* Remote UDP port number */
  91.  
  92. static unsigned short    next_conn_id = 0;
  93.  
  94. #ifdef XARCHIE
  95. int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  96. int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  97. #else /* !XARCHIE */
  98. static int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  99. static int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  100. #endif /* XARCHIE */
  101.  
  102. /* These were parameters to dirsend() */
  103. static PTEXT pkt;
  104. static char *hostname;
  105. static struct sockaddr_in *hostaddr;
  106.  
  107. /* These were locals in dirsend(). Note that the initializations here
  108.  * are really meaningless since we have to redo them for each call to
  109.  * dirsend() since they were formerly automatically initialized.
  110.  */
  111. static PTEXT        first = NULL;    /* First returned packet     */
  112. static PTEXT        next;        /* The one we are waiting for      */
  113. static PTEXT        vtmp;           /* For reorganizing linked list  */
  114. static PTEXT        comp_thru;    /* We have all packets though    */
  115. static int        lp = -1;    /* Opened UDP port             */
  116. static int        hdr_len;    /* Header Length                 */
  117. static int        nd_pkts;    /* Number of packets we want     */
  118. static int        no_pkts;    /* Number of packets we have     */
  119. static int        pkt_cid;        /* Packet connection identifier  */
  120. static unsigned short    this_conn_id;    /* Connection ID we are using    */
  121. static unsigned short    recvd_thru;    /* Received through              */
  122. static short        priority;    /* Priority for request          */
  123. static short        one = 0;    /* Pointer to value 1            */
  124. static short        zero = 0;    /* Pointer to value 0         */
  125. static char        *seqtxt;    /* Pointer to text w/ sequence # */
  126. static struct sockaddr_in  us;        /* Our address                   */
  127. static struct sockaddr_in  to;        /* Address to send query     */
  128. static struct sockaddr_in  from;    /* Reply received from         */
  129. static int        from_sz;    /* Size of from structure     */
  130. static struct hostent    *host;        /* Host info from gethostbyname  */
  131. static long        newhostaddr;    /* New host address from *host   */
  132. static int        req_udp_port=0; /* Requested port (optional)     */
  133. static char        *openparen;    /* Delimits port in name         */
  134. static char        hostnoport[500];/* Host name without port        */
  135. static int        ns;        /* Number of bytes actually sent */
  136. static int        nr;        /* Number of bytes received      */
  137. static fd_set        readfds;    /* Used for select         */
  138. static int        tmp;
  139. static char        *ctlptr;    /* Pointer to control field      */
  140. static short        stmp;        /* Temp short for conversions    */
  141. static int        backoff;    /* Server requested backoff      */
  142. static unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  143. static unsigned char    rdflag12;    /* Second byte of flags (int)    */
  144. static int        scpflag = 0;    /* Set if any sequencd cont pkts */
  145. static int        ackpend = 0;    /* Acknowledgement pending      */
  146. static int        gaps = 0;    /* Gaps present in recvd pkts   */
  147. static struct timeval    timeout;    /* Time to wait for response    */
  148. static struct timeval    ackwait;    /* Time to wait before acking   */
  149. static struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  150. static struct timeval    *selwait;    /* Time to wait for select      */
  151. static int        retries;    /* was = client_dirsrv_retry    */
  152. char   to_hostname[512];        /* lmjm: saves inet_ntoa() str  */
  153.  
  154. /* These are added so dirsend() "blocks" properly */
  155. static PTEXT dirsendReturn;
  156. static int dirsendDone;
  157.  
  158. /* And here are the values for dirsendDone */
  159. #define DSRET_DONE        1
  160. #define DSRET_SEND_ERROR    -1
  161. #define DSRET_RECV_ERROR    -2
  162. #define DSRET_SELECT_ERROR    -3
  163. #define DSRET_TIMEOUT        -4
  164. #define DSRET_ABORTED        -5
  165.  
  166. /* New procedures to break up dirsend() */
  167. static int initDirsend();
  168. static void retryDirsend(), keepWaitingDirsend();
  169. static void timeoutProc();
  170. static void readProc();
  171.  
  172. /* Wrappers around X calls to allow non-X usage */
  173. static void addInputSource(), removeInputSource();
  174. static void addTimeOut(), removeTimeOut();
  175. static void processEvent();
  176.  
  177. /* Extra stuff for the asynchronous X version of dirsend() */
  178. #ifdef XARCHIE
  179. #include <X11/Intrinsic.h>
  180. extern XtAppContext appContext;
  181. #else
  182. typedef char *XtPointer;
  183. typedef char *XtInputId;
  184. typedef char *XtIntervalId;
  185. #endif
  186. static XtInputId inputId;
  187. static XtIntervalId timerId = (XtIntervalId)0;
  188.  
  189. /*
  190.  * dirsend - send packet and receive response
  191.  *
  192.  *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  193.  *   and a pointer to a host address.  It then sends the supplied
  194.  *   packet off to the directory server on the specified host.  If
  195.  *   hostaddr points to a valid address, that address is used.  Otherwise,
  196.  *   the hostname is looked up to obtain the address.  If hostaddr is a
  197.  *   non-null pointer to a 0 address, then the address will be replaced
  198.  *   with that found in the hostname lookup.
  199.  *
  200.  *   DIRSEND will wait for a response and retry an appropriate
  201.  *   number of times as defined by timeout and retries (both static
  202.  *   variables).  It will collect however many packets form the reply, and
  203.  *   return them in a structure (or structures) of type PTEXT.
  204.  *
  205.  *   DIRSEND will free the packet that it is presented as an argument.
  206.  *   The packet is freed even if dirsend fails.
  207.  */
  208. PTEXT
  209. dirsend(pkt_p,hostname_p,hostaddr_p)
  210.     PTEXT pkt_p;
  211.     char *hostname_p;
  212.     struct sockaddr_in    *hostaddr_p;
  213. {
  214.     /* copy parameters to globals since other routines use them */
  215.     pkt = pkt_p;
  216.     hostname = hostname_p;
  217.     hostaddr = hostaddr_p;
  218.     /* Do the initializations of formerly auto variables */
  219.     first = NULL;
  220.     lp = -1;
  221.     one = 0;
  222.     zero = 0;
  223.     req_udp_port=0;
  224.     scpflag = 0;
  225.     ackpend = 0;
  226.     gaps = 0;
  227.     retries = client_dirsrv_retry;
  228.  
  229.     if (initDirsend() < 0)
  230.     return(NULL);
  231.     addInputSource();
  232.     /* set the first timeout */
  233.     retryDirsend();
  234.  
  235.     dirsendReturn = NULL;
  236.     dirsendDone = 0;
  237.     /* Until one of the callbacks says to return, keep processing events */
  238.     while (!dirsendDone)
  239.     processEvent();
  240.     /* Clean up event generators */
  241.     removeTimeOut();
  242.     removeInputSource();
  243. #ifdef XARCHIE
  244.     /* Set status if needed (has to be outside of loop or X will crash) */
  245.     switch (dirsendDone) {
  246.     case DSRET_SEND_ERROR: status0("Send error"); break;
  247.     case DSRET_RECV_ERROR: status0("Recv error"); break;
  248.         case DSRET_TIMEOUT:
  249.         status1("Connection to %s timed out",to_hostname);
  250.         break;
  251.         case DSRET_ABORTED: status0("Aborted"); break;
  252.     }
  253. #endif
  254.     /* Return whatever we're supposed to */
  255.     return(dirsendReturn);
  256. }
  257.  
  258.  
  259. /*    -    -    -    -    -    -    -    -    */
  260. /* This function does all the initialization that used to be done at the
  261.  * start of dirsend(), including opening the socket descriptor "lp". It
  262.  * returns the descriptor if successful, otherwise -1 to indicate that
  263.  * dirsend() should return NULL immediately.
  264.  */
  265. static int
  266. initDirsend()
  267. {
  268. #ifdef XARCHIE
  269.     status0("Initializing");
  270. #endif
  271.  
  272.     if(one == 0) one = htons((short) 1);
  273.  
  274.     priority = htons(rdgram_priority);
  275.  
  276.     timeout.tv_sec = client_dirsrv_timeout;
  277.     timeout.tv_usec = 0;
  278.  
  279.     ackwait.tv_sec = 0;
  280.     ackwait.tv_usec = 500000;
  281.  
  282.     gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  283.     gapwait.tv_usec = 0;
  284.  
  285.     comp_thru = NULL;
  286.     perrno = 0;
  287.     nd_pkts = 0;
  288.     no_pkts = 0;
  289.     pkt_cid = 0;
  290.  
  291.     /* Find first connection ID */
  292.     if(next_conn_id == 0) {
  293.     srand(getpid()+time(0));
  294.     next_conn_id = rand();
  295.     }
  296.  
  297.  
  298.     /* If necessary, find out what udp port to send to */
  299.     if (dir_udp_port == 0) {
  300.         register struct servent *sp;
  301.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  302. #ifdef USE_ASSIGNED_PORT
  303.         if ((sp = getservbyname("prospero","udp")) == 0) {
  304. #ifdef DEBUG
  305.         if (pfs_debug)
  306.         fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  307.             PROSPERO_PORT);
  308. #endif
  309.         dir_udp_port = htons((u_short) PROSPERO_PORT);
  310.         }
  311. #else
  312.         if ((sp = getservbyname("dirsrv","udp")) == 0) {
  313. #ifdef DEBUG
  314.         if (pfs_debug)
  315.         fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n", 
  316.             DIRSRV_PORT);
  317. #endif
  318.         dir_udp_port = htons((u_short) DIRSRV_PORT);
  319.         }
  320. #endif
  321.     else dir_udp_port = sp->s_port;
  322.     pfs_enable = tmp;
  323. #ifdef DEBUG
  324.         if (pfs_debug > 3)
  325.             fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  326. #endif
  327.     }
  328.  
  329.     /* If we were given the host address, then use it.  Otherwise  */
  330.     /* lookup the hostname.  If we were passed a host address of   */
  331.     /* 0, we must lookup the host name, then replace the old value */
  332.     if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  333.     /* I we have a null host name, return an error */
  334.     if((hostname == NULL) || (*hostname == '\0')) {
  335. #ifdef DEBUG
  336.             if (pfs_debug)
  337.                 fprintf(stderr, "dirsrv: Null hostname specified\n");
  338. #endif
  339.         perrno = DIRSEND_BAD_HOSTNAME;
  340.         ptlfree(pkt);
  341.             /* return(NULL); */
  342.         return(-1);
  343.     }
  344.     /* If a port is included, save it away */
  345.     if(openparen = index(hostname,'(')) {
  346.         sscanf(openparen+1,"%d",&req_udp_port);
  347.         strncpy(hostnoport,hostname,400);
  348.         if((openparen - hostname) < 400) {
  349.         *(hostnoport + (openparen - hostname)) = '\0';
  350.         hostname = hostnoport;
  351.         }
  352.     }
  353.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  354.         if((host = gethostbyname(hostname)) == NULL) {
  355.         pfs_enable = tmp;
  356.         /* Check if a numeric address */
  357.         newhostaddr = inet_addr(hostname);
  358.         if(newhostaddr == -1) {
  359. #ifdef DEBUG
  360.         if (pfs_debug)
  361.           fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  362. #endif
  363.         perrno = DIRSEND_BAD_HOSTNAME;
  364.         ptlfree(pkt);
  365.         /* return(NULL); */
  366.         return(-1);
  367.         }
  368.         bzero((char *)&to, S_AD_SZ);
  369.         to.sin_family = AF_INET;
  370.         bcopy(&newhostaddr, (char *)&to.sin_addr, 4);
  371.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  372.     }
  373.     else {
  374.         pfs_enable = tmp;
  375.         bzero((char *)&to, S_AD_SZ);
  376.         to.sin_family = host->h_addrtype;
  377.         bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  378.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  379.     }
  380.     }
  381.     else bcopy(hostaddr,&to, S_AD_SZ);
  382.     /* lmjm: Save away the hostname */
  383.     strncpy(to_hostname,
  384.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&to.sin_addr),
  385.         sizeof(to_hostname)-1);
  386.  
  387.     if(req_udp_port) to.sin_port = htons(req_udp_port);
  388.     else to.sin_port = dir_udp_port;
  389.  
  390.     /* If a port was specified in hostaddr, use it, otherwise fill it in */
  391.     if(hostaddr) {
  392.     if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  393.     else hostaddr->sin_port = to.sin_port;
  394.     }
  395.  
  396.     /* Must open a new port each time. we do not want to see old */
  397.     /* responses to messages we are done with                    */
  398.     if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  399. #ifdef DEBUG
  400.         if (pfs_debug)
  401.             fprintf(stderr,"dirsrv: Can't open socket\n");
  402. #endif
  403.     perrno = DIRSEND_UDP_CANT;
  404.     ptlfree(pkt);
  405.         /* return(NULL); */
  406.     return(-1);
  407.     }
  408.  
  409.     /* Try to bind it to a privileged port - loop through candidate */
  410.     /* ports trying to bind.  If failed, that's OK, we will let the */
  411.     /* system assign a non-privileged port later                    */
  412.     if(!notprived) {
  413.     for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  414.         tmp++) {
  415.         bzero((char *)&us, sizeof(us));
  416.         us.sin_family = AF_INET;
  417.         us.sin_port = htons((u_short) tmp);
  418.         if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  419.         if(errno != EADDRINUSE) {
  420.             notprived++;
  421.             break;
  422.         }
  423.         }
  424.         else break;
  425.     }
  426.     }
  427.  
  428. #ifndef USE_V3_PROT
  429.     /* Add header */
  430.     if(rdgram_priority) {
  431.     pkt->start -= 15;
  432.     pkt->length += 15;
  433.     *(pkt->start) = (char) 15;
  434.     bzero(pkt->start+9,4);
  435.     *(pkt->start+11) = 0x02;
  436.     bcopy(&priority,pkt->start+13,2);
  437.     }
  438.     else {
  439.     pkt->start -= 9;
  440.     pkt->length += 9;
  441.     *(pkt->start) = (char) 9;
  442.     }
  443.     this_conn_id = htons(next_conn_id++);
  444.     if(next_conn_id == 0) next_conn_id++;
  445.     bcopy(&this_conn_id,pkt->start+1,2);
  446.     bcopy(&one,pkt->start+3,2);
  447.     bcopy(&one,pkt->start+5,2);
  448.     bzero(pkt->start+7,2);
  449. #endif
  450.  
  451. #ifdef DEBUG
  452.     if (pfs_debug > 2) {
  453. #ifndef USE_V3_PROT
  454.         if (to.sin_family == AF_INET) {
  455.         if(req_udp_port) 
  456.         fprintf(stderr,"Sending message to %s+%d(%d)...",
  457.             to_hostname, req_udp_port, ntohs(this_conn_id));
  458.         else fprintf(stderr,"Sending message to %s(%d)...",
  459.              to_hostname, ntohs(this_conn_id));
  460.     }
  461. #else
  462.         if (to.sin_family == AF_INET) 
  463.         fprintf(stderr,"Sending message to %s...", to_hostname);
  464. #endif
  465.         else
  466.             fprintf(stderr,"Sending message...");
  467.         (void) fflush(stderr);
  468.     }
  469. #endif
  470.  
  471.     first = ptalloc();
  472.     next = first;
  473.  
  474. #ifdef XARCHIE
  475.     status1("Connecting to %s",to_hostname);
  476. #endif
  477.     return(lp);
  478. }
  479.  
  480. /*    -    -    -    -    -    -    -    -    */
  481. /*
  482.  * This used to be a label to goto to retry the last packet. Now we resend
  483.  * the packet and call keepWaitingDirsend() to wait for a reply. (We
  484.  * call keepWaitingDirsend() because formerly the code dropped through
  485.  * the keep_waiting label.)
  486.  */
  487. static void
  488. retryDirsend()
  489. {
  490.     gaps = ackpend = 0;
  491.  
  492.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  493.     if(ns != pkt->length) {
  494. #ifdef DEBUG
  495.     if (pfs_debug) {
  496.     fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  497.         perror("");
  498.     }
  499. #endif
  500.     close(lp);
  501.     perrno = DIRSEND_NOT_ALL_SENT;
  502.     ptlfree(first);
  503.     ptlfree(pkt);
  504.     /* return(NULL); */
  505.     dirsendReturn = NULL;
  506.     dirsendDone = DSRET_SEND_ERROR;
  507.     }
  508. #ifdef DEBUG
  509.     if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  510. #endif
  511.     keepWaitingDirsend();
  512. }
  513.  
  514. /*    -    -    -    -    -    -    -    -    */
  515. /*
  516.  * This used to be a label to goto to set the appropriate timeout value
  517.  * and blocked in select(). Now we set selwait and the fd_sets to the
  518.  * appropriate values, and in X register a new timeout, then return to
  519.  * allow event processing.
  520.  */
  521. static void
  522. keepWaitingDirsend()
  523. {
  524.     /* We come back to this point (by a goto) if the packet */
  525.     /* received is only part of the response, or if the     */
  526.     /* response came from the wrong host            */
  527.  
  528. #ifdef DEBUG
  529.     if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  530. #endif
  531.     FD_ZERO(&readfds);
  532.     FD_SET(lp, &readfds);
  533.  
  534.     if(ackpend) selwait = &ackwait;
  535.     else if(gaps) selwait = &gapwait;
  536.     else selwait = &timeout;
  537.  
  538.     addTimeOut();
  539. }
  540.  
  541. /*    -    -    -    -    -    -    -    -    */
  542. /*
  543.  * This routine is called when a timeout occurs. It includes the code that
  544.  * was formerly used when select() returned 0 (indicating a timeout).
  545.  */
  546. /*ARGSUSED*/
  547. static void
  548. timeoutProc(client_data,id)
  549. XtPointer client_data;
  550. XtIntervalId *id;
  551. {
  552.     if (gaps || ackpend) { /* Send acknowledgment */
  553.     /* Acks are piggybacked on retries - If we have received */
  554.     /* an ack from the server, then the packet sent is only  */
  555.     /* an ack and the rest of the message will be empty      */
  556. #ifdef DEBUG
  557.     if (pfs_debug > 2) {
  558.             fprintf(stderr,"Acknowledging (%s).\n",
  559.             (ackpend ? "requested" : "gaps"));
  560.     }    
  561. #endif
  562.     retryDirsend();
  563.     return;
  564.     }
  565.  
  566.     if (retries-- > 0) {
  567.     timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  568. #ifdef DEBUG
  569.     if (pfs_debug > 2) {
  570.             fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  571.             timeout.tv_sec);
  572.     }
  573. #endif
  574. #ifdef XARCHIE
  575.         status1("Timed out -- retrying (%d seconds)",timeout.tv_sec);
  576. #endif
  577.     retryDirsend();
  578.     return;
  579.     }
  580.  
  581. #ifdef DEBUG
  582.     if (pfs_debug) {
  583.     fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
  584.         readfds);
  585.     perror("");
  586.     }
  587. #endif
  588.     close(lp);
  589.     perrno = DIRSEND_SELECT_FAILED;
  590.     ptlfree(first);
  591.     ptlfree(pkt);
  592.     /* return(NULL); */
  593.     dirsendReturn = NULL;
  594.     dirsendDone = DSRET_TIMEOUT;
  595. }
  596.  
  597. /*    -    -    -    -    -    -    -    -    */
  598. /*
  599.  * This function is called whenever there's something to read on the
  600.  * connection. It includes the code that was run when select() returned
  601.  * greater than 0 (indicating read ready).
  602.  */
  603. /*ARGSUSED*/
  604. static void
  605. readProc(client_data,source,id)
  606. XtPointer client_data;
  607. int *source;
  608. XtInputId *id;
  609. {
  610.     /* We got something to read, so clear the timer */
  611.     removeTimeOut();
  612.  
  613.     from_sz = sizeof(from);
  614.     next->start = next->dat;
  615.     if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  616. #ifdef DEBUG
  617.         if (pfs_debug) perror("recvfrom");
  618. #endif
  619.     close(lp);
  620.     perrno = DIRSEND_BAD_RECV;
  621.     ptlfree(first);
  622.     ptlfree(pkt);
  623.     /* return(NULL) */
  624.     dirsendReturn = NULL;
  625.     dirsendDone = DSRET_RECV_ERROR;
  626.         return;
  627.     }
  628.  
  629.     next->length = nr;
  630.     
  631.     *(next->start + next->length) = NULL;
  632.  
  633. #ifdef DEBUG
  634.     if (pfs_debug > 2)
  635.         fprintf(stderr,"Received packet from %s\n",
  636.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&from.sin_addr);
  637. #endif
  638.  
  639. #ifdef XARCHIE
  640.     {
  641.         static int num = 2;
  642.     if (num == 2)
  643.         status1("Connected to %s",to_hostname);
  644.     else
  645.         status1("Receiving...%c",(num?'+':'*'));
  646.     num = !num;
  647.     }
  648. #endif
  649.  
  650.     /* For the current format, if the first byte is less than             */
  651.     /* 20, then the first two bits are a version number and the next six  */
  652.     /* are the header length (including the first byte).                  */
  653.     if((hdr_len = (unsigned char) *(next->start)) < 20) {
  654.     ctlptr = next->start + 1;
  655.     next->seq = 0;
  656.     if(hdr_len >= 3) {     /* Connection ID */
  657.         bcopy(ctlptr,&stmp,2);
  658.         if(stmp) pkt_cid = ntohs(stmp);
  659.         ctlptr += 2;
  660.     }
  661.     if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  662.         /* The packet is not for us */
  663.         /* goto keep_waiting; */
  664.         keepWaitingDirsend();
  665.         return;
  666.     }
  667.     if(hdr_len >= 5) {    /* Packet number */
  668.         bcopy(ctlptr,&stmp,2);
  669.         next->seq = ntohs(stmp);
  670.         ctlptr += 2;
  671.     }
  672.     else { /* No packet number specified, so this is the only one */
  673.         next->seq = 1;
  674.         nd_pkts = 1;
  675.     }
  676.     if(hdr_len >= 7) {        /* Total number of packets */
  677.         bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  678.         if(stmp) nd_pkts = ntohs(stmp);
  679.         ctlptr += 2;
  680.     }
  681.     if(hdr_len >= 9) {    /* Receievd through */
  682.         bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  683. #ifndef USE_V3_PROT
  684.         if((stmp) && (ntohs(stmp) == 1)) {
  685.         /* Future retries will be acks only */
  686.         pkt->length = 9;
  687.         bcopy(&zero,pkt->start+3,2);
  688. #ifdef DEBUG
  689.         if(pfs_debug > 2) 
  690.             fprintf(stderr,"Server acked request - retries will be acks only\n");
  691. #endif
  692.         }
  693. #endif
  694.         ctlptr += 2;
  695.     }
  696.     if(hdr_len >= 11) {    /* Backoff */
  697.         bcopy(ctlptr,&stmp,2);
  698.         if(stmp) {
  699.         backoff = ntohs(stmp);
  700. #ifdef DEBUG
  701.         if(pfs_debug > 2) 
  702.             fprintf(stderr,"Backing off to %d seconds\n", backoff);
  703. #endif
  704.         timeout.tv_sec = backoff;
  705.         if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  706.             /* Probably a long queue on the server - don't give up */
  707.             retries = client_dirsrv_retry;
  708.         }
  709.         }
  710.         ctlptr += 2;
  711.     }
  712.     if(hdr_len >= 12) {    /* Flags (1st byte) */
  713.         bcopy(ctlptr,&rdflag11,1);
  714.         if(rdflag11 & 0x80) {
  715. #ifdef DEBUG
  716.         if(pfs_debug > 2) 
  717.             fprintf(stderr,"Ack requested\n");
  718. #endif
  719.         ackpend++;
  720.         }
  721.         if(rdflag11 & 0x40) {
  722. #ifdef DEBUG
  723.         if(pfs_debug > 2) 
  724.             fprintf(stderr,"Sequenced control packet\n");
  725. #endif
  726.         next->length = -1;
  727.         scpflag++;
  728.         }
  729.         ctlptr += 1;
  730.     }
  731.     if(hdr_len >= 13) {    /* Flags (2nd byte) */
  732.         /* Reserved for future use */
  733.         bcopy(ctlptr,&rdflag12,1);
  734.         ctlptr += 1;
  735.     }
  736.     if(next->seq == 0) {
  737.         /* goto keep_waiting; */
  738.         keepWaitingDirsend();
  739.         return;
  740.     }
  741.     if(next->length >= 0) next->length -= hdr_len;
  742.     next->start += hdr_len;
  743.     goto done_old;
  744.     }
  745.  
  746.     pkt_cid = 0;
  747.  
  748.     /* if intermediate format (between old and new), then process */
  749.     /* and go to done_old                                         */
  750.     ctlptr = next->start + max(0,next->length-20);
  751.     while(*ctlptr) ctlptr++;
  752.     /* Control fields start after the terminating null */
  753.     ctlptr++;
  754.     /* Until old version are gone, must be 4 extra bytes minimum */
  755.     /* When no version 3 servers, can remove the -4              */
  756.     if(ctlptr < (next->start + next->length - 4)) {
  757.     /* Connection ID */
  758.     bcopy(ctlptr,&stmp,2);
  759.     if(stmp) pkt_cid = ntohs(stmp);
  760.     ctlptr += 2;
  761.     if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  762.         /* The packet is not for us */
  763.         /* goto keep_waiting; */
  764.         keepWaitingDirsend();
  765.         return;
  766.     }
  767.     /* Packet number */
  768.     if(ctlptr < (next->start + next->length)) {
  769.         bcopy(ctlptr,&stmp,2);
  770.         next->seq = ntohs(stmp);
  771.         ctlptr += 2;
  772.     }
  773.     /* Total number of packets */
  774.     if(ctlptr < (next->start + next->length)) {
  775.         bcopy(ctlptr,&stmp,2);
  776.         if(stmp) nd_pkts = ntohs(stmp);
  777.         ctlptr += 2;
  778.     }
  779.     /* Receievd through */
  780.     if(ctlptr < (next->start + next->length)) {
  781.         /* Not supported by clients */
  782.         ctlptr += 2;
  783.     }
  784.     /* Backoff */
  785.     if(ctlptr < (next->start + next->length)) {
  786.         bcopy(ctlptr,&stmp,2);
  787.         backoff = ntohs(stmp);
  788. #ifdef DEBUG
  789.         if(pfs_debug > 2) 
  790.         fprintf(stderr,"Backing off to %d seconds\n", backoff);
  791. #endif
  792.         if(backoff) timeout.tv_sec = backoff;
  793.         ctlptr += 2;
  794.     }
  795.     if(next->seq == 0) {
  796.         /* goto keep_waiting; */
  797.         keepWaitingDirsend();
  798.         return;
  799.     }
  800.     goto done_old;
  801.  
  802.     }
  803.  
  804.     /* Notes that we have to start searching 11 bytes before the    */
  805.     /* expected start of the MULTI-PACKET line because the message  */
  806.     /* might include up to 10 bytes of data after the trailing null */
  807.     /* The order of those bytes is two bytes each for Connection ID */
  808.     /* Packet-no, of, Received-through, Backoff                     */
  809.     seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  810.     if(seqtxt) seqtxt+= 13;
  811.  
  812.     if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  813.  
  814.     tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  815. #ifdef DEBUG    
  816.     if (pfs_debug && (tmp == 0)) 
  817.     fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  818. #endif
  819.  done_old:
  820. #ifdef DEBUG
  821.     if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  822. #endif
  823.     if ((first == next) && (no_pkts == 0)) {
  824.     if(first->seq == 1) {
  825.         comp_thru = first;
  826.         /* If only one packet, then return it */
  827.         if(nd_pkts == 1) goto all_done;
  828.     }
  829.     else gaps++;
  830.     no_pkts = 1;
  831.     next = ptalloc();
  832.     /* goto keep_waiting; */
  833.     keepWaitingDirsend();
  834.     return;
  835.     }
  836.     
  837.     if(comp_thru && (next->seq <= comp_thru->seq))
  838.     ptfree(next);
  839.     else if (next->seq < first->seq) {
  840.     vtmp = first;
  841.     first = next;
  842.     first->next = vtmp;
  843.     first->previous = NULL;
  844.     vtmp->previous = first;
  845.     if(first->seq == 1) comp_thru = first;
  846.     no_pkts++;
  847.     }
  848.     else {
  849.     vtmp = (comp_thru ? comp_thru : first);
  850.     while (vtmp->seq < next->seq) {
  851.         if(vtmp->next == NULL) {
  852.         vtmp->next = next;
  853.         next->previous = vtmp;
  854.         next->next = NULL;
  855.         no_pkts++;
  856.         goto ins_done;
  857.         }
  858.         vtmp = vtmp->next;
  859.     }
  860.     if(vtmp->seq == next->seq)
  861.         ptfree(next);
  862.     else {
  863.         vtmp->previous->next = next;
  864.         next->previous = vtmp->previous;
  865.         next->next = vtmp;
  866.         vtmp->previous = next;
  867.         no_pkts++;
  868.     }
  869.     }   
  870.  
  871. ins_done:
  872.     
  873.     while(comp_thru && comp_thru->next && 
  874.       (comp_thru->next->seq == (comp_thru->seq + 1))) {
  875.     comp_thru = comp_thru->next;
  876. #ifndef USE_V3_PROT
  877.     recvd_thru = htons(comp_thru->seq);
  878.     bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  879. #endif
  880.     /* We've made progress, so reset retry count */
  881.     retries = client_dirsrv_retry;
  882.     /* Also, next retry will be only an acknowledgement */
  883.     /* but for now, we can't fill in the ack field      */
  884. #ifdef DEBUG
  885.     if(pfs_debug > 2) 
  886.         fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  887. #endif
  888.     }
  889.  
  890.     /* See if there are any gaps */
  891.     if(!comp_thru || comp_thru->next) gaps++;
  892.     else gaps = 0;
  893.  
  894.     if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  895.     next = ptalloc();
  896.     /* goto keep_waiting; */
  897.     keepWaitingDirsend();
  898.     return;
  899.     }
  900.  
  901.  all_done:
  902.     if(ackpend) { /* Send acknowledgement if requested */
  903. #ifdef DEBUG
  904.     if (pfs_debug > 2) {
  905.         if (to.sin_family == AF_INET)
  906.         fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  907.             to_hostname, ntohs(this_conn_id));
  908.             else
  909.                 fprintf(stderr,"Acknowledging final packet\n");
  910.         (void) fflush(stderr);
  911.     }
  912. #endif
  913.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  914.     if(ns != pkt->length) {
  915. #ifdef DEBUG
  916.         if (pfs_debug) {
  917.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  918.         perror("");
  919.         }
  920. #endif
  921.     }
  922.  
  923.     }
  924.     close(lp);
  925.     ptlfree(pkt);
  926.  
  927.     /* Get rid of any sequenced control packets */
  928.     if(scpflag) {
  929.     while(first && (first->length < 0)) {
  930.         vtmp = first;
  931.         first = first->next;
  932.         if(first) first->previous = NULL;
  933.         ptfree(vtmp);
  934.     }
  935.     vtmp = first;
  936.     while(vtmp && vtmp->next) {
  937.         if(vtmp->next->length < 0) {
  938.         if(vtmp->next->next) {
  939.             vtmp->next = vtmp->next->next;
  940.             ptfree(vtmp->next->previous);
  941.             vtmp->next->previous = vtmp;
  942.         }
  943.         else {
  944.             ptfree(vtmp->next);
  945.             vtmp->next = NULL;
  946.         }
  947.         }
  948.         vtmp = vtmp->next;
  949.     }
  950.     }
  951.  
  952.     /* return(first); */
  953.     dirsendReturn = first;
  954.     dirsendDone = DSRET_DONE;
  955.  
  956. }
  957. /*    -    -    -    -    -    -    -    -    */
  958. /* These routines allow dirsend() to run with or without X by providing
  959.  * wrappers around the calls that handle the asynchronous communication.
  960.  * All parameters are passed using globals.
  961.  * Under X: The input sources and timeouts are set using Xt calls, and
  962.  *        processEvent() just calls XtAppProcessEvent().
  963.  * Non-X: None of the input sources and timeouts are used, and
  964.  *      processEvent() calls select() to handle both timeouts and the
  965.  *      socket file descriptor. The return value of select() is used
  966.  *      to determine which callback routine to call.
  967.  */
  968.  
  969. static void
  970. addInputSource()
  971. {
  972. #ifdef XARCHIE
  973.     inputId = XtAppAddInput(appContext,lp,XtInputReadMask,readProc,NULL);
  974. #endif
  975. }
  976.  
  977. static void
  978. removeInputSource()
  979. {
  980. #ifdef XARCHIE
  981.     XtRemoveInput(inputId);
  982. #endif
  983. }
  984.  
  985. static void
  986. addTimeOut()
  987. {
  988. #ifdef XARCHIE
  989.     unsigned long timeoutLen = selwait->tv_sec*1000 + selwait->tv_usec/1000;
  990.  
  991.     /* old timeout can still be there if we are being called after the
  992.      * file descriptor was read, so we remove it just to be sure. */
  993.     removeTimeOut();
  994.     timerId = XtAppAddTimeOut(appContext,timeoutLen,timeoutProc,NULL);
  995. #endif
  996. }
  997.  
  998. static void
  999. removeTimeOut()
  1000. {
  1001. #ifdef XARCHIE
  1002.     if (timerId != (XtIntervalId)0) {
  1003.     XtRemoveTimeOut(timerId);
  1004.     timerId = (XtIntervalId)0;
  1005.     }
  1006. #endif
  1007. }
  1008.  
  1009. static void
  1010. processEvent()
  1011. {
  1012. #ifdef XARCHIE
  1013.     XtAppProcessEvent(appContext,XtIMAll);
  1014. #else
  1015.     /* select - either recv is ready, or timeout */
  1016.     /* see if timeout or error or wrong descriptor */
  1017.     tmp = select(lp + 1, &readfds, (fd_set *)0, (fd_set *)0, selwait);
  1018.     if (tmp == 0) {
  1019.     timeoutProc(NULL,&timerId);
  1020.     } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
  1021. #ifdef DEBUG
  1022.     if (pfs_debug) {
  1023.         fprintf(stderr, "select failed(processEvent): readfds=%x ",
  1024.             readfds);
  1025.         perror("");
  1026.     }
  1027. #endif
  1028.     close(lp);
  1029.     perrno = DIRSEND_SELECT_FAILED;
  1030.     ptlfree(first);
  1031.     ptlfree(pkt);
  1032.     /* return(NULL); */
  1033.     dirsendReturn = NULL;
  1034.     dirsendDone = DSRET_SELECT_ERROR;
  1035.     } else {
  1036.     readProc(NULL,&lp,&inputId);
  1037.     }
  1038. #endif /* XARCHIE */
  1039. }
  1040.  
  1041. void
  1042. abortDirsend()
  1043. {
  1044.     if (!dirsendDone) {
  1045.     close(lp);
  1046.     ptlfree(first);
  1047.     ptlfree(pkt);
  1048.     dirsendReturn = NULL;
  1049.     dirsendDone = DSRET_ABORTED;
  1050.     }
  1051.     return;
  1052. }
  1053.