home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / XARCHIE0.TAR / dirsend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-28  |  20.6 KB  |  747 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.  * Modified for xarchie by George Ferguson, ferguson@cs.rochester.edu,
  8.  * 21 Aug 1991.
  9.  */
  10.  
  11. #include <copyright.h>
  12. #include <stdio.h>
  13. #include <errno.h>
  14. #include <sys/time.h>
  15. #include <netdb.h>
  16. #include <strings.h>
  17.  
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #ifdef AIX
  21. #include <sys/select.h>
  22. #endif
  23.  
  24.  
  25. #include <pfs.h>
  26. #include <pprot.h>
  27. #include <pcompat.h>
  28. #include <perrno.h>
  29. #include <pmachine.h>
  30.  
  31.  
  32. static int notprived = 0;
  33. extern int errno;
  34. extern int perrno;
  35. #ifdef DEBUG
  36. extern int pfs_debug;
  37. #endif
  38. extern int pfs_disable_flag;
  39.  
  40. int    rdgram_priority = 0;
  41.  
  42. char    *nlsindex();
  43.  
  44. #define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  45.  
  46. static int        dir_udp_port = 0;    /* Remote UDP port number */
  47.  
  48. static unsigned short    next_conn_id = 0;
  49.  
  50. #ifdef XARCHIE
  51. int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  52. int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  53. #else /* !XARCHIE */
  54. static int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  55. static int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  56. #endif /* XARCHIE */
  57.  
  58. /*
  59.  * dirsend - send packet and receive response
  60.  *
  61.  *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  62.  *   and a pointer to a host address.  It then sends the supplied
  63.  *   packet off to the directory server on the specified host.  If
  64.  *   hostaddr points to a valid address, that address is used.  Otherwise,
  65.  *   the hostname is looked up to obtain the address.  If hostaddr is a
  66.  *   non-null pointer to a 0 address, then the address will be replaced
  67.  *   with that found in the hostname lookup.
  68.  *
  69.  *   DIRSEND will wait for a response and retry an appropriate
  70.  *   number of times as defined by timeout and retries (both static
  71.  *   variables).  It will collect however many packets form the reply, and
  72.  *   return them in a structure (or structures) of type PTEXT.
  73.  *
  74.  *   DIRSEND will free the packet that it is presented as an argument.
  75.  *   The packet is freed even if dirsend fails.
  76.  */
  77. PTEXT
  78. dirsend(pkt,hostname,hostaddr)
  79.     PTEXT pkt;
  80.     char *hostname;
  81.     struct sockaddr_in    *hostaddr;
  82. {
  83.     PTEXT        first = NULL;    /* First returned packet     */
  84.     PTEXT        next;        /* The one we are waiting for      */
  85.     PTEXT        vtmp;           /* For reorganizing linked list  */
  86.     PTEXT        comp_thru;    /* We have all packets though    */
  87.     int            lp = -1;    /* Opened UDP port             */
  88.     int            hdr_len;    /* Header Length                 */
  89.     int            nd_pkts;    /* Number of packets we want     */
  90.     int            no_pkts;    /* Number of packets we have     */
  91.     int            pkt_cid;        /* Packet connection identifier  */
  92.     unsigned short    this_conn_id;    /* Connection ID we are using    */
  93.     unsigned short    recvd_thru;    /* Received through              */
  94.     short        priority;    /* Priority for request          */
  95.     static short    one = 0;    /* Pointer to value 1            */
  96.     static short    zero = 0;    /* Pointer to value 0         */
  97.     char        *seqtxt;    /* Pointer to text w/ sequence # */
  98.     struct sockaddr_in  us;        /* Our address                   */
  99.     struct sockaddr_in    to;        /* Address to send query     */
  100.     struct sockaddr_in    from;        /* Reply received from         */
  101.     int            from_sz;    /* Size of from structure     */
  102.     struct hostent    *host;        /* Host info from gethostbyname  */
  103.     long        newhostaddr;    /* New host address from *host   */
  104.     int            req_udp_port=0; /* Requested port (optional)     */
  105.     char        *openparen;    /* Delimits port in name         */
  106.     char        hostnoport[500];/* Host name without port        */
  107.     int            ns;        /* Number of bytes actually sent */
  108.     int            nr;        /* Number of bytes received      */
  109.     fd_set        readfds;    /* Used for select         */
  110.     int            tmp;
  111.     char        *ctlptr;    /* Pointer to control field      */
  112.     short        stmp;        /* Temp short for conversions    */
  113.     int            backoff;    /* Server requested backoff      */
  114.     unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  115.     unsigned char    rdflag12;    /* Second byte of flags (int)    */
  116.     int            scpflag = 0;    /* Set if any sequencd cont pkts */
  117.  
  118.     int            ackpend = 0;    /* Acknowledgement pending      */
  119.     int            gaps = 0;    /* Gaps present in recvd pkts   */
  120.     struct timeval    timeout;    /* Time to wait for response    */
  121.     struct timeval    ackwait;    /* Time to wait before acking   */
  122.     struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  123.     struct timeval    *selwait;    /* Time to wait for select      */
  124.     int            retries = client_dirsrv_retry;
  125.  
  126. #ifdef XARCHIE
  127.     status0("Initializing");
  128. #endif
  129.  
  130.     if(one == 0) one = htons((short) 1);
  131.  
  132.     priority = htons(rdgram_priority);
  133.  
  134.     timeout.tv_sec = client_dirsrv_timeout;
  135.     timeout.tv_usec = 0;
  136.  
  137.     ackwait.tv_sec = 0;
  138.     ackwait.tv_usec = 500000;
  139.  
  140.     gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  141.     gapwait.tv_usec = 0;
  142.  
  143.     comp_thru = NULL;
  144.     perrno = 0;
  145.     nd_pkts = 0;
  146.     no_pkts = 0;
  147.     pkt_cid = 0;
  148.  
  149.     /* Find first connection ID */
  150.     if(next_conn_id == 0) {
  151.     srand(getpid()+time(0));
  152.     next_conn_id = rand();
  153.     }
  154.  
  155.  
  156.     /* If necessary, find out what udp port to send to */
  157.     if (dir_udp_port == 0) {
  158.         register struct servent *sp;
  159.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  160. #ifdef USE_ASSIGNED_PORT
  161.         if ((sp = getservbyname("prospero","udp")) == 0) {
  162. #ifdef DEBUG
  163.         if (pfs_debug)
  164.         fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  165.             PROSPERO_PORT);
  166. #endif
  167.         dir_udp_port = htons((u_short) PROSPERO_PORT);
  168.         }
  169. #else
  170.         if ((sp = getservbyname("dirsrv","udp")) == 0) {
  171. #ifdef DEBUG
  172.         if (pfs_debug)
  173.         fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n", 
  174.             DIRSRV_PORT);
  175. #endif
  176.         dir_udp_port = htons((u_short) DIRSRV_PORT);
  177.         }
  178. #endif
  179.     else dir_udp_port = sp->s_port;
  180.     pfs_enable = tmp;
  181. #ifdef DEBUG
  182.         if (pfs_debug > 3)
  183.             fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  184. #endif
  185.     }
  186.  
  187.     /* If we were given the host address, then use it.  Otherwise  */
  188.     /* lookup the hostname.  If we were passed a host address of   */
  189.     /* 0, we must lookup the host name, then replace the old value */
  190.     if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  191.     /* I we have a null host name, return an error */
  192.     if((hostname == NULL) || (*hostname == '\0')) {
  193. #ifdef DEBUG
  194.             if (pfs_debug)
  195.                 fprintf(stderr, "dirsrv: Null hostname specified\n");
  196. #endif
  197.         perrno = DIRSEND_BAD_HOSTNAME;
  198.         ptlfree(pkt);
  199.             return(NULL);
  200.     }
  201.     /* If a port is included, save it away */
  202.     if(openparen = index(hostname,'(')) {
  203.         sscanf(openparen+1,"%d",&req_udp_port);
  204.         strncpy(hostnoport,hostname,400);
  205.         if((openparen - hostname) < 400) {
  206.         *(hostnoport + (openparen - hostname)) = '\0';
  207.         hostname = hostnoport;
  208.         }
  209.     }
  210.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  211.         if((host = gethostbyname(hostname)) == NULL) {
  212.         pfs_enable = tmp;
  213.         /* Check if a numeric address */
  214.         newhostaddr = inet_addr(hostname);
  215.         if(newhostaddr == -1) {
  216. #ifdef DEBUG
  217.         if (pfs_debug)
  218.           fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  219. #endif
  220.         perrno = DIRSEND_BAD_HOSTNAME;
  221.         ptlfree(pkt);
  222.         return(NULL);
  223.         }
  224.         bzero((char *)&to, S_AD_SZ);
  225.         to.sin_family = AF_INET;
  226.         bcopy(&newhostaddr, (char *)&to.sin_addr, 4);
  227.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  228.     }
  229.     else {
  230.         pfs_enable = tmp;
  231.         bzero((char *)&to, S_AD_SZ);
  232.         to.sin_family = host->h_addrtype;
  233.         bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  234.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  235.     }
  236.     }
  237.     else bcopy(hostaddr,&to, S_AD_SZ);
  238.  
  239.     if(req_udp_port) to.sin_port = htons(req_udp_port);
  240.     else to.sin_port = dir_udp_port;
  241.  
  242.     /* If a port was specified in hostaddr, use it, otherwise fill it in */
  243.     if(hostaddr) {
  244.     if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  245.     else hostaddr->sin_port = to.sin_port;
  246.     }
  247.  
  248.     /* Must open a new port each time. we do not want to see old */
  249.     /* responses to messages we are done with                    */
  250.     if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  251. #ifdef DEBUG
  252.         if (pfs_debug)
  253.             fprintf(stderr,"dirsrv: Can't open socket\n");
  254. #endif
  255.     perrno = DIRSEND_UDP_CANT;
  256.     ptlfree(pkt);
  257.         return(NULL);
  258.     }
  259.  
  260.     /* Try to bind it to a privileged port - loop through candidate */
  261.     /* ports trying to bind.  If failed, that's OK, we will let the */
  262.     /* system assign a non-privileged port later                    */
  263.     if(!notprived) {
  264.     for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  265.         tmp++) {
  266.         bzero((char *)&us, sizeof(us));
  267.         us.sin_family = AF_INET;
  268.         us.sin_port = htons((u_short) tmp);
  269.         if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  270.         if(errno != EADDRINUSE) {
  271.             notprived++;
  272.             break;
  273.         }
  274.         }
  275.         else break;
  276.     }
  277.     }
  278.  
  279. #ifndef USE_V3_PROT
  280.     /* Add header */
  281.     if(rdgram_priority) {
  282.     pkt->start -= 15;
  283.     pkt->length += 15;
  284.     *(pkt->start) = (char) 15;
  285.     bzero(pkt->start+9,4);
  286.     *(pkt->start+11) = 0x02;
  287.     bcopy(&priority,pkt->start+13,2);
  288.     }
  289.     else {
  290.     pkt->start -= 9;
  291.     pkt->length += 9;
  292.     *(pkt->start) = (char) 9;
  293.     }
  294.     this_conn_id = htons(next_conn_id++);
  295.     if(next_conn_id == 0) next_conn_id++;
  296.     bcopy(&this_conn_id,pkt->start+1,2);
  297.     bcopy(&one,pkt->start+3,2);
  298.     bcopy(&one,pkt->start+5,2);
  299.     bzero(pkt->start+7,2);
  300. #endif
  301.  
  302. #ifdef DEBUG
  303.     if (pfs_debug > 2) {
  304. #ifndef USE_V3_PROT
  305.         if (to.sin_family == AF_INET) {
  306.         if(req_udp_port) 
  307.         fprintf(stderr,"Sending message to %s+%d(%d)...",
  308.             inet_ntoa(*(struct in_addr *)&to.sin_addr), req_udp_port, ntohs(this_conn_id));
  309.         else fprintf(stderr,"Sending message to %s(%d)...",
  310.              inet_ntoa(*(struct in_addr *)&to.sin_addr), ntohs(this_conn_id));
  311.     }
  312. #else
  313.         if (to.sin_family == AF_INET) 
  314.         fprintf(stderr,"Sending message to %s...", inet_ntoa(*(struct in_addr *)&to.sin_addr));
  315. #endif
  316.         else
  317.             fprintf(stderr,"Sending message...");
  318.         (void) fflush(stderr);
  319.     }
  320. #endif
  321.  
  322.     first = ptalloc();
  323.     next = first;
  324.  
  325. #ifdef XARCHIE
  326.     status1("Connecting to %s",inet_ntoa(*(struct in_addr *)&to.sin_addr));
  327. #endif
  328.  
  329.  retry:
  330.  
  331.     gaps = ackpend = 0;
  332.  
  333.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  334.     if(ns != pkt->length) {
  335. #ifdef DEBUG
  336.     if (pfs_debug) {
  337.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  338.         perror("");
  339.     }
  340. #endif
  341.     close(lp);
  342.     perrno = DIRSEND_NOT_ALL_SENT;
  343.     ptlfree(first);
  344.     ptlfree(pkt);
  345. #ifdef XARCHIE
  346.         status0("Send Error");
  347. #endif
  348.         return(NULL);
  349.     }
  350. #ifdef DEBUG
  351.     if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  352. #endif
  353.     /* We come back to this point (by a goto) if the packet */
  354.     /* received is only part of the response, or if the     */
  355.     /* response came from the wrong host            */
  356.  
  357.  keep_waiting:    
  358. #ifdef DEBUG
  359.     if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  360. #endif
  361.     FD_ZERO(&readfds);
  362.     FD_SET(lp, &readfds);
  363.  
  364.     if(ackpend) selwait = &ackwait;
  365.     else if(gaps) selwait = &gapwait;
  366.     else selwait = &timeout;
  367.  
  368.     /* select - either recv is ready, or timeout */
  369.     /* see if timeout or error or wrong descriptor */
  370.     tmp = select(lp + 1, &readfds, (fd_set *)0, (fd_set *)0, selwait);
  371.  
  372.     if((tmp == 0) && (gaps || ackpend)) { /* Send acknowledgment */
  373.     /* Acks are piggybacked on retries - If we have received */
  374.     /* an ack from the server, then the packet sent is only  */
  375.     /* an ack and the rest of the message will be empty      */
  376. #ifdef DEBUG
  377.     if (pfs_debug > 2) {
  378.             fprintf(stderr,"Acknowledging (%s).\n",
  379.             (ackpend ? "requested" : "gaps"));
  380.     }    
  381. #endif
  382.     goto retry;
  383.     }
  384.  
  385.     if((tmp == 0) && (retries-- > 0)) {
  386.     timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  387. #ifdef DEBUG
  388.     if (pfs_debug > 2) {
  389.             fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  390.             timeout.tv_sec);
  391.     }
  392. #endif
  393. #ifdef XARCHIE
  394.         status1("Timed out -- retrying (%d seconds)",timeout.tv_sec);
  395. #endif
  396.     goto retry;
  397.     }
  398.  
  399.     if((tmp < 1) || !FD_ISSET(lp, &readfds)) {
  400. #ifdef DEBUG
  401.     if (pfs_debug) {
  402.         fprintf(stderr, "select failed: readfds=%x ",
  403.                     readfds);
  404.             perror("");
  405.         }
  406. #endif
  407.     close(lp);
  408.     perrno = DIRSEND_SELECT_FAILED;
  409.     ptlfree(first);
  410.     ptlfree(pkt);
  411. #ifdef XARCHIE
  412.         status1("Couldn't connect to %s",
  413.         inet_ntoa(*(struct in_addr *)&to.sin_addr));
  414. #endif
  415.         return(NULL);
  416.     }
  417.  
  418.  
  419.     from_sz = sizeof(from);
  420.     next->start = next->dat;
  421.     if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  422. #ifdef DEBUG
  423.         if (pfs_debug) perror("recvfrom");
  424. #endif
  425.     close(lp);
  426.     perrno = DIRSEND_BAD_RECV;
  427.     ptlfree(first);
  428.     ptlfree(pkt);
  429. #ifdef XARCHIE
  430.         status0("Recv Error");
  431. #endif
  432.         return(NULL);
  433.     }
  434.  
  435.     next->length = nr;
  436.     
  437.     *(next->start + next->length) = NULL;
  438.  
  439. #ifdef DEBUG
  440.     if (pfs_debug > 2) 
  441.         fprintf(stderr,"Received packet from %s\n", inet_ntoa(*(struct in_addr *)&from.sin_addr));
  442. #endif
  443.     if (to.sin_addr.s_addr != from.sin_addr.s_addr) {
  444. #ifdef DEBUG
  445.     if (pfs_debug) {
  446.         fprintf(stderr, "dirsend: received packet from wrong host! (%x)\n",
  447.             from.sin_addr.s_addr);
  448.         (void) fflush(stdout);
  449.     }
  450. #endif
  451.     goto keep_waiting;
  452.     }
  453.  
  454. #ifdef XARCHIE
  455.     {
  456.         static int num = 2;
  457.     if (num == 2)
  458.         status1("Connected to %s",
  459.             inet_ntoa(*(struct in_addr *)&to.sin_addr));
  460.     else
  461.         status1("Receiving...%c",(num?'+':'*'));
  462.     num = !num;
  463.     }
  464. #endif
  465.  
  466.     /* For the current format, if the first byte is less than             */
  467.     /* 20, then the first two bits are a version number and the next six  */
  468.     /* are the header length (including the first byte).                  */
  469.     if((hdr_len = (unsigned char) *(next->start)) < 20) {
  470.     ctlptr = next->start + 1;
  471.     next->seq = 0;
  472.     if(hdr_len >= 3) {     /* Connection ID */
  473.         bcopy(ctlptr,&stmp,2);
  474.         if(stmp) pkt_cid = ntohs(stmp);
  475.         ctlptr += 2;
  476.     }
  477.     if(hdr_len >= 5) {    /* Packet number */
  478.         bcopy(ctlptr,&stmp,2);
  479.         next->seq = ntohs(stmp);
  480.         ctlptr += 2;
  481.     }
  482.     else { /* No packet number specified, so this is the only one */
  483.         next->seq = 1;
  484.         nd_pkts = 1;
  485.     }
  486.     if(hdr_len >= 7) {        /* Total number of packets */
  487.         bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  488.         if(stmp) nd_pkts = ntohs(stmp);
  489.         ctlptr += 2;
  490.     }
  491.     if(hdr_len >= 9) {    /* Receievd through */
  492.         bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  493. #ifndef USE_V3_PROT
  494.         if((stmp) && (ntohs(stmp) == 1)) {
  495.         /* Future retries will be acks only */
  496.         pkt->length = 9;
  497.         bcopy(&zero,pkt->start+3,2);
  498. #ifdef DEBUG
  499.         if(pfs_debug > 2) 
  500.             fprintf(stderr,"Server acked request - retries will be acks only\n");
  501. #endif
  502.         }
  503. #endif
  504.         ctlptr += 2;
  505.     }
  506.     if(hdr_len >= 11) {    /* Backoff */
  507.         bcopy(ctlptr,&stmp,2);
  508.         if(stmp) {
  509.         backoff = ntohs(stmp);
  510. #ifdef DEBUG
  511.         if(pfs_debug > 2) 
  512.             fprintf(stderr,"Backing off to %d seconds\n", backoff);
  513. #endif
  514.         timeout.tv_sec = backoff;
  515.         if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  516.             /* Probably a long queue on the server - don't give up */
  517.             retries = client_dirsrv_retry;
  518.         }
  519.         }
  520.         ctlptr += 2;
  521.     }
  522.     if(hdr_len >= 12) {    /* Flags (1st byte) */
  523.         bcopy(ctlptr,&rdflag11,1);
  524.         if(rdflag11 & 0x80) {
  525. #ifdef DEBUG
  526.         if(pfs_debug > 2) 
  527.             fprintf(stderr,"Ack requested\n");
  528. #endif
  529.         ackpend++;
  530.         }
  531.         if(rdflag11 & 0x40) {
  532. #ifdef DEBUG
  533.         if(pfs_debug > 2) 
  534.             fprintf(stderr,"Sequenced control packet\n");
  535. #endif
  536.         next->length = -1;
  537.         scpflag++;
  538.         }
  539.         ctlptr += 1;
  540.     }
  541.     if(hdr_len >= 13) {    /* Flags (2nd byte) */
  542.         /* Reserved for future use */
  543.         bcopy(ctlptr,&rdflag12,1);
  544.         ctlptr += 1;
  545.     }
  546.     if(next->seq == 0) goto keep_waiting;
  547.     if(next->length >= 0) next->length -= hdr_len;
  548.     next->start += hdr_len;
  549.     goto done_old;
  550.     }
  551.  
  552.     pkt_cid = 0;
  553.  
  554.     /* if intermediate format (between old and new), then process */
  555.     /* and go to done_old                                         */
  556.     ctlptr = next->start + max(0,next->length-20);
  557.     while(*ctlptr) ctlptr++;
  558.     /* Control fields start after the terminating null */
  559.     ctlptr++;
  560.     /* Until old version are gone, must be 4 extra bytes minimum */
  561.     /* When no version 3 servers, can remove the -4              */
  562.     if(ctlptr < (next->start + next->length - 4)) {
  563.     /* Connection ID */
  564.     bcopy(ctlptr,&stmp,2);
  565.     if(stmp) pkt_cid = ntohs(stmp);
  566.     ctlptr += 2;
  567.     /* Packet number */
  568.     if(ctlptr < (next->start + next->length)) {
  569.         bcopy(ctlptr,&stmp,2);
  570.         next->seq = ntohs(stmp);
  571.         ctlptr += 2;
  572.     }
  573.     /* Total number of packets */
  574.     if(ctlptr < (next->start + next->length)) {
  575.         bcopy(ctlptr,&stmp,2);
  576.         if(stmp) nd_pkts = ntohs(stmp);
  577.         ctlptr += 2;
  578.     }
  579.     /* Receievd through */
  580.     if(ctlptr < (next->start + next->length)) {
  581.         /* Not supported by clients */
  582.         ctlptr += 2;
  583.     }
  584.     /* Backoff */
  585.     if(ctlptr < (next->start + next->length)) {
  586.         bcopy(ctlptr,&stmp,2);
  587.         backoff = ntohs(stmp);
  588. #ifdef DEBUG
  589.         if(pfs_debug > 2) 
  590.         fprintf(stderr,"Backing off to %d seconds\n", backoff);
  591. #endif
  592.         if(backoff) timeout.tv_sec = backoff;
  593.         ctlptr += 2;
  594.     }
  595.     if(next->seq == 0) goto keep_waiting;
  596.     goto done_old;
  597.  
  598.     }
  599.  
  600.     /* Notes that we have to start searching 11 bytes before the    */
  601.     /* expected start of the MULTI-PACKET line because the message  */
  602.     /* might include up to 10 bytes of data after the trailing null */
  603.     /* The order of those bytes is two bytes each for Connection ID */
  604.     /* Packet-no, of, Received-through, Backoff                     */
  605.     seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  606.     if(seqtxt) seqtxt+= 13;
  607.  
  608.     if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  609.  
  610.     tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  611. #ifdef DEBUG    
  612.     if (pfs_debug && (tmp == 0)) 
  613.     fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  614. #endif
  615.  done_old:
  616. #ifdef DEBUG
  617.     if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  618. #endif
  619.     if ((first == next) && (no_pkts == 0)) {
  620.     if(first->seq == 1) {
  621.         comp_thru = first;
  622.         /* If only one packet, then return it */
  623.         if(nd_pkts == 1) goto all_done;
  624.     }
  625.     else gaps++;
  626.     no_pkts = 1;
  627.     next = ptalloc();
  628.     goto keep_waiting;
  629.     }
  630.     
  631.     if(comp_thru && (next->seq <= comp_thru->seq))
  632.     ptfree(next);
  633.     else if (next->seq < first->seq) {
  634.     vtmp = first;
  635.     first = next;
  636.     first->next = vtmp;
  637.     first->previous = NULL;
  638.     vtmp->previous = first;
  639.     if(first->seq == 1) comp_thru = first;
  640.     no_pkts++;
  641.     }
  642.     else {
  643.     vtmp = (comp_thru ? comp_thru : first);
  644.     while (vtmp->seq < next->seq) {
  645.         if(vtmp->next == NULL) {
  646.         vtmp->next = next;
  647.         next->previous = vtmp;
  648.         next->next = NULL;
  649.         no_pkts++;
  650.         goto ins_done;
  651.         }
  652.         vtmp = vtmp->next;
  653.     }
  654.     if(vtmp->seq == next->seq)
  655.         ptfree(next);
  656.     else {
  657.         vtmp->previous->next = next;
  658.         next->previous = vtmp->previous;
  659.         next->next = vtmp;
  660.         vtmp->previous = next;
  661.         no_pkts++;
  662.     }
  663.     }   
  664.  
  665. ins_done:
  666.     
  667.     while(comp_thru && comp_thru->next && 
  668.       (comp_thru->next->seq == (comp_thru->seq + 1))) {
  669.     comp_thru = comp_thru->next;
  670. #ifndef USE_V3_PROT
  671.     recvd_thru = htons(comp_thru->seq);
  672.     bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  673. #endif
  674.     /* We've made progress, so reset retry count */
  675.     retries = client_dirsrv_retry;
  676.     /* Also, next retry will be only an acknowledgement */
  677.     /* but for now, we can't fill in the ack field      */
  678. #ifdef DEBUG
  679.     if(pfs_debug > 2) 
  680.         fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  681. #endif
  682.     }
  683.  
  684.     /* See if there are any gaps */
  685.     if(!comp_thru || comp_thru->next) gaps++;
  686.     else gaps = 0;
  687.  
  688.     if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  689.     next = ptalloc();
  690.     goto keep_waiting;
  691.     }
  692.  
  693.  all_done:
  694.     if(ackpend) { /* Send acknowledgement if requested */
  695. #ifdef DEBUG
  696.     if (pfs_debug > 2) {
  697.         if (to.sin_family == AF_INET)
  698.         fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  699.             inet_ntoa(*(struct in_addr *)&to.sin_addr), ntohs(this_conn_id));
  700.             else
  701.                 fprintf(stderr,"Acknowledging final packet\n");
  702.         (void) fflush(stderr);
  703.     }
  704. #endif
  705.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  706.     if(ns != pkt->length) {
  707. #ifdef DEBUG
  708.         if (pfs_debug) {
  709.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  710.         perror("");
  711.         }
  712. #endif
  713.     }
  714.  
  715.     }
  716.     close(lp);
  717.     ptlfree(pkt);
  718.  
  719.     /* Get rid of any sequenced control packets */
  720.     if(scpflag) {
  721.     while(first && (first->length < 0)) {
  722.         vtmp = first;
  723.         first = first->next;
  724.         if(first) first->previous = NULL;
  725.         ptfree(vtmp);
  726.     }
  727.     vtmp = first;
  728.     while(vtmp && vtmp->next) {
  729.         if(vtmp->next->length < 0) {
  730.         if(vtmp->next->next) {
  731.             vtmp->next = vtmp->next->next;
  732.             ptfree(vtmp->next->previous);
  733.             vtmp->next->previous = vtmp;
  734.         }
  735.         else {
  736.             ptfree(vtmp->next);
  737.             vtmp->next = NULL;
  738.         }
  739.         }
  740.         vtmp = vtmp->next;
  741.     }
  742.     }
  743.  
  744.     return(first);
  745.  
  746. }
  747.