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