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