dirsend.c
资源名称:socks5.zip [点击查看]
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:26k
源码类别:
代理服务器
开发平台:
Unix_Linux
- /* Copyright (c) 1989, 1990, 1991 by the University of Washington */
- /* */
- /* For copying and distribution information, please see the file */
- /* <copyright.h>. */
- /* If you're going to hack on this, I'd suggest using unifdef with -UCUTCP */
- /* for your working copy. When you've got your changes done, come back and */
- /* add them into this main file. It's getting pretty nasty down there. */
- #include "pmachine.h"
- /* THIS does FD_SET etc on AT&T 3b2s. */
- #ifdef u3b2
- # include <sys/inet.h>
- #endif
- /* Interactive UNIX keeps some of the socket definitions in funny places. */
- #ifdef ISC
- # include <net/errno.h>
- #endif /* ISC */
- #include "pfs.h"
- #include "pprot.h"
- #include "pcompat.h"
- #include "perrno.h"
- static int notprived = 0;
- extern int errno;
- extern int perrno;
- extern int rdgram_priority;
- #ifdef DEBUG
- extern int pfs_debug;
- #endif
- extern int pfs_disable_flag;
- extern int verbose;
- char *nlsindex();
- #define max(X, Y) ((X) > (Y) ? (X) : (Y))
- static int dir_udp_port = 0; /* Remote UDP port number */
- static unsigned short next_conn_id = 0;
- static int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
- static int client_dirsrv_retry = CLIENT_DIRSRV_RETRY;
- /* These were parameters to dirsend() */
- static PTEXT pkt;
- static char *hostname;
- static struct sockaddr_in *hostaddr;
- /* These were locals in dirsend(). Note that the initializations here
- * are really meaningless since we have to redo them for each call to
- * dirsend() since they were formerly automatically initialized.
- */
- static PTEXT first = NULL; /* First returned packet */
- static PTEXT next; /* The one we are waiting for */
- static PTEXT vtmp; /* For reorganizing linked list */
- static PTEXT comp_thru; /* We have all packets though */
- static int lp = -1; /* Opened UDP port */
- static int hdr_len; /* Header Length */
- static int nd_pkts; /* Number of packets we want */
- static int no_pkts; /* Number of packets we have */
- static int pkt_cid; /* Packet connection identifier */
- static unsigned short this_conn_id; /* Connection ID we are using */
- static unsigned short recvd_thru; /* Received through */
- static short priority; /* Priority for request */
- static short one = 0; /* Pointer to value 1 */
- static short zero = 0; /* Pointer to value 0 */
- static char *seqtxt; /* Pointer to text w/ sequence # */
- static struct sockaddr_in us; /* Our address */
- static struct sockaddr_in to; /* Address to send query */
- static struct sockaddr_in from; /* Reply received from */
- static int from_sz; /* Size of from structure */
- static struct hostent *host; /* Host info from gethostbyname */
- static long newhostaddr; /* New host address from *host */
- static int req_udp_port=0; /* Requested port (optional) */
- static char *openparen; /* Delimits port in name */
- static char hostnoport[500];/* Host name without port */
- static int ns; /* Number of bytes actually sent */
- static int nr; /* Number of bytes received */
- static SELECTARG readfds; /* Used for select */
- static int tmp;
- static char *ctlptr; /* Pointer to control field */
- static short stmp; /* Temp short for conversions */
- static int backoff; /* Server requested backoff */
- static unsigned char rdflag11; /* First byte of flags (bit vect)*/
- static unsigned char rdflag12; /* Second byte of flags (int) */
- static int scpflag = 0; /* Set if any sequencd cont pkts */
- static int ackpend = 0; /* Acknowledgement pending */
- static int gaps = 0; /* Gaps present in recvd pkts */
- static struct timeval timeout; /* Time to wait for response */
- static struct timeval ackwait; /* Time to wait before acking */
- static struct timeval gapwait; /* Time to wait b4 filling gaps */
- static struct timeval *selwait; /* Time to wait for select */
- static int retries; /* was = client_dirsrv_retry */
- char to_hostname[512]; /* lmjm: saves inet_ntoa() str */
- /* These are added so dirsend() "blocks" properly */
- static PTEXT dirsendReturn;
- static int dirsendDone;
- /* And here are the values for dirsendDone */
- #define DSRET_DONE 1
- #define DSRET_SEND_ERROR -1
- #define DSRET_RECV_ERROR -2
- #define DSRET_SELECT_ERROR -3
- #define DSRET_TIMEOUT -4
- #define DSRET_ABORTED -5
- /* New procedures to break up dirsend() */
- static int initDirsend();
- static void retryDirsend(), keepWaitingDirsend();
- static void timeoutProc();
- static void readProc();
- /* Wrappers around X calls to allow non-X usage */
- static void processEvent();
- /* Extra stuff for the asynchronous X version of dirsend() */
- typedef char *XtPointer;
- typedef char *XtInputId;
- typedef char *XtIntervalId;
- static XtInputId inputId;
- static XtIntervalId timerId = (XtIntervalId)0;
- /*
- * dirsend - send packet and receive response
- *
- * DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
- * and a pointer to a host address. It then sends the supplied
- * packet off to the directory server on the specified host. If
- * hostaddr points to a valid address, that address is used. Otherwise,
- * the hostname is looked up to obtain the address. If hostaddr is a
- * non-null pointer to a 0 address, then the address will be replaced
- * with that found in the hostname lookup.
- *
- * DIRSEND will wait for a response and retry an appropriate
- * number of times as defined by timeout and retries (both static
- * variables). It will collect however many packets form the reply, and
- * return them in a structure (or structures) of type PTEXT.
- *
- * DIRSEND will free the packet that it is presented as an argument.
- * The packet is freed even if dirsend fails.
- */
- PTEXT
- dirsend(pkt_p,hostname_p,hostaddr_p)
- PTEXT pkt_p;
- char *hostname_p;
- struct sockaddr_in *hostaddr_p;
- {
- /* copy parameters to globals since other routines use them */
- pkt = pkt_p;
- hostname = hostname_p;
- hostaddr = hostaddr_p;
- /* Do the initializations of formerly auto variables */
- first = NULL;
- lp = -1;
- one = 0;
- zero = 0;
- req_udp_port=0;
- scpflag = 0;
- ackpend = 0;
- gaps = 0;
- retries = client_dirsrv_retry;
- if (initDirsend() < 0)
- return(NULL);
- /* set the first timeout */
- retryDirsend();
- dirsendReturn = NULL;
- dirsendDone = 0;
- /* Until one of the callbacks says to return, keep processing events */
- while (!dirsendDone)
- processEvent();
- /* Return whatever we're supposed to */
- return(dirsendReturn);
- }
- /* - - - - - - - - */
- /* This function does all the initialization that used to be done at the
- * start of dirsend(), including opening the socket descriptor "lp". It
- * returns the descriptor if successful, otherwise -1 to indicate that
- * dirsend() should return NULL immediately.
- */
- static int
- initDirsend()
- {
- if(one == 0) one = htons((short) 1);
- priority = htons(rdgram_priority);
- timeout.tv_sec = client_dirsrv_timeout;
- timeout.tv_usec = 0;
- ackwait.tv_sec = 0;
- ackwait.tv_usec = 500000;
- gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
- gapwait.tv_usec = 0;
- comp_thru = NULL;
- perrno = 0;
- nd_pkts = 0;
- no_pkts = 0;
- pkt_cid = 0;
- /* Find first connection ID */
- if(next_conn_id == 0) {
- srand(getpid()+time(0)); /* XXX: arg ok, but not right type. */
- next_conn_id = rand();
- }
- /* If necessary, find out what udp port to send to */
- if (dir_udp_port == 0) {
- register struct servent *sp;
- tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
- #ifdef USE_ASSIGNED_PORT
- /* UCX needs 0 & -1 */
- sp = getservbyname("prospero","udp");
- if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
- #ifdef DEBUG
- if (pfs_debug)
- fprintf(stderr, "dirsrv: udp/prospero unknown service - using %dn",
- PROSPERO_PORT);
- #endif
- dir_udp_port = htons((u_short) PROSPERO_PORT);
- }
- #else
- /* UCX needs 0 & -1 */
- sp = getservbyname("dirsrv","udp");
- if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
- #ifdef DEBUG
- if (pfs_debug)
- fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %dn",
- DIRSRV_PORT);
- #endif
- dir_udp_port = htons((u_short) DIRSRV_PORT);
- }
- #endif
- else dir_udp_port = sp->s_port;
- pfs_enable = tmp;
- #ifdef DEBUG
- if (pfs_debug > 3)
- fprintf(stderr,"dir_udp_port is %dn", ntohs(dir_udp_port));
- #endif
- }
- /* If we were given the host address, then use it. Otherwise */
- /* lookup the hostname. If we were passed a host address of */
- /* 0, we must lookup the host name, then replace the old value */
- if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
- /* I we have a null host name, return an error */
- if((hostname == NULL) || (*hostname == ' ')) {
- #ifdef DEBUG
- if (pfs_debug)
- fprintf(stderr, "dirsrv: Null hostname specifiedn");
- #endif
- perrno = DIRSEND_BAD_HOSTNAME;
- ptlfree(pkt);
- /* return(NULL); */
- return(-1);
- }
- /* If a port is included, save it away */
- if((openparen = index(hostname,'('))) {
- sscanf(openparen+1,"%d",&req_udp_port);
- strncpy(hostnoport,hostname,400);
- if((openparen - hostname) < 400) {
- *(hostnoport + (openparen - hostname)) = ' ';
- hostname = hostnoport;
- }
- }
- tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
- if((host = gethostbyname(hostname)) == NULL) {
- pfs_enable = tmp;
- /* Check if a numeric address */
- newhostaddr = inet_addr(hostname);
- if(newhostaddr == -1) {
- #ifdef DEBUG
- if (pfs_debug)
- fprintf(stderr, "dirsrv: Can't resolve host %sn",hostname);
- #endif
- perrno = DIRSEND_BAD_HOSTNAME;
- ptlfree(pkt);
- /* return(NULL); */
- return(-1);
- }
- bzero((char *)&to, S_AD_SZ);
- to.sin_family = AF_INET;
- bcopy((char *)&newhostaddr, (char *)&to.sin_addr, 4);
- if(hostaddr) bcopy((char *)&to, (char *)hostaddr, S_AD_SZ);
- }
- else {
- pfs_enable = tmp;
- bzero((char *)&to, S_AD_SZ);
- to.sin_family = host->h_addrtype;
- bcopy((char *)host->h_addr, (char *)&to.sin_addr, host->h_length);
- if(hostaddr) bcopy((char *)&to, (char *)hostaddr, S_AD_SZ);
- }
- }
- else bcopy((char *)hostaddr, (char *)&to, S_AD_SZ);
- /* lmjm: Save away the hostname */
- strncpy(to_hostname, inet_ntoa(to.sin_addr), sizeof(to_hostname)-1);
- if(req_udp_port) to.sin_port = htons(req_udp_port);
- else to.sin_port = dir_udp_port;
- /* If a port was specified in hostaddr, use it, otherwise fill it in */
- if(hostaddr) {
- if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
- else hostaddr->sin_port = to.sin_port;
- }
- /* Must open a new port each time. we do not want to see old */
- /* responses to messages we are done with */
- if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- #ifdef DEBUG
- if (pfs_debug)
- fprintf(stderr,"dirsrv: Can't open socketn");
- #endif
- perrno = DIRSEND_UDP_CANT;
- ptlfree(pkt);
- /* return(NULL); */
- return(-1);
- }
- /* Try to bind it to a privileged port - loop through candidate */
- /* ports trying to bind. If failed, that's OK, we will let the */
- /* system assign a non-privileged port later */
- if(!notprived) {
- for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP;
- tmp++) {
- bzero((char *)&us, sizeof(us));
- us.sin_family = AF_INET;
- us.sin_port = htons((u_short) tmp);
- if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
- if(errno != EADDRINUSE) {
- notprived++;
- break;
- }
- }
- else break;
- }
- }
- #ifndef USE_V3_PROT
- /* Add header */
- if(rdgram_priority) {
- pkt->start -= 15;
- pkt->length += 15;
- *(pkt->start) = (char) 15;
- bzero(pkt->start+9,4);
- *(pkt->start+11) = 0x02;
- bcopy((char *)&priority, pkt->start+13,2);
- }
- else {
- pkt->start -= 9;
- pkt->length += 9;
- *(pkt->start) = (char) 9;
- }
- this_conn_id = htons(next_conn_id++);
- if(next_conn_id == 0) next_conn_id++;
- bcopy((char *)&this_conn_id, pkt->start+1,2);
- bcopy((char *)&one,pkt->start+3,2);
- bcopy((char *)&one,pkt->start+5,2);
- bzero(pkt->start+7,2);
- #endif
- #ifdef DEBUG
- if (pfs_debug > 2) {
- #ifndef USE_V3_PROT
- if (to.sin_family == AF_INET) {
- if(req_udp_port)
- fprintf(stderr,"Sending message to %s+%d(%d)...",
- to_hostname, req_udp_port, ntohs(this_conn_id));
- else fprintf(stderr,"Sending message to %s(%d)...",
- to_hostname, ntohs(this_conn_id));
- }
- #else
- if (to.sin_family == AF_INET)
- fprintf(stderr,"Sending message to %s...", to_hostname);
- #endif /* USE_V3_PROT */
- else
- fprintf(stderr,"Sending message...");
- (void) fflush(stderr);
- }
- #endif /* DEBUG */
- first = ptalloc();
- next = first;
- return(lp);
- }
- /* - - - - - - - - */
- /*
- * This used to be a label to goto to retry the last packet. Now we resend
- * the packet and call keepWaitingDirsend() to wait for a reply. (We
- * call keepWaitingDirsend() because formerly the code dropped through
- * the keep_waiting label.)
- */
- static void
- retryDirsend()
- {
- gaps = ackpend = 0;
- ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
- if(ns != pkt->length) {
- #ifdef DEBUG
- if (pfs_debug) {
- fprintf(stderr,"nsent only %d/%d: ",ns, pkt->length);
- perror("");
- }
- #endif
- close(lp);
- perrno = DIRSEND_NOT_ALL_SENT;
- ptlfree(first);
- ptlfree(pkt);
- /* pkt= NULL; */ /* added by NEC NWSL */
- /* return(NULL); */
- dirsendReturn = NULL;
- dirsendDone = DSRET_SEND_ERROR;
- }
- #ifdef DEBUG
- if (pfs_debug > 2) fprintf(stderr,"Sent.n");
- #endif
- keepWaitingDirsend();
- }
- /* - - - - - - - - */
- /*
- * This used to be a label to goto to set the appropriate timeout value
- * and blocked in select(). Now we set selwait and the SELECTARGs to the
- * appropriate values, and in X register a new timeout, then return to
- * allow event processing.
- */
- static void
- keepWaitingDirsend()
- {
- /* We come back to this point (by a goto) if the packet */
- /* received is only part of the response, or if the */
- /* response came from the wrong host */
- #ifdef DEBUG
- if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
- #endif
- FD_ZERO(&readfds);
- FD_SET(lp, &readfds);
- if(ackpend) selwait = &ackwait;
- else if(gaps) selwait = &gapwait;
- else selwait = &timeout;
- }
- /* - - - - - - - - */
- /*
- * This routine is called when a timeout occurs. It includes the code that
- * was formerly used when select() returned 0 (indicating a timeout).
- */
- /*ARGSUSED*/
- static void
- timeoutProc(client_data,id)
- XtPointer client_data;
- XtIntervalId *id;
- {
- if (gaps || ackpend) { /* Send acknowledgment */
- /* Acks are piggybacked on retries - If we have received */
- /* an ack from the server, then the packet sent is only */
- /* an ack and the rest of the message will be empty */
- #ifdef DEBUG
- if (pfs_debug > 2) {
- fprintf(stderr,"Acknowledging (%s).n",
- (ackpend ? "requested" : "gaps"));
- }
- #endif
- if (gaps && verbose)
- fprintf (stderr, "Searching...n");
- retryDirsend();
- return;
- }
- if (retries-- > 0) {
- timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
- #ifdef DEBUG
- if (pfs_debug > 2) {
- fprintf(stderr,"Timed out. Setting timeout to %d seconds.n",
- (int)timeout.tv_sec);
- }
- #endif
- retryDirsend();
- return;
- }
- #ifdef DEBUG
- if (pfs_debug) {
- fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
- *(int *)&readfds);
- perror("");
- }
- #endif
- close(lp);
- perrno = DIRSEND_SELECT_FAILED;
- ptlfree(first);
- ptlfree(pkt);
- /* return(NULL); */
- dirsendReturn = NULL;
- dirsendDone = DSRET_TIMEOUT;
- }
- /* - - - - - - - - */
- /*
- * This function is called whenever there's something to read on the
- * connection. It includes the code that was run when select() returned
- * greater than 0 (indicating read ready).
- */
- /*ARGSUSED*/
- static void
- readProc(client_data,source,id)
- XtPointer client_data;
- int *source;
- XtInputId *id;
- {
- from_sz = sizeof(from);
- next->start = next->dat;
- if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
- #ifdef DEBUG
- if (pfs_debug) perror("recvfrom");
- #endif
- close(lp);
- perrno = DIRSEND_BAD_RECV;
- ptlfree(first);
- ptlfree(pkt);
- /* return(NULL) */
- dirsendReturn = NULL;
- dirsendDone = DSRET_RECV_ERROR;
- return;
- }
- next->length = nr;
- next->start[next->length] = 0;
- #ifdef DEBUG
- if (pfs_debug > 2)
- fprintf(stderr,"Received packet from %sn", inet_ntoa(from.sin_addr));
- #endif
- /* For the current format, if the first byte is less than */
- /* 20, then the first two bits are a version number and the next six */
- /* are the header length (including the first byte). */
- if((hdr_len = (unsigned char) *(next->start)) < 20) {
- ctlptr = next->start + 1;
- next->seq = 0;
- if(hdr_len >= 3) { /* Connection ID */
- bcopy(ctlptr, (char *)&stmp,2);
- if(stmp) pkt_cid = ntohs(stmp);
- ctlptr += 2;
- }
- if (pkt_cid<0)
- pkt_cid = 65536+pkt_cid;
- if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
- /* The packet is not for us */
- /* goto keep_waiting; */
- #ifdef DEBUG
- if (pfs_debug > 20)
- fprintf(stderr,"Packet not for us %d,%d,%dn",
- pkt_cid,this_conn_id,ntohs(this_conn_id));
- #endif
- keepWaitingDirsend();
- return;
- }
- if(hdr_len >= 5) { /* Packet number */
- bcopy(ctlptr, (char *)&stmp,2);
- next->seq = ntohs(stmp);
- ctlptr += 2;
- }
- else { /* No packet number specified, so this is the only one */
- next->seq = 1;
- nd_pkts = 1;
- }
- if(hdr_len >= 7) { /* Total number of packets */
- bcopy(ctlptr, (char *)&stmp,2); /* 0 means don't know */
- if(stmp) nd_pkts = ntohs(stmp);
- ctlptr += 2;
- }
- if(hdr_len >= 9) { /* Receievd through */
- bcopy(ctlptr, (char *)&stmp,2); /* 1 means received request */
- #ifndef USE_V3_PROT
- if((stmp) && (ntohs(stmp) == 1)) {
- /* Future retries will be acks only */
- pkt->length = 9;
- bcopy((char *)&zero, pkt->start+3,2);
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Server acked request - retries will be acks onlyn");
- #endif
- }
- #endif
- ctlptr += 2;
- }
- if(hdr_len >= 11) { /* Backoff */
- bcopy(ctlptr, (char *)&stmp,2);
- if(stmp) {
- backoff = (short) ntohs(stmp);
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Backing off to %d secondsn", backoff);
- #endif
- timeout.tv_sec = backoff;
- if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
- /* Probably a long queue on the server - don't give up */
- retries = client_dirsrv_retry;
- }
- }
- ctlptr += 2;
- }
- if(hdr_len >= 12) { /* Flags (1st byte) */
- bcopy(ctlptr, (char *)&rdflag11,1);
- if(rdflag11 & 0x80) {
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Ack requestedn");
- #endif
- ackpend++;
- }
- if(rdflag11 & 0x40) {
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Sequenced control packetn");
- #endif
- next->length = -1;
- scpflag++;
- }
- ctlptr += 1;
- }
- if(hdr_len >= 13) { /* Flags (2nd byte) */
- /* Reserved for future use */
- bcopy(ctlptr, (char *)&rdflag12,1);
- ctlptr += 1;
- }
- if(next->seq == 0) {
- /* goto keep_waiting; */
- keepWaitingDirsend();
- return;
- }
- if(next->length >= 0) next->length -= hdr_len;
- next->start += hdr_len;
- goto done_old;
- }
- pkt_cid = 0;
- /* if intermediate format (between old and new), then process */
- /* and go to done_old */
- ctlptr = next->start + max(0,next->length-20);
- while(*ctlptr) ctlptr++;
- /* Control fields start after the terminating null */
- ctlptr++;
- /* Until old version are gone, must be 4 extra bytes minimum */
- /* When no version 3 servers, can remove the -4 */
- if(ctlptr < (next->start + next->length - 4)) {
- /* Connection ID */
- bcopy(ctlptr, (char *)&stmp,2);
- if(stmp) pkt_cid = ntohs(stmp);
- ctlptr += 2;
- if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
- /* The packet is not for us */
- /* goto keep_waiting; */
- keepWaitingDirsend();
- return;
- }
- /* Packet number */
- if(ctlptr < (next->start + next->length)) {
- bcopy(ctlptr, (char *)&stmp,2);
- next->seq = ntohs(stmp);
- ctlptr += 2;
- }
- /* Total number of packets */
- if(ctlptr < (next->start + next->length)) {
- bcopy(ctlptr, (char *)&stmp,2);
- if(stmp) nd_pkts = ntohs(stmp);
- ctlptr += 2;
- }
- /* Receievd through */
- if(ctlptr < (next->start + next->length)) {
- /* Not supported by clients */
- ctlptr += 2;
- }
- /* Backoff */
- if(ctlptr < (next->start + next->length)) {
- bcopy(ctlptr, (char *)&stmp,2);
- backoff = ntohs(stmp);
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Backing off to %d secondsn", backoff);
- #endif
- if (verbose && backoff)
- fprintf (stderr, "Searching...n");
- if(backoff) timeout.tv_sec = backoff;
- ctlptr += 2;
- }
- if(next->seq == 0) {
- /* goto keep_waiting; */
- keepWaitingDirsend();
- return;
- }
- goto done_old;
- }
- /* Notes that we have to start searching 11 bytes before the */
- /* expected start of the MULTI-PACKET line because the message */
- /* might include up to 10 bytes of data after the trailing null */
- /* The order of those bytes is two bytes each for Connection ID */
- /* Packet-no, of, Received-through, Backoff */
- seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET");
- if(seqtxt) seqtxt+= 13;
- if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
- tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
- #ifdef DEBUG
- if (pfs_debug && (tmp == 0))
- fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);
- #endif
- done_old:
- #ifdef DEBUG
- if(pfs_debug > 2) fprintf(stderr,"Packet %d of %dn",next->seq,nd_pkts);
- #endif
- if ((first == next) && (no_pkts == 0)) {
- if(first->seq == 1) {
- comp_thru = first;
- /* If only one packet, then return it */
- if(nd_pkts == 1) goto all_done;
- }
- else gaps++;
- no_pkts = 1;
- next = ptalloc();
- /* goto keep_waiting; */
- keepWaitingDirsend();
- return;
- }
- if(comp_thru && (next->seq <= comp_thru->seq))
- ptfree(next);
- else if (next->seq < first->seq) {
- vtmp = first;
- first = next;
- first->next = vtmp;
- first->previous = NULL;
- vtmp->previous = first;
- if(first->seq == 1) comp_thru = first;
- no_pkts++;
- }
- else {
- vtmp = (comp_thru ? comp_thru : first);
- while (vtmp->seq < next->seq) {
- if(vtmp->next == NULL) {
- vtmp->next = next;
- next->previous = vtmp;
- next->next = NULL;
- no_pkts++;
- goto ins_done;
- }
- vtmp = vtmp->next;
- }
- if(vtmp->seq == next->seq)
- ptfree(next);
- else {
- vtmp->previous->next = next;
- next->previous = vtmp->previous;
- next->next = vtmp;
- vtmp->previous = next;
- no_pkts++;
- }
- }
- ins_done:
- while(comp_thru && comp_thru->next &&
- (comp_thru->next->seq == (comp_thru->seq + 1))) {
- comp_thru = comp_thru->next;
- #ifndef USE_V3_PROT
- recvd_thru = htons(comp_thru->seq);
- bcopy((char *)&recvd_thru,pkt->start+7,2); /* Let server know we got it */
- #endif
- /* We've made progress, so reset retry count */
- retries = client_dirsrv_retry;
- /* Also, next retry will be only an acknowledgement */
- /* but for now, we can't fill in the ack field */
- #ifdef DEBUG
- if(pfs_debug > 2)
- fprintf(stderr,"Packets now received through %dn",comp_thru->seq);
- #endif
- }
- /* See if there are any gaps */
- if(!comp_thru || comp_thru->next) gaps++;
- else gaps = 0;
- if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
- next = ptalloc();
- /* goto keep_waiting; */
- keepWaitingDirsend();
- return;
- }
- all_done:
- if(ackpend) { /* Send acknowledgement if requested */
- #ifdef DEBUG
- if (pfs_debug > 2) {
- if (to.sin_family == AF_INET)
- fprintf(stderr,"Acknowledging final packet to %s(%d)n",
- to_hostname, ntohs(this_conn_id));
- else
- fprintf(stderr,"Acknowledging final packetn");
- (void) fflush(stderr);
- }
- #endif
- ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
- if(ns != pkt->length) {
- #ifdef DEBUG
- if (pfs_debug) {
- fprintf(stderr,"nsent only %d/%d: ",ns, pkt->length);
- perror("");
- }
- #endif
- }
- }
- close(lp);
- ptlfree(pkt);
- /* Get rid of any sequenced control packets */
- if(scpflag) {
- while(first && (first->length < 0)) {
- vtmp = first;
- first = first->next;
- if(first) first->previous = NULL;
- ptfree(vtmp);
- }
- vtmp = first;
- while(vtmp && vtmp->next) {
- if(vtmp->next->length < 0) {
- if(vtmp->next->next) {
- vtmp->next = vtmp->next->next;
- ptfree(vtmp->next->previous);
- vtmp->next->previous = vtmp;
- }
- else {
- ptfree(vtmp->next);
- vtmp->next = NULL;
- }
- }
- vtmp = vtmp->next;
- }
- }
- /* return(first); */
- dirsendReturn = first;
- dirsendDone = DSRET_DONE;
- }
- static void
- processEvent()
- {
- /* select - either recv is ready, or timeout */
- /* see if timeout or error or wrong descriptor */
- tmp = select(lp + 1, &readfds, (SELECTARG *)0, (SELECTARG *)0, selwait);
- if (tmp == 0) {
- timeoutProc(NULL,&timerId);
- } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
- #ifdef DEBUG
- if (pfs_debug) {
- fprintf(stderr, "select failed(processEvent): readfds=%x ",
- *(int *)&readfds);
- perror("");
- }
- #endif
- close(lp);
- perrno = DIRSEND_SELECT_FAILED;
- ptlfree(first);
- ptlfree(pkt);
- /* return(NULL); */
- dirsendReturn = NULL;
- dirsendDone = DSRET_SELECT_ERROR;
- } else {
- readProc(NULL,&lp,&inputId);
- }
- }
- void
- abortDirsend()
- {
- if (!dirsendDone) {
- close(lp);
- ptlfree(first);
- ptlfree(pkt);
- dirsendReturn = NULL;
- dirsendDone = DSRET_ABORTED;
- }
- return;
- }