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