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