dirsend.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:26k
源码类别:

代理服务器

开发平台:

Unix_Linux

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