diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2020-05-21 18:41:12 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2020-05-21 18:41:12 (GMT) |
commit | 38fc67b0d117a0b84264b8fe1cf4776567deea7a (patch) | |
tree | c0134726c957cd68b8a158494fc4daeca44ff460 /xpa/client.c | |
parent | 1ab8762e64446c716427e10aab027a3df92212c6 (diff) | |
download | blt-38fc67b0d117a0b84264b8fe1cf4776567deea7a.zip blt-38fc67b0d117a0b84264b8fe1cf4776567deea7a.tar.gz blt-38fc67b0d117a0b84264b8fe1cf4776567deea7a.tar.bz2 |
upgrade xpa
Diffstat (limited to 'xpa/client.c')
-rw-r--r-- | xpa/client.c | 3057 |
1 files changed, 0 insertions, 3057 deletions
diff --git a/xpa/client.c b/xpa/client.c deleted file mode 100644 index f70ff40..0000000 --- a/xpa/client.c +++ /dev/null @@ -1,3057 +0,0 @@ -/* - * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory - */ - -#include <xpap.h> - -/* - *---------------------------------------------------------------------------- - * - * - * Private Routines and Data - * - * - *---------------------------------------------------------------------------- - */ - -/* this is the head of the global list of client xpas */ -static XPA xpaclienthead=NULL; - -static char errbuf[SZ_LINE]; /* holds current error message */ -static int id=0; /* id of current command */ - -#define DATA_CONNECT 1 -#define DATA_ACCEPT 2 -#define DATA_DATA 4 - -/* use of a double fork() call is used to prevent zombies which happen - if fork is a child of xpans started by an XPA server (i.e., for some - reason, the SIGCHLD signal does not get sent to xpans parent) - See Stevens, Advanced Programming in te Unix Environment, p. 202 */ -#define USE_DOUBLE_FORK 1 -#ifndef USE_DOUBLE_FORK -#ifdef ANSI_FUNC -void sig_chld(int signo) -#else -#endif -{ - int stat; - - while(waitpid(-1, &stat, WNOHANG) > 0){ - ; - } - return; -} -#endif - -/* - *---------------------------------------------------------------------------- - * - * Routine: rdl - * - * Purpose: read characters up a new-line - * - * Returns: number of characters read - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -rdl (int fd, char *buf, size_t len) -#else -static int rdl(fd, buf, len) - int fd; - char *buf; - int len; -#endif -{ - int i=0; - int got; - - /* start out clean */ - *buf = '\0'; - - /* make sure we have a valid channel */ - if( fd < 0 ) - return(-1); - - /* grab characters up to a new-line or max len */ - while( i < (len-1) ){ - got = read(fd, &(buf[i]), 1); - if( got < 1 ) - break; - else if( buf[i++] == '\n' ) - break; - } - buf[i] = '\0'; - return(i); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAProxyAccept - * - * Purpose: accept a connection from an XPA proxy server - * - * Return: fd of accepted connection or -1 - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static -int XPAProxyAccept(XPA xpa, char *method, char *xclass, char *name, int ifd, - unsigned int *rip, unsigned short *rport, char *rname) -#else -static -int XPAProxyAccept(xpa, method, xclass, name, ifd, rip, rport, rname) - XPA xpa; - char *method; - char *xclass; - char *name; - int ifd; - unsigned int *rip; - unsigned short *rport; - char *rname; -#endif -{ - int sock; - int got; - int oum; - int ofd; - int niter; - int swidth=FD_SETSIZE; - int keep_alive=1; - int reuse_addr=1; - unsigned int ip; - unsigned short port; - char tbuf[SZ_LINE]; - char amethod[SZ_LINE]; - char *tptr; - socklen_t slen; - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - struct timeval tv; - struct timeval *tvp; - fd_set readfds; - - /* initialize results */ - if( rip ) *rip = 0; - if( rport ) *rport = 0; - if( rname ) *rname = '\0'; - - switch(XPAMethod(method)){ - case XPA_INET: - if( !XPAParseIpPort(method, &ip, &port) ){ - goto error; - } - /* open a socket for data connections */ - if( (sock = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ - PERROR(("xpaaccept socket")); - goto error; - } - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&reuse_addr, sizeof(reuse_addr)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = htonl(INADDR_ANY); - sock_in.sin_port = htons(port); - /* bind to the ip:port */ - if( xbind(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ - PERROR(("xpaaccept bind")); - xclose(sock); - goto error; - } - snprintf(amethod, SZ_LINE, "%x:%d", ip, port); - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - ip = 0; - port = 0; - /* get filename part, composed of class and name and unique id */ - snprintf(tbuf, SZ_LINE, "%s_%s.%d", xclass, name, (int)time(NULL)); - /* change "/" to "_" for filename */ - for(tptr = tbuf; *tptr != '\0'; tptr++){ - if( *tptr == '/' ) *tptr = '_'; - } - /* create full pathname */ - snprintf(amethod, SZ_LINE, "%s/%s", XPATmpdir(), tbuf); - /* delete old copy */ - unlink (amethod); - /* open a socket and fill in socket information */ - if( (sock = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ - goto error; - } - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_un, 0, sizeof(sock_un)); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, amethod); - /* unset umask so that everyone can read and write */ - oum = umask(0); - /* bind to the file */ - got = xbind(sock, (struct sockaddr *)&sock_un, sizeof(sock_un)); - /* reset umask to previous */ - umask(oum); - /* now check for bind error */ - if( got < 0 ){ - xclose(sock); - goto error; - } - break; -#endif - default: - goto error; - } - - /* send port to client so they can connect */ - /* first listen for the connection */ - if( listen(sock, XPA_MAXLISTEN) < 0 ){ - PERROR(("xpaaccept listen")); - xclose(sock); - goto error; - } - - /* and tell the client that we are listening */ - snprintf(tbuf, SZ_LINE, "xpaaccept %s (%s:%s %s)\n", - amethod, xclass, name, method); - FPRINTF((stderr, "%sXPAProxyAccept: sending command to %d:\n%s", - _sp, ifd, tbuf)); - if( XPAPuts(NULL, ifd, tbuf, XPAShortTimeout()) <= 0 ){ - PERROR(("client xpaaccept write")); - xclose(sock); - goto error; - } - - /* we will iterate on xselect */ - if( XPAShortTimeout() > 0 ) - niter = XPAShortTimeout()*100; - else - niter = XPA_SHORT_TIMEOUT*100; -again: - /* this has to be able to time out */ - tv.tv_sec = 0; - tv.tv_usec = 10000; - tvp = &tv; - /* wait for this socket and XPA sockets */ - FD_ZERO(&readfds); - FD_SET(sock, &readfds); - XPAAddSelect(NULL, &readfds); - /* wait for the connection */ - got = xselect(swidth, &readfds, NULL, NULL, tvp); - /* process results of select */ - if( got > 0 ){ - if( !FD_ISSET(sock, &readfds)){ - XPAProcessSelect(&readfds, 0); - goto again; - } - switch(XPAMethod(method)){ - case XPA_INET: - while( 1 ){ - slen = sizeof(struct sockaddr_in); - if((ofd=xaccept(sock, (struct sockaddr *)&sock_in, &slen)) >= 0){ - break; - } - else{ - if( xerrno == EINTR ) - continue; - else{ - PERROR(("xpaaccept acccept")); - xclose(sock); - goto error; - } - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - while( 1 ){ - slen = sizeof(struct sockaddr_un); - if((ofd=xaccept(sock, (struct sockaddr *)&sock_un, &slen)) >= 0){ - break; - } - else{ - if( xerrno == EINTR ) - continue; - else{ - PERROR(("xpaaccept acccept")); - xclose(sock); - goto error; - } - } - } - break; -#endif - default: - xclose(sock); - goto error; - } - } - /* timeout? */ - else if( got == 0 ){ - if( --niter > 0 ){ - goto again; - } - else{ - xclose(sock); - FPRINTF((stderr, "%sXPAProxyAccept: select timed out\n", _sp)); - goto error; - } - } - /* error */ - else{ - if( xerrno == EINTR ){ - PERROR(("xpaaccept select")); - goto again; - } - else{ - xclose(sock); - goto error; - } - } - /* done with listening */ - xclose(sock); - - /* fill in return information */ - if( rip ) *rip = ip; - if( rport ) *rport = port; - if( rname ){ - strncpy(rname, amethod, SZ_LINE-1); - rname[SZ_LINE-1] = '\0'; - } - return(ofd); - -error: - return(-1); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientNewInput - * - * Purpose: allocate a new input struct for reading data from stdin - * - * Return: input struct, or NULL on error - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static XPAInput -XPAClientNewInput(XPA xpa) -#else -static XPAInput XPAClientNewInput(xpa) - XPA xpa; -#endif -{ - XPAInput xnew, inp; - - /* allocate a new record */ - if( (xnew=(XPAInput)xcalloc(1, sizeof(XPAInputRec))) == NULL ){ - return(NULL); - } - /* allocate the data buffer */ - xnew->buf = (char *)xmalloc(XPA_BIOSIZE); - /* this buffer starts (and currently ends) at the current byte count */ - xnew->start = xpa->inpbytes; - xnew->end = xpa->inpbytes; - xnew->bytes = 0; - - /* add this input to end of list of input's */ - if( xpa->inphead == NULL ){ - xpa->inphead = xnew; - } - else{ - for(inp=xpa->inphead; inp->next!=NULL; inp=inp->next) - ; - inp->next = xnew; - } - - /* return the record struct */ - return(xnew); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientFreeInput - * - * Purpose: free a input buffer once its been sent to all targets - * - * Return: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -XPAClientFreeInput (XPA xpa, XPAInput inp) -#else -static void XPAClientFreeInput(xpa, inp) - XPA xpa; - XPAInput inp; -#endif -{ - XPAInput cur; - - if( !xpa || !inp ) - return; - - if( inp == xpa->inphead ){ - xpa->inphead = inp->next; - } - else{ - for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ - if( cur->next == inp ){ - cur->next = inp->next; - break; - } - } - } - - /* free current record */ - if( inp != NULL ){ - if( inp->buf != NULL ) - xfree(inp->buf ); - xfree(inp); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientFreeAllInputs - * - * Purpose: free remaining input buffers - * - * Return: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -XPAClientFreeAllInputs (XPA xpa) -#else -static void XPAClientFreeAllInputs(xpa) - XPA xpa; -#endif -{ - XPAInput cur, tmp; - - if( !xpa ) - return; - - for(cur=xpa->inphead; cur!=NULL; ){ - tmp = cur->next; - XPAClientFreeInput(xpa, cur); - cur = tmp; - } - xpa->inpbytes = 0; -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientProcessInput - * - * Purpose: read input from stdin and store in an input struct - * - * Return: bytes read - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientProcessInput(XPA xpa) -#else -static int XPAClientProcessInput(xpa) - XPA xpa; -#endif -{ - static XPAInput cur=NULL; - int get, got; - - /* set up next buffer, if necessary */ - for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ - if( cur->bytes < XPA_BIOSIZE ) - break; - } - if( cur == NULL ){ - cur = XPAClientNewInput(xpa); - } - - /* read data from stdin */ - get = MIN(XPA_IOSIZE, XPA_BIOSIZE - cur->bytes); - if( isatty(xpa->ifd) ){ - got = rdl(xpa->ifd, &(cur->buf[cur->bytes]), get); - } - else{ - got = read(xpa->ifd, &(cur->buf[cur->bytes]), get); - } - switch(got){ - case -1: - if( XPAVerbosity() ){ - PERROR(("XPA client read")); - } - return(0); - case 0: - xpa->ifd = -1; - FPRINTF((stderr, "%sXPAClientProcessInput: signalling EOF\n", _sp)); - break; - default: - break; - } - cur->bytes += got; - cur->end += got; - xpa->inpbytes += got; -#ifdef FIXEDBYCYGWIN -#if HAVE_CYGWIN - /* on non-NT Windows machines, Cygwin select() does not work once a pipe - gets EOF. It should show the fd ready for reading (and read 0 bytes), - but does not, so we have to hack a manual check */ - /* GetVersion is a Windows call */ - if( GetVersion() >= 0x80000000L ){ - if( got < get ){ - xpa->ifd = -1; - } - } -#endif -#endif - - /* verify to stdout, if necessary */ - if( xpa->client_mode & XPA_CLIENT_VERIFY ){ - fwrite(&(cur->buf[cur->bytes-got]), sizeof(char), got, stdout); - } - - /* return the number of bytes just read */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientFree - * - * Purpose: free a client record and remove from list - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -XPAClientFree (XPA xpa, XPAClient client) -#else -static void XPAClientFree(xpa, client) - XPA xpa; - XPAClient client; -#endif -{ - XPAClient cur; - - /* remove from list of xpa's */ - if( xpa->clienthead ){ - if( xpa->clienthead == client ){ - xpa->clienthead = client->next; - } - else{ - for(cur=xpa->clienthead; cur!=NULL; cur=cur->next){ - if( cur->next == client ){ - cur->next = client->next; - break; - } - } - } - } - - if( client->cmdfd >= 0 ){ -#if HAVE_CYGWIN - shutdown(client->cmdfd, SHUT_RDWR); -#endif - xclose(client->cmdfd); - } - if( client->datafd >= 0 ){ -#if HAVE_CYGWIN - shutdown(client->datafd, SHUT_RDWR); -#endif - xclose(client->datafd); - } - if( client->dataname ){ - unlink(client->dataname); - xfree(client->dataname); - } - if( client->method ) - xfree(client->method); - if( client->info ) - xfree(client->info); - if( client->xtemplate ) - xfree(client->xtemplate); - if( client->xclass ) - xfree(client->xclass); - if( client->name ) - xfree(client->name); - if( client->id ) - xfree(client->id); - /* xpaget's fd mode has an alloc'ed bufptr and lenptr */ - if( (client->type == 'g') && (client->mode & XPA_CLIENT_FD) ){ - if( client->bufptr && *(client->bufptr) ) - xfree(*(client->bufptr)); - if( client->bufptr ) - xfree(client->bufptr); - if( client->lenptr ) - xfree(client->lenptr); - } - xfree(client); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientDataSent - * - * Purpose: data is sent, so close data channel and change status to - * signal that we are waiting for the server - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -XPAClientDataSent (XPA xpa, XPAClient client) -#else -static void XPAClientDataSent(xpa, client) - XPA xpa; - XPAClient client; -#endif -{ - FPRINTF((stderr, "%sXPAClientDataSent: for cmd %d data %d\n", _sp, - client->cmdfd, client->datafd)); - /* close the data channel, which should trigger a result from the server */ - if( client->datafd >= 0 ){ -#if HAVE_CYGWIN - shutdown(client->datafd, SHUT_RDWR); -#endif - xclose(client->datafd); - client->datafd = -1; - } - /* we are now waiting for the server to complete the calllback */ - client->status = XPA_CLIENT_WAITING; -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientEnd - * - * Purpose: finish up with this client - * - * Returns: error message or null - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static char * -XPAClientEnd (XPA xpa, XPAClient client) -#else -static char *XPAClientEnd(xpa, client) - XPA xpa; - XPAClient client; -#endif -{ - char *error=NULL; - char *eptr; - - FPRINTF((stderr, "%sXPAClientEnd: for cmd %d data %d\n", _sp, - client->cmdfd, client->datafd)); - /* always read the status line -- if we are not ack'ing, we'll get an - OK from the server before the calllback and we can exit quickly */ - /* don't do this if client is xpainfo and we're not ack'ing */ - if( !((client->type == 'i') && !(client->mode & XPA_CLIENT_ACK)) ){ -retry: - if( XPAGets(NULL, client->cmdfd, errbuf, SZ_LINE, XPALongTimeout()) >0 ){ - FPRINTF((stderr, "%sXPAClientEnd: read %s\n", _sp, errbuf)); - eptr = errbuf; - /* this should never happen */ - if( *eptr == '?' ){ - snprintf(errbuf, SZ_LINE, - "XPA$WARNING: protocol mismatch - missing id\n%s", eptr); - error = NULL; - } - else{ - /* make sure we are dealing with a proper message */ - if( strncmp(eptr, client->id, strlen(client->id)) ){ - if( XPAVerbosity() > 1 ){ - fprintf(stderr, - "XPA$WARNING: ignoring out of sync server message:\n"); - fprintf(stderr, "%s", errbuf); - } - goto retry; - } - /* go past id */ - eptr += strlen(client->id); - while( isspace((int)*eptr) ) eptr++; - if( !strncmp(eptr, "XPA$OK", 6) ){ - error = NULL; - } - else{ - error = eptr; - } - } - } - else{ - if( XPAVerbosity() > 1 ){ - fprintf(stderr, - "XPA$WARNING: no reply from server callback (assuming OK)\n"); - } - error = NULL; - } - } - else - error = NULL; - - /* store the error return */ - if( client->errptr ) - *(client->errptr) = xstrdup(error); - - /* remove this client if we are not meant to persist */ - if( !xpa->persist ){ - XPAClientFree(xpa, client); - } - /* otherwise mark as inactive */ - else{ - client->status = XPA_CLIENT_IDLE; - client->bytes = 0; - } - - /* return error status */ - return(error); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientNew - * - * Purpose: allocate a new xpa client - * - * Returns: xpa client struct - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static XPAClient -XPAClientNew (XPA xpa, char *mode, char *xtemplate, int type, - char *xclass, char *name, char *method, char *info) -#else -static XPAClient XPAClientNew(xpa, mode, xtemplate, type, - xclass, name, method, info) - XPA xpa; - char *mode; - char *xtemplate; - int type; - char *xclass; - char *name; - char *method; - char *info; -#endif -{ - XPAClient xnew, client; - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - char xmode[SZ_LINE]; - char tbuf[SZ_LINE]; - char amethod[SZ_LINE]; - char *s=NULL; - unsigned short port; - unsigned int ip=0; - int fd; - int pfd; - int tries=0; - int nsproxy=0; - int keep_alive=1; - - FPRINTF((stderr, "%sXPAClientNew: entering with %s %s %s %s\n", _sp, - xclass, name, method, info)); - - /* no errors as yet */ - *errbuf = '\0'; - - /* look for reuse of xpans fd (used in conjunction with the xpans proxy) */ - *xmode = '\0'; - if( mode ){ - strncpy(xmode, mode, SZ_LINE-1); - xmode[SZ_LINE-1] = '\0'; - } - if( keyword(xmode, "nsproxy", tbuf, SZ_LINE) ){ - nsproxy = 1; - pfd = strtol(tbuf, &s, 0); - fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), - xclass, name, pfd, &ip, &port, amethod); - /* make sure we got a valid int fd */ - if( fd < 0 ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server on proxyaccept (%s:%s%s)\n", - xclass, name, XPATimestamp()); - FPRINTF((stderr, "%sXPAClientNew: %s", _sp, errbuf)); - PERROR(("XPAClientNew")); - return(NULL); - } - } - /* normal usage: connect to server */ - else{ - switch(XPAMethod(method)){ - case XPA_INET: -again1: - if( !XPAParseIpPort(method, &ip, &port) ) - return(NULL); - /* use $localhost over $host (we do not trust host to be correct) */ - if( (ip == gethostip("$host")) && (tries == 0) ) - ip = gethostip("$localhost"); - /* connect to the server before we go further */ - if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ - return(NULL); - } - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = htonl(ip); - sock_in.sin_port = htons(port); - /* make the connection with the server */ - if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) <0 ){ - xclose(fd); - /* if localhost doesn't work, make one try with the host ip */ - /* we also try again just in case there was an odd error such - as "permission denied", which we have seen once or twice */ - if( tries < 2 ){ - tries++; - goto again1; - } - /* give up */ - else{ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server on connect (%s:%s%s)\n", - xclass, name, XPATimestamp()); - PERROR(("XPAClientNew")); - return(NULL); - } - } - /* make sure we close on exec */ - xfcntl(fd, F_SETFD, FD_CLOEXEC); - FPRINTF((stderr, "%sXPAClientNew: inet connect returns fd %d\n", - _sp, fd)); - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: -again2: - /* open a socket and fill in socket information */ - if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ - return(NULL); - } - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_un, 0, sizeof(sock_un)); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, method); - /* make the connection with the server */ - if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) <0 ){ - xclose(fd); - /* Unix sockets get ECONNREFUSED when the listen queue is full, - so we try a few times to give the server a chance to recover */ - if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ - tries++; - XPASleep(10); - goto again2; - } - /* give up */ - else{ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server on connect (%s:%s%s)\n", - xclass, name, XPATimestamp()); - PERROR(("XPAClientNew")); - return(NULL); - } - } - /* make sure we close on exec */ - xfcntl(fd, F_SETFD, FD_CLOEXEC); - FPRINTF((stderr, "%sXPAClientNew: unix connect returns fd %d\n", - _sp, fd)); - break; -#endif - default: - return(NULL); - } - strncpy(amethod, method, SZ_LINE-1); - amethod[SZ_LINE-1] = '\0'; - } - - /* allocate new send record */ - if( (xnew=(XPAClient)xcalloc(1, sizeof(XPAClientRec))) == NULL ){ - xclose(fd); - return(NULL); - } - - /* fill in the blanks */ - xnew->xtemplate = xstrdup(xtemplate); - xnew->type = type; - xnew->cmdfd = fd; - xnew->datafd = -1; - xnew->xclass = xstrdup(xclass); - xnew->name = xstrdup(name); - xnew->method = xstrdup(amethod); - xnew->info = xstrdup(info); - xnew->ip = ip; - xnew->nsproxy = nsproxy; - xnew->status = XPA_CLIENT_ACTIVE; - - /* now that we have a valid client, add to list */ - if( xpa->clienthead == NULL ){ - xpa->clienthead = xnew; - } - else{ - for(client=xpa->clienthead; client->next!=NULL; client=client->next) - ; - client->next = xnew; - } - FPRINTF((stderr, "%sXPAClientNew: new fd %d\n", _sp, xnew->cmdfd)); - /* return the good news */ - return(xnew); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientAddSelect - * - * Purpose: add one or more xpa client sockets to the select flags - * - * Return: number of clients that were added to the select flags - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAClientAddSelect (XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr) -#else -int XPAClientAddSelect(xpa, readfdsptr, writefdsptr) - XPA xpa; - fd_set *readfdsptr; - fd_set *writefdsptr; -#endif -{ - XPAClient client; - int got=0; - int loop=0; - - /* better have some place to set the flags */ - if( readfdsptr == NULL ) - return(0); - - /* if no xpa is specified, do them all */ - if( xpa == NULL ){ - if( xpaclienthead == NULL ) return(0); - xpa = xpaclienthead; - loop = 1; - } - -loop: - /* set select flags for all clients */ - for(client=xpa->clienthead; client!=NULL; client=client->next){ - /* if this client is processing */ - if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >= 0) ){ - if( client->type == 'g' ){ - FPRINTF((stderr, "%sXPAClientAddSelect(get): adding fd %d\n", _sp, - client->datafd)); - FD_SET(client->datafd, readfdsptr); - got++; - } - else if( client->type == 's' ){ - FPRINTF((stderr, "%sXPAClientAddSelect(set): adding fd %d\n", _sp, - client->datafd)); - FD_SET(client->datafd, writefdsptr); - got++; - } - } - /* if this client is waiting */ - else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ - FPRINTF((stderr, "%sXPAClientAddSelect(waiting): adding fd %d\n", _sp, - client->cmdfd)); - FD_SET(client->cmdfd, readfdsptr); - got++; - } - } - /* loop if necessary */ - if( loop && (xpa=xpa->next) ) goto loop; - /* return the news */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientGet - * - * Purpose: process an xpaget request for a given client - * - * Return: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientGet (XPA xpa, XPAClient client) -#else -static int XPAClientGet(xpa, client) - XPA xpa; - XPAClient client; -#endif -{ - int status; - char tbuf[SZ_LINE]; - - /* allocate the first buffer, if necessary */ - if( *(client->bufptr) == NULL ){ - client->bufsize = XPA_IOSIZE; - *(client->bufptr) = (char *)xmalloc(client->bufsize); - *(client->lenptr) = 0; - } - if( (*(client->lenptr) + XPA_IOSIZE) > client->bufsize ){ - client->bufsize += (XPA_IOSIZE*10); - *(client->bufptr) = (char *)xrealloc(*(client->bufptr), client->bufsize); - } - - /* now retrieve the data from the server */ - status = recv(client->datafd, *(client->bufptr) + *(client->lenptr), - XPA_IOSIZE, 0); - /* status < 0 means error */ - switch(status){ - /* error */ - case -1: - /* socket would block */ - if((xerrno == EINPROGRESS) || (xerrno == EWOULDBLOCK)){ - return(0); - } - /* clean up after error */ - if( *(client->bufptr) ){ - xfree(*(client->bufptr)); - *(client->bufptr) = NULL; - client->bufsize = 0; - } - *(client->lenptr) = 0; - XPAClientDataSent(xpa, client); -#ifdef OLD - (void)XPAClientEnd(xpa, client); - /* we need to flag some sort of error, if nothing came across */ - if( *(client->errptr) == NULL ){ - *(client->errptr) = xstrdup( - "XPA$ERROR: incomplete transmission from server\n"); - } -#endif - break; - /* eof */ - case 0: - /* if we have multiple clients, we now need to write this one */ - if( client->mode & XPA_CLIENT_FD ){ - if( xpa->nclient > 1 ){ - snprintf(tbuf, SZ_LINE, "XPA$BEGIN %s:%s %s\n", - client->xclass, client->name, client->method); - write(client->fd, tbuf, strlen(tbuf)); - } - write(client->fd, *(client->bufptr), *(client->lenptr)); - if( xpa->nclient > 1 ){ - snprintf(tbuf, SZ_LINE, "XPA$END %s:%s %s\n", - client->xclass, client->name, client->method); - write(client->fd, tbuf, strlen(tbuf)); - } - /* we can free buf, since its not being passed back */ - if( *(client->bufptr) ){ - xfree(*(client->bufptr)); - *(client->bufptr) = NULL; - client->bufsize = 0; - } - } - else{ - /* set final buffer size and put a convenience null at the end */ - if( *(client->bufptr) ){ - client->bufsize = *(client->lenptr)+1; - *(client->bufptr) = (char *)xrealloc(*(client->bufptr),client->bufsize); - *(*(client->bufptr)+*(client->lenptr)) = '\0'; - } - } - /* for all clients, we need to clean up */ - XPAClientDataSent(xpa, client); -#ifdef OLD - (void)XPAClientEnd(xpa, client); -#endif - break; - /* status > 0: bytes read */ - default: - *(client->lenptr) += status; - /* for single client fd mode, we write immediately -- this deals with - the important case of one client with a large amount of data */ - if( (client->mode & XPA_CLIENT_FD) && (xpa->nclient == 1) ){ - write(client->fd, *(client->bufptr), *(client->lenptr)); - /* reset buf for next read */ - if( *(client->bufptr) ) xfree(*(client->bufptr)); - *(client->bufptr) = NULL; - *(client->lenptr) = 0; - } - break; - } - return(status); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientSet - * - * Purpose: process an xpaset request for a given client - * - * Return: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientSet (XPA xpa, XPAClient client) -#else -static int XPAClientSet(xpa, client) - XPA xpa; - XPAClient client; -#endif -{ - int status; - int left; - int got; - int len; - XPAInput inp; - - if( client->mode & XPA_CLIENT_BUF ){ - while( 1 ){ - len = MIN(XPA_IOSIZE, client->len - client->bytes); - /* see if we have written it all */ - if( len == 0 ){ - status = 1; - goto done; - } - /* write the next chunk */ - FPRINTF((stderr, - "%sXPAClientSet: fd %d sending %lu bytes (%lu - %lu)\n", _sp, - client->datafd, (unsigned long)len, - (unsigned long)client->len, (unsigned long)client->bytes)); - got=send(client->datafd, &(client->buf[client->bytes]), len, 0); - if( got >= 0 ){ - client->bytes += got; - if( XPALevelGet() >0 ) - return(got); - } - else{ - PERROR(("XPAClientSet")); - /* check for error */ - if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ - status = -1; - goto done; - } - /* write would block, so we return and wait the server */ - else{ - return(0); - } - } - } - } - /* reading from stdin and writing to servers */ - else{ - /* find the input buf that contains the data we need */ - for(inp=xpa->inphead; inp!=NULL; inp=inp->next){ - if( (client->bytes >= inp->start) && (client->bytes < inp->end) ){ - break; - } - } - /* if we can't find a buffer ... */ - if( !inp ){ - /* ... and we have all the input, we are done */ - if( xpa->ifd < 0 ){ - FPRINTF((stderr, "%sXPAClientSet: all data read\n", _sp)); - status = 1; - goto done; - } - /* ... but there is more input to come, return */ - else{ - return(0); - } - } - /* optimization: don't write a buffer until its full (or until eof) */ - if( (xpa->ifd >=0) && (inp->bytes < XPA_BIOSIZE) ){ - return(0); - } - - /* write bytes until we would block or until end of this buffer, etc */ - while( 1 ){ - len = MIN(XPA_IOSIZE, inp->end - client->bytes); - FPRINTF((stderr, "%sXPAClientSet: has %lu=min(%d,(%lu-%lu)) [%d]\n", - _sp, (unsigned long)len, XPA_IOSIZE, - (unsigned long)inp->end, (unsigned long)client->bytes, - client->status)); - /* if we are done with this buffer, just return */ - if( (client->status == XPA_CLIENT_PROCESSING) && (len <=0) ){ - /* see if everyone else is done with this buffer as well, - in which case we can free it */ - left = 0; - for(client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type != 's') || !(client->mode & XPA_CLIENT_FD) ) - continue; - /* in order to be totally written out, the following must be true: - * 1. send->bytes must be past the end of this buffer - * and - * 2. this buffer must be filled or else we hit eof - */ - FPRINTF((stderr, - "%sXPAClientSet: %lu>=%lu && ((%lu>=%d) or %d<0)) .. ", - _sp, client->bytes, (unsigned long)inp->end, - (unsigned long)inp->bytes, XPA_BIOSIZE, - xpa->ifd)); - if( (client->bytes >= inp->end) && - ((inp->bytes >= XPA_BIOSIZE) || (xpa->ifd < 0)) ){ - /* buffer complete written */ - FPRINTF((stderr, "%sEOF (%lu)\n", - _sp, (unsigned long)xpa->inpbytes)); - ; - } - else{ - FPRINTF((stderr, "%s\n", _sp)); - /* buffer not complete written */ - left++; - break; - } - } - /* if nothing is left, we can free this input struct */ - if( !left ){ - XPAClientFreeInput(xpa, inp); - } - return(0); - } - /* write to the server */ - FPRINTF((stderr, - "%sXPAClientSet: fd %d sending %lu bytes (%lu):\n", _sp, - client->datafd, - (unsigned long)len, (unsigned long)client->bytes)); - got = send(client->datafd, &(inp->buf[client->bytes-inp->start]),len,0); - /* check for success */ - if( got >= 0 ){ - /* update the number of bytes we wrote */ - client->bytes += got; - FPRINTF((stderr, "%sXPAClientSet: sent %lu bytes (total is %lu)\n", - _sp, (unsigned long)got, (unsigned long)client->bytes)); - /* go back for more */ - if( XPALevelGet() >0 ) - return(got); - else - continue; - } - /* check for error */ - else{ - PERROR(("XPAClientSet")); - /* anything but a "would block" error is bad */ - if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ - status = -1; - goto done; - } - /* write would block, so we return and wait the server */ - else{ - FPRINTF((stderr, "%sXPAClientSet: waiting for more data\n", _sp)); - return(0); - } - } - } - } - -done: - XPAClientDataSent(xpa, client); -#ifdef OLD - (void)XPAClientEnd(xpa, client); -#endif - return(status); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientProcessSelect - * - * Purpose: process xpas that have pending reads or writes - * - * Return: number of xpas processed - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAClientProcessSelect (XPA xpa, - fd_set *readfdsptr, fd_set *writefdsptr, int maxreq) -#else -int XPAClientProcessSelect(xpa, readfdsptr, writefdsptr, maxreq) - XPA xpa; - fd_set *readfdsptr; - fd_set *writefdsptr; - int maxreq; -#endif -{ - int got=0; - int loop=0; - XPAClient client; - - /* <= 0 means do all of them */ - if( maxreq < 0 ){ - maxreq = 0; - } - - /* if no xpa is specified, do them all */ - if( xpa == NULL ){ - if( xpaclienthead == NULL ) return(0); - xpa = xpaclienthead; - loop = 1; - } - -loop: - /* first process any new input before we write output */ - if( xfd_isset_stdin(xpa->ifd, readfdsptr) ){ - xfd_clr_stdin(xpa->ifd, readfdsptr); - XPAClientProcessInput(xpa); - } - /* look at all clients */ -again: - for(client=xpa->clienthead; client!=NULL; client=client->next){ - /* if we are processing */ - if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd>=0) ){ - /* then handle new requests */ - if((client->type == 'g') && FD_ISSET(client->datafd, readfdsptr)){ - FD_CLR(client->datafd, readfdsptr); - XPAClientGet(xpa, client); - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - else if((client->type == 's') && FD_ISSET(client->datafd, writefdsptr)){ - FD_CLR(client->datafd, writefdsptr); - /* if the return is > 0, we completed the send */ - if( XPAClientSet(xpa, client) > 0 ) - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - } - /* if this client is waiting */ - else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ - if( FD_ISSET(client->cmdfd, readfdsptr)){ - FD_CLR(client->cmdfd, readfdsptr); - XPAClientEnd(xpa, client); - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - } - } - /* loop if necessary */ - if( loop && (xpa=xpa->next) ) goto loop; - /* return the news */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientLoop - * - * Purpose: non-X programs event loop for handling XPA client events - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientLoop (XPA xpa, int mode) -#else -static int XPAClientLoop(xpa, mode) - XPA xpa; - int mode; -#endif -{ - int got=0; - int sgot; - int doxpa=1; - int ltimeout; - char *s=NULL; - fd_set readfds; - fd_set writefds; - static int width=0; - struct timeval tv; - struct timeval *tvp; - - /* set width once */ - if( width == 0 ){ - width = FD_SETSIZE; - } - /* allow environment to turn off xpa server processing in client loop */ - if( (s=getenv("XPA_CLIENT_DOXPA")) && isfalse(s) ){ - doxpa = 0; - } - ltimeout = XPALongTimeout(); - FD_ZERO(&readfds); - FD_ZERO(&writefds); - while( XPAClientAddSelect(xpa, &readfds, &writefds) ){ - /* add other XPA's and process them as we process the client */ - if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ - FPRINTF((stderr, "%sXPAClientLoop: will handle server reqs ...\n", _sp)); - XPAAddSelect(NULL, &readfds); - } - /* hopefully, a server will respond in a finite amount of time */ - if( ltimeout > 0 ){ - tv.tv_sec = ltimeout; - tv.tv_usec = 0; - tvp = &tv; - } - /* wait forever, if necessary */ - else{ - tvp = NULL; - } - /* add stdin to select, if there is one */ - if( xpa->ifd >= 0 ){ - xfd_set_stdin(xpa->ifd, &readfds); -#if HAVE_MINGW32 - /* BUT: for windows, we can't add stdin to select and therefore we - must set a short timeout and look manually */ - tv.tv_sec = 0; - tv.tv_usec = 10000; - /* this is the number of window iterations we will perform */ - if( ltimeout > 0 ) - ltimeout *= 100; - tvp = &tv; -#endif - } - /* wait for a server to respond */ - FPRINTF((stderr, "%sXPAClientLoop: waiting on select() ...\n", _sp)); - sgot = xselect(width, &readfds, &writefds, NULL, tvp); - FPRINTF((stderr, "%sXPAClientLoop: select returns: %d\n", _sp, sgot)); - /* error -- what should we do? */ - if( sgot < 0 ){ - if( xerrno == EINTR ){ - FD_ZERO(&readfds); - FD_ZERO(&writefds); - continue; - } - if( XPAVerbosity() ){ - perror("XPAClientLoop() select"); - } - exit(1); - } - /* timed out -- no one responded */ - else if( sgot == 0 ){ -#if HAVE_MINGW32 - if( xpa->ifd >= 0 ){ - if( ltimeout > 0 ){ - if( --ltimeout <= 0 ) - break; - } - } - else{ - break; - } -#else - break; -#endif - } - else{ - got += XPAClientProcessSelect(xpa, &readfds, &writefds, 0); - if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ - got += XPAProcessSelect(&readfds, 0); - } - } - FD_ZERO(&readfds); - FD_ZERO(&writefds); - } - return(got); -} - -#if HAVE_MINGW32==0 -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientLoopFork - * - * Purpose: non-X programs forked event loop for handling XPA client events - * - * Returns: number of clients "processed" - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientLoopFork (XPA xpa, int mode) -#else -static int XPAClientLoopFork(xpa, mode) - XPA xpa; - int mode; -#endif -{ - XPAClient client, tclient; - pid_t pid; - int got; - int fd[2]; - char active=1; -#ifndef USE_DOUBLE_FORK - struct sigaction act; - /* set up the signal handler to reap children (to avoid zombies) */ - act.sa_handler = sig_chld; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_RESTART - act.sa_flags |= SA_RESTART; -#endif -#ifdef SA_NOCLDWAIT - act.sa_flags |= SA_NOCLDWAIT; -#endif - sigaction(SIGCHLD, &act, NULL); -#endif - - if( pipe(fd) < 0 ){ - got = 0; - } - else if( (pid = fork()) < 0 ){ - close(fd[0]); - close(fd[1]); - got=0; - } - else if( pid == 0 ){ /* child */ - /* child write to parent that he is active */ - close(fd[0]); - write(fd[1], &active, 1); - close(fd[1]); -#ifdef USE_DOUBLE_FORK - /* second fork prevents zombies: - when child/parent exits, second child is inherited - by init and thus is not a child of original parent */ - if( (pid = fork()) >= 0 ){ - /* child/parent exits */ - if( pid > 0 ) - exit(0); - /* new child goes on under init ... */ - } -#endif - /* enter the main loop and process */ - XPAIOCallsXPA(0); - XPAClientLoop(xpa, mode); - exit(0); - } else { /* parent */ - /* parent waits for child to wake up */ - close(fd[1]); - read(fd[0], &active, 1); - close(fd[0]); -#ifdef USE_DOUBLE_FORK - /* for double fork, also wait for intermediate process to exit */ - waitpid(pid, NULL, 0); -#endif - /* fake end of clients */ - for(got=0, client=xpa->clienthead; client!=NULL; ){ - got++; - tclient = client->next; - if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >=0) ){ -#if HAVE_CYGWIN - /* In Cygwin, we call shutdown (as well as close) to avoid Windows - problems. The parent can't do this since the child is using the - sockets, so we just close the sockets explicitly here */ - xclose(client->datafd); - client->datafd = -1; - if( !xpa->persist ){ - xclose(client->cmdfd); - client->cmdfd = -1; - } -#endif - client->errptr = NULL; - /* remove this client if we are not meant to persist */ - if( !xpa->persist ){ - XPAClientFree(xpa, client); - } - /* otherwise mark as inactive */ - else{ - client->status = XPA_CLIENT_IDLE; - client->bytes = 0; - } - } - client = tclient; - } - } - return(got); -} -#endif - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientConnect - * - * Purpose: go to name service and get new names, merge with old, - * and connect to servers - * - * Returns: number of connections - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientConnect (XPA xpa, char *mode, char *xtemplate, int type) -#else -static int XPAClientConnect(xpa, mode, xtemplate, type) - XPA xpa; - char *mode; - char *xtemplate; - int type; -#endif -{ - int i; - int n; - int got; - int lp=0; - int total=0; - char **xclasses; - char **names; - char **methods; - char **infos; - char xtype[2]; - char xmode[SZ_LINE]; - char tbuf[SZ_LINE]; - char lbuf[SZ_LINE]; - XPAClient client; - - /* do some initialization */ - XPAInitEnv(); - - /* make sure we have a target */ - if( !xtemplate || !*xtemplate ) - return(0); - - /* make a string out of the type for the lookup */ - xtype[0] = type; - xtype[1] = '\0'; - - /* reset the number of clients we are processing */ - xpa->nclient = 0; - - /* look for specific proxy info */ - *xmode = '\0'; - if( mode ){ - strncpy(xmode, mode, SZ_LINE-1); - xmode[SZ_LINE-1] = '\0'; - } - if( keyword(xmode, "ns", lbuf, SZ_LINE) ){ - FPRINTF((stderr, "%sXPAClientConnect: using ns info: %s\n", _sp, lbuf)); - newdtable("(),"); - xclasses = (char **)xmalloc(sizeof(char *)); - names = (char **)xmalloc(sizeof(char *)); - methods = (char **)xmalloc(sizeof(char *)); - infos = (char **)xmalloc(sizeof(char *)); - if( word(lbuf, tbuf, &lp) ) - xclasses[0] = xstrdup(tbuf); - if( word(lbuf, tbuf, &lp) ) - names[0] = xstrdup(tbuf); - if( word(lbuf, tbuf, &lp) ) - methods[0] = xstrdup(tbuf); - infos[0] = xstrdup(XPA_DEF_CLIENT_INFO); - n = 1; - freedtable(); - } - /* else ask xpans for access points matching the template */ - else{ - n = XPANSLookup(xpa, - xtemplate, xtype, &xclasses, &names, &methods, &infos); - } - /* mark existing clients who do not match this template */ - for(got=0, client=xpa->clienthead; client !=NULL; client=client->next){ - for(i=0; i<n; i++){ - if( (client->type == type) && - (!strcmp(client->xclass, xclasses[i])) && - (!strcmp(client->name, names[i])) && - (!strcmp(client->method, methods[i])) && - (!strcmp(client->info, infos[i])) ){ - got++; - } - } - /* don't unmark if its a different type -- someone else might be active */ - if( !got && (client->type == type) ){ - client->status = XPA_CLIENT_IDLE; - } - } - /* add new clients for this type */ - for(i=0; i<n; i++){ - for(got=0, client=xpa->clienthead; client !=NULL; client=client->next){ - if( (client->type == type) && - (!strcmp(client->xclass, xclasses[i])) && - (!strcmp(client->name, names[i])) && - (!strcmp(client->method, methods[i])) && - (!strcmp(client->info, infos[i])) ){ - /* might have to change the template */ - if( strcmp(client->xtemplate, xtemplate) ){ - xfree(client->xtemplate); - client->xtemplate = xstrdup(xtemplate); - } - client->status = XPA_CLIENT_ACTIVE; - got++; - total++; - FPRINTF((stderr, "%sXPAClientConnect: existing match: %s %s %s\n", - _sp, xclasses[i], names[i], methods[i])); - break; - } - } - if( !got ){ - FPRINTF((stderr, "%sXPAClientConnect: calls XPAClientNew for %s:%s %s\n", - _sp, xclasses[i], names[i], methods[i])); - if( XPAClientNew(xpa, mode, xtemplate, type, - xclasses[i], names[i], methods[i], infos[i]) ) - total++; - } - /* done with these strings */ - xfree(xclasses[i]); - xfree(names[i]); - xfree(methods[i]); - xfree(infos[i]); - } - /* free up arrays alloc'ed by names server */ - if( n > 0 ){ - xfree(xclasses); - xfree(names); - xfree(methods); - xfree(infos); - } - return(total); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClientStart - * - * Purpose: send init string to server and perform other authentication - * tasks - * - * Returns: 0 if success, -1 otherwise - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -XPAClientStart (XPA xpa, XPAClient client, char *paramlist, char *mode) -#else -static int XPAClientStart(xpa, client, paramlist, mode) - XPA xpa; - XPAClient client; - char *paramlist; - char *mode; -#endif -{ - int fd=0; - int lp=0; - int flags; - int tries=0; - int dmode=0; - int keep_alive=1; - unsigned int ip=0; - unsigned short port; - char tbuf[SZ_LINE]; - char tbuf2[SZ_LINE]; - char lbuf[SZ_LINE]; - char *cmd=NULL; - char *method=NULL; - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - - switch(client->type){ - case 'a': - cmd = "xpaaccess"; - break; - case 'g': - cmd = "xpaget"; - break; - case 'i': - cmd = "xpainfo"; - break; - case 's': - cmd = "xpaset"; - break; - } - - /* get mode flags */ - XPAMode(mode, &(client->mode), "ack", XPA_CLIENT_ACK, 1); - if( client->type == 's' ) - XPAMode(mode, &(xpa->client_mode), "verify", XPA_CLIENT_VERIFY, 0); - /* package up and send the initialization message */ - strcpy(lbuf, cmd); - /* set and save the id value */ - snprintf(tbuf, SZ_LINE, "%c%d", client->type, id++); - if( client->id ) xfree(client->id); - client->id = xstrdup(tbuf); - /* if we are using the xpans proxy, we will want to call - accept() (server calls connect()) for the data channel */ - if( client->nsproxy ) - strcat(lbuf, " -a"); - /* set the value of the client big-endian-ness */ - snprintf(tbuf, SZ_LINE, " -e %s", XPAEndian() ? "big" : "little"); - strcat(lbuf, tbuf); - snprintf(tbuf, SZ_LINE, " -i %s", client->id); - strcat(lbuf, tbuf); - if( !(client->mode & XPA_CLIENT_ACK) ) - strcat(lbuf, " -n"); - if( strcmp(client->info, XPA_DEF_CLIENT_INFO) ){ - snprintf(tbuf, SZ_LINE, " -p %s", client->info); - strcat(lbuf, tbuf); - } - snprintf(tbuf, SZ_LINE, " %s:%s", client->xclass, client->name); - strcat(lbuf, tbuf); - if( paramlist && *paramlist ){ - strcat(lbuf, " "); - strncat(lbuf, paramlist, MAX(0,(int)(SZ_LINE-(int)strlen(lbuf)-2))); - } - strcat(lbuf, "\n"); - FPRINTF((stderr, "%sXPAClientStart: fd %d sends:\n%s", - _sp, client->cmdfd, lbuf)); - if( XPAPuts(NULL, client->cmdfd, lbuf, XPAShortTimeout()) <= 0 ){ - goto error; - } - - /* if xpainfo and no ack'ing, we are basically done */ - if( (client->type == 'i') && !(client->mode & XPA_CLIENT_ACK) ){ - goto done; - } - - /* authentication */ -retry: - lp = 0; - if( XPAGets(NULL, client->cmdfd, lbuf, SZ_LINE, XPAShortTimeout()) >0 ){ - FPRINTF((stderr, "%sXPAClientStart: fd %d received cmd:\n%s", _sp, - client->cmdfd, lbuf)); - /* this should never happen */ - if( !word(lbuf, tbuf, &lp) || (*tbuf == '?') ){ - snprintf(errbuf, SZ_LINE, - "XPA$WARNING: Protocol mismatch: id\n%s", lbuf); - goto error; - } - /* make sure we are dealing with a proper message */ - if( strcmp(tbuf, client->id) ){ - FPRINTF((stderr, "%sXPA$WARNING: ignoring out of sync message:\n", _sp)); - FPRINTF((stderr, "%s", lbuf)); - if( XPAVerbosity() > 1 ){ - fprintf(stderr, "XPA$WARNING: ignoring out of sync server message:\n"); - fprintf(stderr, "%s", lbuf); - } - goto retry; - } - - /* this should never happen */ - if( !word(lbuf, tbuf, &lp) ){ - snprintf(errbuf, SZ_LINE, "XPA$WARNING: missing BUF request\n%s", lbuf); - goto error; - } - if( !strcmp(tbuf, "XPA$NODATA") || !strcmp(tbuf, "XPA$NOBUF") ){ - xpa->nclient += 1; - goto started; - } - /* support 2.2 (DATA) and 2.0,2.1 (BUF) */ - else if( !strcmp(tbuf, "XPA$DATA") || !strcmp(tbuf, "XPA$BUF") ){ - if( !strcmp(tbuf, "XPA$DATA") ){ - dmode |= DATA_DATA; - if( !word(lbuf, tbuf, &lp) ){ - snprintf(errbuf, SZ_LINE, - "XPA$WARNING: missing DATA request type\n%s", lbuf); - goto error; - } - if( !strcmp(tbuf, "connect") ){ - method = client->method; - dmode |= DATA_CONNECT; - } - else if( !strcmp(tbuf, "accept") ){ - method = client->method; - dmode |= DATA_ACCEPT; - } - else{ - snprintf(errbuf, SZ_LINE, - "XPA$WARNING: invalid data connection request: %s (%s:%s)\n", - tbuf, client->xclass, client->name); - goto error; - } - } - else if( !strcmp(tbuf, "XPA$BUF") ){ - if( !word(lbuf, tbuf, &lp) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: missing data buffer method (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - goto error; - } - method = tbuf; - dmode |= DATA_CONNECT; - } - /* handle connect-type requests */ - if( dmode & DATA_CONNECT ){ - switch(XPAMethod(method)){ - case XPA_INET: - XPAParseIpPort(method, &ip, &port); - /* connect to the server before we go further */ - if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - if( XPAVerbosity() ){ - perror("XPA client socket"); - } - goto error; - } - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - /* connect using the same ip we used for the command channel - (i.e., could be localhost) */ - sock_in.sin_addr.s_addr = htonl(client->ip); - sock_in.sin_port = htons(port); - FPRINTF((stderr, - "%sXPAClientStart: attempting dchan connect: %s\n", - _sp, method)); - if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ - PERROR(("dchan connect")); - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - if( XPAVerbosity() ){ - perror("XPA client connect"); - } - xclose(fd); - goto error; - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: -again: - /* open a socket and fill in socket information */ - if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - if( XPAVerbosity() ){ - perror("XPA client socket"); - } - goto error; - } - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_un, 0, sizeof(sock_un)); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, method); - FPRINTF((stderr, - "%sXPAClientStart: attempting dchan connect: %s\n", - _sp, method)); - if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) < 0 ){ - PERROR(("dchan connect")); - xclose(fd); - if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ - tries++; - xclose(fd); - XPASleep(10); - goto again; - } - /* give up */ - else{ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - if( XPAVerbosity() ){ - perror("XPA client connect"); - } - goto error; - } - } - break; -#endif - default: - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: unknown connection method (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - goto error; - } - } - /* handle "doaccept" requests */ - else if( dmode & DATA_ACCEPT ){ - fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), - client->xclass, client->name, client->cmdfd, - NULL, NULL, tbuf2); - if( fd < 0 ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: can't connect to proxy server (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - goto error; - } - else if( *tbuf2 ){ - client->dataname = xstrdup(tbuf2); - } - } - - /* common code for either type of data connect request */ - client->datafd = fd; - /* make sure we close on exec */ - xfcntl(client->datafd, F_SETFD, FD_CLOEXEC); - /* for senders, set to no block mode */ - if( client->type == 's' ){ - /* save state and set in non-blocking mode */ - xfcntl_nonblock(client->datafd, flags); - } - xpa->nclient += 1; - goto started; - } - /* handle error message */ - else if( !strcmp(tbuf, "XPA$ERROR") ){ - snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); - goto error; - } - /* everything else is an error */ - else{ - snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); - goto error; - } - } - else{ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server during handshake (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - goto error; - } - -error: - FPRINTF((stderr, "Error in XPAClientStart: %s", errbuf)); - XPAClientFree(xpa, client); - return(-1); - -started: - /* it is necessary to add this this extra hack/ack between the - authentication ack and the error return (both from the server) - to avoid getting Nagle buffered. if we already did an accept, - however, we already sent a message and need not repeat it */ - if( !(dmode & DATA_ACCEPT) ){ - FPRINTF((stderr, "%sXPAClientStart: %d sending nagle\n", - _sp, client->cmdfd)); - XPAPuts(NULL, client->cmdfd, "xpanagle\n", XPAShortTimeout()); - } - - /* write a "data request" to the server on the data channel, supplying - the arguments to allow the server to find the associated command */ - if( dmode & DATA_DATA ){ - if( !word(lbuf, tbuf, &lp) ) - strcpy(tbuf, "?"); - if( !word(lbuf, tbuf2, &lp) ) - strcpy(tbuf2, "?"); - snprintf(lbuf, SZ_LINE, "xpadata -f %s %s\n", tbuf, tbuf2); - FPRINTF((stderr, - "%sXPAClientStart: sending data channel %d request: %s", _sp, - client->datafd, lbuf)); - if( XPAPuts(NULL, client->datafd, lbuf, XPAShortTimeout()) <0 ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: unable to issue data request: %s (%s:%s%s)\n", - lbuf, client->xclass, client->name, XPATimestamp()); - FPRINTF((stderr, "%sXPAClientStart: error returned is %s", _sp, errbuf)); - goto error; - } - } - -done: - /* mark as active and started */ - client->status = XPA_CLIENT_PROCESSING; - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * - * Public Routines - * - * - *---------------------------------------------------------------------------- - */ - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAClientValid - * - * Purpose: see if the xpa client struct is valid - * - * Results: 1 on success, 0 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAClientValid (XPA xpa) -#else -int XPAClientValid(xpa) - XPA xpa; -#endif -{ - return(_XPAValid(xpaclienthead, xpa, "c")); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAOpen - * - * Purpose: open a persistent XPA client connection - * - * Returns: XPA struct on success - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -XPA -XPAOpen (char *mode) -#else -XPA XPAOpen(mode) - char *mode; -#endif -{ - XPA xpa; - - /* allocate xpa struct */ - if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) - return(NULL); - /* add version */ - xpa->version = xstrdup(XPA_VERSION); - /* mark this as a client struct */ - xpa->type = xstrdup("c"); - /* mark as persistent so we don't destroy at the end of the transfer */ - xpa->persist = 1; - - /* add this xpa to end of list of client xpas */ - XPAListAdd(&xpaclienthead, xpa); - - return(xpa); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAClose - * - * Purpose: close a persistent XPA client connection - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAClose (XPA xpa) -#else -void XPAClose(xpa) - XPA xpa; -#endif -{ - XPAClient client, tclient; - NS ns, tns; - - /* ignore struct if its not a client struct */ - if( !XPAClientValid(xpa) ) - return; - - /* remove from list of client xpas */ - XPAListDel(&xpaclienthead, xpa); - - /* free each remaining client */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - XPAClientFree(xpa, client); - client = tclient; - } - - /* close down the name server and all of the remotes for this xpa */ - for(ns=xpa->nshead; ns!=NULL; ){ - tns = ns->next; - XPANSClose(xpa, ns); - ns = tns; - } - - /* free string space */ - if( xpa->version ) - xfree(xpa->version); - if( xpa->type ) - xfree(xpa->type); - if( xpa ) - xfree(xpa); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAGet - * - * Purpose: get XPA values - * - * Returns: 0 for success, -1 for failure - * len bytes of data returned in buf - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAGet (XPA xpa, char *xtemplate, char *paramlist, char *mode, - char **bufs, size_t *lens, char **names, char **messages, int n) -#else -int XPAGet(xpa, xtemplate, paramlist, mode, bufs, lens, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - char *mode; - char **bufs; - size_t *lens; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int xmode=0; - int type='g'; - int idef=1; - int got=0; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - FPRINTF((stderr, "%sXPAGet: starting\n", _sp)); - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* these arrays are required */ - if( (bufs == NULL) || (lens == NULL) ){ - got = -1; - goto done; - } - - /* flag that we don't read from stdin */ - xpa->ifd = -1; - - /* zero out the return buffers */ - memset((char *)bufs, 0, ABS(n)*sizeof(char *)); - memset((char *)lens, 0, ABS(n)*sizeof(size_t)); - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ - /* retrieve data from n active clients */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ - /* we fill buffers */ - client->mode |= XPA_CLIENT_BUF; - client->bufptr = &(bufs[got]); - client->lenptr = &(lens[got]); - if( names != NULL ) - client->nameptr = &(names[got]); - if( messages != NULL ) - client->errptr = &(messages[got]); - } - else{ - if( messages != NULL ) - messages[got] = xstrdup(errbuf); - } - got++; - } - client = tclient; - } - /* if we have active clients */ - if( got ){ -#if HAVE_MINGW32==0 - /* check for loop modes */ - XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); - /* dofork implies don't do xpa */ - if( xmode & XPA_CLIENT_SEL_FORK ) - idef = 0; - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - if( xmode & XPA_CLIENT_SEL_FORK ){ - XPAClientLoopFork(xpa, xmode); - } - else{ - /* enter the main loop and process */ - XPAClientLoop(xpa, xmode); - } -#else - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - XPAClientLoop(xpa, xmode); -#endif - } - } - -done: - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAGetFd - * - * Purpose: get XPA values - * - * Returns: 0 for success, -1 for failure - * len bytes of data returned in buf - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAGetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, - int *fds, char **names, char **messages, int n) -#else -int XPAGetFd(xpa, xtemplate, paramlist, mode, fds, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - int *fds; - char *mode; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int xmode=0; - int got=0; - int type='g'; - int idef=1; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - FPRINTF((stderr, "%sXPAGetFd: starting\n", _sp)); - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* flag that we don't read from stdin */ - xpa->ifd = -1; - - /* zero out the return buffers */ - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) > 0 ){ - /* retrieve data from n active clients */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ - /* we write to an fd */ - client->mode |= XPA_CLIENT_FD; - /* negative value => one channel for all clients */ - if( n < 0 ) - client->fd = fds[0]; - else - client->fd = fds[got]; - client->bufptr = (char **)xcalloc(1, sizeof(char *)); - client->lenptr = (size_t *)xcalloc(1, sizeof(size_t)); - if( names != NULL ) - client->nameptr = &(names[got]); - if( messages != NULL ) - client->errptr = &(messages[got]); - } - else{ - if( messages != NULL ) - messages[got] = xstrdup(errbuf); - } - got++; - } - client = tclient; - } - /* if we have active clients */ - if( got ){ -#if HAVE_MINGW32==0 - /* check for loop modes */ - XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); - /* dofork implies don't do xpa */ - if( xmode & XPA_CLIENT_SEL_FORK ) - idef = 0; - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - if( xmode & XPA_CLIENT_SEL_FORK ){ - XPAClientLoopFork(xpa, xmode); - } - else{ - /* enter the main loop and process */ - XPAClientLoop(xpa, xmode); - } -#else - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - XPAClientLoop(xpa, xmode); -#endif - } - } - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASet - * - * Purpose: set XPA values - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASet (XPA xpa, char *xtemplate, char *paramlist, char *mode, - char *buf, size_t len, char **names, char **messages, int n) -#else -int XPASet(xpa, xtemplate, paramlist, mode, buf, len, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - char *mode; - char *buf; - size_t len; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int xmode=0; - int got=0; - int type='s'; - int idef=1; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - FPRINTF((stderr, "%sXPASet: starting\n", _sp)); - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* flag that we don't read from stdin */ - xpa->ifd = -1; - - /* zero out the return buffers */ - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ - /* retrieve data from n active clients */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ - /* we fill buffers */ - client->mode |= XPA_CLIENT_BUF; - client->buf = buf; - client->len = len; - if( names != NULL ) - client->nameptr = &(names[got]); - if( messages != NULL ) - client->errptr = &(messages[got]); - } - else{ - if( messages != NULL ) - messages[got] = xstrdup(errbuf); - } - got++; - } - client = tclient; - } - /* if we have active clients */ - if( got ){ -#if HAVE_MINGW32==0 - /* check for loop modes */ - XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); - /* dofork implies don't do xpa */ - if( xmode & XPA_CLIENT_SEL_FORK ) - idef = 0; - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - if( xmode & XPA_CLIENT_SEL_FORK ){ - XPAClientLoopFork(xpa, xmode); - } - else{ - /* enter the main loop and process */ - XPAClientLoop(xpa, xmode); - } -#else - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - XPAClientLoop(xpa, xmode); -#endif - } - } - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASetFd - * - * Purpose: set XPA values - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, - int fd, char **names, char **messages, int n) -#else -int XPASetFd(xpa, xtemplate, paramlist, mode, fd, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - char *mode; - int fd; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int xmode=0; - int got=0; - int got2=0; - int type='s'; - int idef=1; - int flags; - char *s; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - FPRINTF((stderr, "%sXPASetFd: starting\n", _sp)); - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* Set non-blocking mode for the input fd, if its not a tty */ - xpa->ifd = fd; - if( isatty(xpa->ifd) == 0 ){ - /* save state and set in non-blocking mode */ - xfcntl_nonblock(xpa->ifd, flags); - } - /* zero out the return buffers */ - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ - /* open clients all at once */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ - /* we fill buffers */ - client->mode |= XPA_CLIENT_FD; - if( names != NULL ) - client->nameptr = &(names[got]); - if( messages != NULL ) - client->errptr = &(messages[got]); - } - else{ - if( messages != NULL ) - messages[got] = xstrdup(errbuf); - } - got++; - } - client = tclient; - } - /* if we have active clients */ - if( got ){ - /* if fd is null, user did not want to send data, just the paramlist */ - if( fd < 0 ){ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - XPAClientDataSent(xpa, client); - s = XPAClientEnd(xpa, client); - if( (messages != NULL) && (messages[got2] == NULL) ) - messages[got2] = xstrdup(s); - got2++; - } - client = tclient; - } - } - else{ -#if HAVE_MINGW32==0 - /* check for loop modes */ - XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); - /* dofork implies don't do xpa */ - if( xmode & XPA_CLIENT_SEL_FORK ) - idef = 0; - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - if( xmode & XPA_CLIENT_SEL_FORK ){ - XPAClientLoopFork(xpa, xmode); - } - else{ - /* enter the main loop and process */ - XPAClientLoop(xpa, xmode); - } -#else - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); - XPAClientLoop(xpa, xmode); -#endif - } - } - } - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* reset flags, if necessary */ - if( xpa->ifd >=0 && (isatty(xpa->ifd) ==0) ){ - xfcntl(xpa->ifd, F_SETFL, flags); - } - /* free all input structs */ - XPAClientFreeAllInputs(xpa); - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAInfo - * - * Purpose: send XPA info - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAInfo (XPA xpa, char *xtemplate, char *paramlist, char *mode, - char **names, char **messages, int n) -#else -int XPAInfo(xpa, xtemplate, paramlist, mode, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - char *mode; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int got=0; - char type='i'; - char *s; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* flag that we don't read from stdin */ - xpa->ifd = -1; - - /* zero out the return buffers */ - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ - /* retrieve data from n active clients */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ - XPAClientDataSent(xpa, client); - s = XPAClientEnd(xpa, client); - if( (messages != NULL) && (messages[got] == NULL) ) - messages[got] = xstrdup(s); - } - else{ - if( (messages != NULL) && (messages[got] == NULL) ) - messages[got] = xstrdup(errbuf); - } - got++; - } - client = tclient; - } - } - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAAccess - * - * Purpose: determine if XPA access point is available - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAAccess (XPA xpa, char *xtemplate, char *paramlist, char *mode, - char **names, char **messages, int n) -#else -int XPAAccess(xpa, xtemplate, paramlist, mode, names, messages, n) - XPA xpa; - char *xtemplate; - char *paramlist; - char *mode; - char **names; - char **messages; - int n; -#endif -{ - int i; - int oldmode=0; - int xmode=0; - int got=0; - int type='a'; - char *s; - char *ind1, *ind2; - char tbuf[SZ_LINE]; - XPAClient client, tclient; - - /* if not persistent, we need a temp xpa struct; - (also ignore passed struct if its not a client struct) */ - if( (xpa == NULL) || strcmp(xpa->type, "c") ){ - if( (xpa = XPAOpen(NULL)) == NULL ) - return(-1); - /* mark this as not persistent */ - xpa->persist = 0; - } - /* save xpa mode -- this call might override */ - else{ - /* make sure we have a valid client handle */ - if( !XPAClientValid(xpa) ){ - if( XPAVerbosity() ){ - fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); - } - return(-1); - } - oldmode = xpa->client_mode; - } - - /* flag that we don't read from stdin */ - xpa->ifd = -1; - - /* zero out the return buffers */ - if( names != NULL ) - memset((char *)names, 0, ABS(n)*sizeof(char *)); - if( messages != NULL ) - memset((char *)messages, 0, ABS(n)*sizeof(char *)); - - /* connect to clients and grab data */ - if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ - /* retrieve data from n active clients */ - for(client=xpa->clienthead; client!=NULL; ){ - tclient = client->next; - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (got<ABS(n)) ){ - if( names != NULL ){ - snprintf(tbuf, SZ_LINE, "%s:%s %s", - client->xclass, client->name, client->method); - names[got] = xstrdup(tbuf); - } - if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ - XPAClientDataSent(xpa, client); - s = XPAClientEnd(xpa, client); - if( (messages != NULL) && (messages[got] == NULL) ) - messages[got] = xstrdup(s); - } - else{ - if( (messages != NULL) && (messages[got] == NULL) ) - messages[got] = xstrdup(errbuf); - } - /* might have to fix the name if was an explicit mach:port */ - if( names && names[got] && *errbuf && - !strncmp(names[got], "?:?", 3) && - (ind1=strrchr(errbuf, '(')) && (ind2=strrchr(errbuf, ')')) ){ - ind1++; - strncpy(tbuf, ind1, ind2-ind1); - tbuf[ind2-ind1] = '\0'; - xfree(names[got]); - names[got] = xstrdup(tbuf); - } - got++; - } - client = tclient; - } - /* if we have active clients */ - if( got ){ - /* check for loop modes */ - XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, 1); - /* enter the main loop and process */ - XPAClientLoop(xpa, xmode); - } - } - /* look for clients who timed out */ - for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ - if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && - (i<ABS(n)) ){ - i++; - if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ - snprintf(errbuf, SZ_LINE, - "XPA$ERROR: no response from server callback (%s:%s%s)\n", - client->xclass, client->name, XPATimestamp()); - messages[i] = xstrdup(errbuf); - } - } - } - /* remove this xpa if we are not meant to persist */ - if( xpa && !xpa->persist ) - XPAClose(xpa); - /* restore xpa mode -- this call might override */ - else - xpa->client_mode = oldmode; - - /* return number of clients processes (including errors) */ - return(got); -} - |