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