📄 dirsend.c
字号:
/* 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 DEBUGextern int pfs_debug;#endifextern 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. */PTEXTdirsend(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 intinitDirsend(){ 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 %d\n", 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 %d\n", 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 %d\n", 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 == '\0')) {#ifdef DEBUG if (pfs_debug) fprintf(stderr, "dirsrv: Null hostname specified\n");#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)) = '\0'; 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 %s\n",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 socket\n");#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 voidretryDirsend(){ 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 voidkeepWaitingDirsend(){ /* 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -