diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2018-01-23 16:53:51 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2018-01-23 16:53:51 (GMT) |
commit | 51e1f85047b34f095ed69a3024d696997d2667c8 (patch) | |
tree | a8d46838982aa78a35653c10d0b7370d751d6181 /xpa/xpa.c | |
parent | 0c198f7902ee997dd8ec3631e8ff1c385257014d (diff) | |
download | blt-51e1f85047b34f095ed69a3024d696997d2667c8.zip blt-51e1f85047b34f095ed69a3024d696997d2667c8.tar.gz blt-51e1f85047b34f095ed69a3024d696997d2667c8.tar.bz2 |
upgrade xpa
Diffstat (limited to 'xpa/xpa.c')
-rw-r--r-- | xpa/xpa.c | 4720 |
1 files changed, 0 insertions, 4720 deletions
diff --git a/xpa/xpa.c b/xpa/xpa.c deleted file mode 100644 index d9c94e4..0000000 --- a/xpa/xpa.c +++ /dev/null @@ -1,4720 +0,0 @@ -/* - * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory - */ - -#include <xpap.h> - -/* - *---------------------------------------------------------------------------- - * - * - * Private Routines and Data - * - * - *---------------------------------------------------------------------------- - */ - -/* this is the head of the global list -- too lazy to do anything more */ -static XPA xpahead=NULL; - -/* globals for the xpa environment, controlled by environment variables */ -static int stimeout=XPA_SHORT_TIMEOUT; /* select, gets timeout in secs */ -static int ltimeout=XPA_LONG_TIMEOUT; /* fillbuf timeout in secs */ -static int ctimeout=XPA_CONNECT_TIMEOUT;/* local xpans connect */ -static int verbosity=XPA_VERBOSITY; /* 0=quiet, 1=normal, 2=full */ -static int nsdelay=XPA_NSDELAY; /* delay increment waiting for ns to start */ -static int retries=XPA_RETRIES; /* retries when retrying */ -static int guseacl=1; /* 0=don't use acls, 1=enable acls */ -static int etimestamp=0; /* 0=don't timestamp errors, 1=do timestamp */ -static int nsregister=1; /* 0=don't register with xpans, 1=register */ -static int sigusr1=1; /* 0=don't use sigusr1, 1=enable sigusr1 */ -static int vercheck=1; /* 0=don't check version, 1=check version */ -static char *tmpdir=NULL; /* temporary dir for logs. etc. */ -#if HAVE_ATEXIT -static int atexitinit=0; /* whether atexit has been registered */ -#endif - -/* variables used by all XPAs in this process */ -static char activefds[FD_SETSIZE]; -static char nsmethod[SZ_LINE]; -static char nsusers[SZ_LINE]; - -/* global method type: unix or inet */ -static int mtype=0; - -/* width of select channel flag */ -static int swidth=FD_SETSIZE; - -/* defined in tcp.c */ -extern int use_localhost; - -/* erro code strings -- must match the error codes in xpap.h */ -char *xpaMessbuf[] = { - "oh, what a mess we've made!", - "authentication failed", - "xpa connection refused", - "can't resolve host name for xpa", - "can't read initialization info for xpa", - "invalid xpa command in initialization string", - "no receive function defined for this xpa", - "no send function defined for this xpa", - "no info function defined for this xpa", - "undefined command for this xpa", - "missing command for this xpa", - "name does not match target template", - "can't create data channel socket", - "could not read data buf (possible timeout)", - "illegal command or command switch" -}; - -/* temp static time buffer */ -static char ctimebuf[SZ_LINE]; - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAProxyConnect - * - * Purpose: connect to a client (in proxy mode) - * - * Returns: 0 if successfull, otherwise -1 - * - *---------------------------------------------------------------------------- - */ - -#ifdef ANSI_FUNC -static int -XPAProxyConnect(XPA xpa, char *method, - unsigned int *rip, unsigned short *rport, char *rname) -#else -static int XPAProxyConnect(xpa, method, rip, rport, rname) - XPA xpa; - char *method; - unsigned int *rip; - unsigned short *rport; - char *rname; -#endif -{ - int ofd; - int tries=0; - int keep_alive=1; - unsigned int ip; - unsigned short port; - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - - FPRINTF((stderr, "%sXPAProxyConnect to %s\n", _sp, method)); - /* initialize results */ - if( rip ) *rip = 0; - if( rport ) *rport = 0; - if( rname ) *rname = '\0'; - - switch(XPAMethod(method)){ - case XPA_INET: -again1: - if( !XPAParseIpPort(method, &ip, &port) ){ - goto error; - } - /* use $localhost over $host (we don't trust host to be correct) */ - if( (ip == gethostip("$host")) && (tries == 0) ){ - ip = gethostip("$localhost"); - } - /* connect to the server before we go further */ - if( (ofd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ - PERROR(("XPAProxyConnect: socket()")); - goto error; - } - setsockopt(ofd, 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(ofd, (struct sockaddr *)&sock_in, sizeof(sock_in))<0){ - xclose(ofd); - /* 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{ - PERROR(("XPAProxyConnect: connect()")); - goto error; - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: -again2: - ip = 0; - port = 0; - /* open a socket and fill in socket information */ - if( (ofd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ - goto error; - } - setsockopt(ofd, 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(ofd, (struct sockaddr *)&sock_un, sizeof(sock_un))<0){ - xclose(ofd); - /* 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 < retries) ){ - tries++; - XPASleep(10); - goto again2; - } - /* give up */ - else{ - goto error; - } - } - break; -#endif - default: - goto error; - } - - /* fill in blansk */ - if( rip ) *rip = ip; - if( rport ) *rport = port; - if( rname ){ - strncpy(rname, method, SZ_LINE-1); - rname[SZ_LINE-1] = '\0'; - } - return(ofd); - -error: - return -1; -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: CommNew - * - * Purpose: allocate a new comm record and add to end of list - * - * Returns: allocated comm record - * - *---------------------------------------------------------------------------- - */ - -#ifdef ANSI_FUNC -static XPAComm -CommNew (XPA xpa, int fd, unsigned int ip, int port, char *name, NS ns) -#else -static XPAComm CommNew(xpa, fd, ip, port, name, ns) - XPA xpa; - int fd; - unsigned int ip; - int port; - char *name; - NS ns; -#endif -{ - XPAComm comm, cur; - int i; - socklen_t slen; - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - - /* create the comm struct */ - if( (comm = (XPAComm)xcalloc(1, sizeof(XPACommRec))) == NULL ) - return(NULL); - - /* if fd < 0, we accept a connection to get the fd */ - if( fd < 0 ){ - /* accept the connection */ - switch(mtype){ - case XPA_INET: - while( 1 ){ - slen = sizeof(struct sockaddr_in); - if((comm->cmdfd=xaccept(xpa->fd,(struct sockaddr *)&sock_in,&slen))>=0){ - comm->cmdip = ntohl(sock_in.sin_addr.s_addr); - comm->cmdport = ntohs(sock_in.sin_port); - break; - } - else{ - if( xerrno == EINTR ) - continue; - else{ - xfree(comm); - return(NULL); - } - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - while( 1 ){ - slen = sizeof(struct sockaddr_un); - if((comm->cmdfd=xaccept(xpa->fd,(struct sockaddr *)&sock_un,&slen))>=0){ - comm->cmdname = xstrdup(sock_un.sun_path); - break; - } - else{ - if( xerrno == EINTR ) - continue; - else{ - xfree(comm); - return(NULL); - } - } - } - break; -#endif - default: - xfree(comm); - return(NULL); - } - } - /* all info is supplied */ - else{ - switch(mtype){ - case XPA_INET: - comm->cmdip = ip; - comm->cmdport = port; - break; - case XPA_UNIX: - comm->cmdname = xstrdup(name); - break; - } - comm->cmdfd = fd; - /* store name server record */ - comm->ns = ns; - } - - /* set back pointer */ - /* make sure we close on exec */ - xfcntl(comm->cmdfd, F_SETFD, FD_CLOEXEC); - /* mark data socket with impossible value */ - comm->datafd = -1; - /* default is to ack */ - comm->ack = 1; - /* set default cendian flag */ - comm->cendian = "?"; - /* clear the acl flags */ - for(i=0; i<XPA_CMDS+1; i++){ - comm->acl[i] = -1; - } - - /* add this comm to end of list of comms */ - if( xpa->commhead == NULL ){ - xpa->commhead = comm; - } - else{ - for(cur=xpa->commhead; cur->next!=NULL; cur=cur->next){ - ; - } - cur->next = comm; - } - - /* we might have to add this fd specially to a non-select event loop */ - if( xpa->seladd ) - comm->selcptr = (xpa->seladd)(xpa, comm->cmdfd); - - /* make this fd active */ - XPAActive(xpa, comm, 1); - - FPRINTF((stderr, "%sCommNew: ip=%x port=%d fd=%d\n", _sp, - comm->cmdip, comm->cmdport, comm->cmdfd)); - - /* return the good news */ - return(comm); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: CommFree - * - * Purpose: free a comm record and remove from list - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -CommFree (XPA xpa, XPAComm comm, int flag) -#else -static void CommFree(xpa, comm, flag) - XPA xpa; - XPAComm comm; - int flag; -#endif -{ - XPAComm cur; - - if( !comm ) - return; - - FPRINTF((stderr, "%sCommFree: ip=%x port=%d fd=%d dfd=%d\n", _sp, - comm->cmdip, comm->cmdport, comm->cmdfd, comm->datafd)); - /* remove from list of this xpa's comms */ - if( xpa ){ - if( xpa->commhead ){ - if( xpa->commhead == comm ){ - xpa->commhead = comm->next; - } - else{ - for(cur=xpa->commhead; cur!=NULL; cur=cur->next){ - if( cur->next == comm ){ - cur->next = comm->next; - break; - } - } - } - } - } - /* must check all xpas */ - else{ - for(xpa=xpahead; xpa!=NULL; xpa=xpa->next){ - if( xpa->commhead ){ - if( xpa->commhead == comm ){ - xpa->commhead = comm->next; - } - else{ - for(cur=xpa->commhead; cur!=NULL; cur=cur->next){ - if( cur->next == comm ){ - cur->next = comm->next; - break; - } - } - } - } - } - } - - /* close socket connections */ - if( flag && (comm->cmdfd >= 0) ){ - FPRINTF((stderr, "%sCommFree closing cmd fd: %d\n", _sp, comm->cmdfd)); - /* remove from active */ - if( comm->cmdfd < FD_SETSIZE ) - activefds[comm->cmdfd] = 0; - /* delete the comm cmd fd specially from a non-select event loop */ - if( xpa && xpa->seldel && comm->selcptr ){ - (xpa->seldel)(comm->selcptr); - comm->selcptr = NULL; - } - /* close file */ - xclose(comm->cmdfd); - } - /* close data channel */ - XPACloseData(xpa, comm); - /* if we have a file name (unix sockets), free it */ - if( comm->cmdname != NULL ){ - unlink(comm->cmdname); - xfree(comm->cmdname); - } - if( comm->dataname != NULL ){ - unlink(comm->dataname); - xfree(comm->dataname); - } - - /* free up the space */ - if( comm->id != NULL ) xfree(comm->id); - if( comm->info != NULL ) xfree(comm->info); - if( comm->target != NULL ) xfree(comm->target); - if( comm->paramlist != NULL ) xfree(comm->paramlist); - - /* this comm is no longer associated with an ns */ - if( comm->ns ){ - comm->ns->nproxy -= 1; - } - - /* disassociate from parent xpa */ - if( xpa ){ - xpa->comm = NULL; - } - - /* free up structure */ - xfree(comm); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSOpen - * - * Purpose: open a connection to the name service - * - * Returns: connection fd on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static NS -XPANSOpen (XPA xpa, char *host, int force) -#else -static NS XPANSOpen(xpa, host, force) - XPA xpa; - char *host; - int force; -#endif -{ - int i; - int status; - int xnsfd=0; - int keep_alive=1; - int tries=0; - int ip=0; - int dowarn=0; - int contmode=XPA_CONNECT_TIMEOUT_MODE; - unsigned short xnsport=0; - unsigned int xnsip=0; - static int errinit=0; - char *s; - char *path; - char *method; - char nscmd[SZ_LINE]; - char tbuf[SZ_LINE]; - char tbuf2[SZ_LINE]; - struct sockaddr_in sock_in; - struct passwd *pw; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - char *findname=NULL; - NS ns, cur; - - /* get name server method */ - method = XPANSMethod(host, 0); - - /* if the name service already is open, just return fd */ - if( xpa ){ - for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ - if( !strcmp(ns->method, method) ){ - /* if forcing, see if the connection is valid */ - if( force >= 0 ){ - if( (XPAPuts(xpa, ns->fd, "status\n", stimeout) >0) && - (XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0) && - !strncmp(tbuf, "XPA$OK", 6) ){ - FPRINTF((stderr, "%sXPANSOpen: found existing ns: %s\n", - _sp, ns->method)); - return ns; - } - /* found the ns, but its not open */ - else{ - FPRINTF((stderr, "%sXPANSOpen: existing ns is dead: %s\n", - _sp, ns->method)); - XPANSClose(xpa, ns); - break; - } - } - /* just return whatever we have if we are not forcing */ - else{ - return ns; - } - } - } - } - - /* if no existing ns and flag is negative, we are done */ - if( force == -1 ) - return(NULL); - - /* we always make up the command afresh */ - *nscmd = '\0'; - - /* get users for this user */ - if( (s=(char *)getenv("XPA_NSUSERS")) != NULL ) - strncpy(nsusers, s, SZ_LINE-1); - /* default is just this use's userrname, from the environment */ - else if( (s=(char *)getenv("LOGNAME")) != NULL ) - strncpy(nsusers, s, SZ_LINE-1); -#if HAVE_MINGW32==0 - /* this is a last resort */ - else if( (pw=getpwuid(geteuid())) ) - strncpy(nsusers, pw->pw_name, SZ_LINE-1); -#endif - /* if nothing good has happened, make it "all" */ - if( *nsusers == '\0' ) - strcpy(nsusers, "*"); - /* null-terminate string */ - nsusers[SZ_LINE-1] = '\0'; - - /* set up communications socket for this method */ - switch(mtype){ - case XPA_INET: -again1: - XPAParseIpPort(method, &xnsip, &xnsport); - /* use $localhost over $host (we do not trust host to be correct) */ - if( (xnsip == gethostip("$host")) && (tries == 0) ){ - xnsip = gethostip("$localhost"); - } - if( xnsip == 0 ){ - fprintf(stderr, - "XPA$ERROR: invalid host name specified: %s.\n", method); - return(NULL); - } - if( (xnsfd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) - goto nons; - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = htonl(xnsip); - sock_in.sin_port = htons(xnsport); - /* try connecting to the name server */ - if( ctimeout <= 0 ) contmode = 0; - switch(contmode){ - case 1: -#if HAVE_MINGW32==0 - status=alrmconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); -#else - status=noblkconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); -#endif - break; - case 2: - status=noblkconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); - break; - default: - status=connect(xnsfd, (struct sockaddr *)&sock_in, sizeof(sock_in)); - break; - } - if( status == 0 ){ - FPRINTF((stderr, "%sXPANSOpen: connect to xpans\n", _sp)); - goto okns; - } - else{ - xclose(xnsfd); - /* if localhost doesn't work, make one try with the host ip */ - if( (xerrno == ECONNREFUSED) && (tries < 1) ){ - tries++; - goto again1; - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: -again2: - /* open a socket and fill in socket information */ - if( (xnsfd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) - goto nons; - memset((char *)&sock_un, 0, sizeof(sock_un)); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, method); - xnsip = 0; - /* try connecting to the name server */ - status=connect(xnsfd, (struct sockaddr *)&sock_un, sizeof(sock_un)); - if( status == 0 ){ - FPRINTF((stderr, "%sXPANSOpen: connect to xpans\n", _sp)); - goto okns; - } - else{ - xclose(xnsfd); - /* 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 < retries) ){ - tries++; - XPASleep(10); - goto again2; - } - } - break; -#endif - } - - /* if force is set, we try to start up the name server */ - if( force == 0 ) - goto noforce; - - /* make up the xpans command we will use */ - if( *nscmd == '\0' ){ - if( (mtype == XPA_UNIX) || LOCALIP(xnsip) ){ - path = (char *)getenv("PATH"); - findname = (char *)Find(XPANSNAME, "x", NULL, path); -#if HAVE_CYGWIN - /* this will help start up xpans under Windows */ - if( !findname ) findname = (char *)Find(XPANSNAME, "x", NULL, "."); -#endif - } - if( findname != NULL ){ - switch(mtype){ - case XPA_INET: -#if USE_LAUNCH - /* change spaces to special launch space */ - for(i=0; i<strlen(findname); i++){ - if( findname[i] == ' '){ - findname[i] = LAUNCH_SPACE; - } - } - snprintf(nscmd, SZ_LINE, "%s -e -p %d -l %s/xpans_%d.log", - findname, xnsport, tmpdir, xnsport); -#else - snprintf(nscmd, SZ_LINE, "\"%s\" -e -p %d -l %s/xpans_%d.log &\n", - findname, xnsport, tmpdir, xnsport); -#endif - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: -#if USE_LAUNCH - /* change spaces to special launch space */ - for(i=0; i<strlen(findname); i++){ - if( findname[i] == ' '){ - findname[i] = LAUNCH_SPACE; - } - } - snprintf(nscmd, SZ_LINE, "%s -e -f %s -l %s.log", - findname, method, method); -#else - snprintf(nscmd, SZ_LINE, "\"%s\" -e -f %s -l %s.log &\n", - findname, method, method); -#endif - break; -#endif - } - } - else{ - *nscmd = '\0'; - } - } - - /* did not find the name server -- start it up if we can, i.e., - if its on the same machine as we are on and we found it in the path */ - if((*nscmd != '\0') && ((mtype == XPA_UNIX) || LOCALIP(xnsip)) ){ - FPRINTF((stderr, "%sLaunching: %s\n", _sp, nscmd)); -#if USE_LAUNCH - if( Launch(nscmd, 0, NULL, NULL) != 0 ) - goto nons; -#else - if( system(nscmd) != 0 ) - goto nons; -#endif - /* enter loop looking to connect */ - for(tries=0; tries<retries; tries++){ - switch(mtype){ - case XPA_INET: - /* use $localhost alternately with $host */ - if( (xnsip == gethostip("$host")) && (tries % 2 == 0) ){ - xnsip = gethostip("$localhost"); - } - if( xnsip == 0 ){ - fprintf(stderr, - "XPA$ERROR: invalid host name specified: %s.\n", method); - return(NULL); - } - if( (xnsfd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) - goto nons; - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = htonl(xnsip); - sock_in.sin_port = htons(xnsport); - FPRINTF((stderr, "%sXPANSOPEN: attempting connect to %x\n", - _sp, xnsip)); - if(connect(xnsfd, (struct sockaddr *)&sock_in, sizeof(sock_in)) ==0) - goto okns; - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - if( (xnsfd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) - goto nons; - if(connect(xnsfd, (struct sockaddr *)&sock_un, sizeof(sock_un)) ==0) - goto okns; - break; -#endif - } - xclose(xnsfd); - XPASleep(nsdelay); - } - /* if we got here, we did not connect */ - goto nons; - } - /* name server is on a remote machine, so there is no hope */ - else{ - goto nons; - } - -okns: - /* make sure we close on exec */ - xfcntl(xnsfd, F_SETFD, FD_CLOEXEC); - setsockopt(xnsfd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - /* fill in new record */ - if( (ns = (NS)xcalloc(1, sizeof(NSRec))) == NULL ){ - xclose(xnsfd); - return NULL; - } - ns->method = xstrdup(method); - ns->host = xstrdup(host); - ns->fd = xnsfd; - FPRINTF((stderr, "%sXPANSOpen: host %s opened on fd %d\n", _sp, - host?host:"<unknown>", xnsfd)); - switch(mtype){ - case XPA_INET: - ns->ip = xnsip; - ns->port = xnsport; - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - ns->name = xstrdup(method); - break; -#endif - } - if( xpa ){ - /* add to list of name servers */ - if( xpa->nshead == NULL ){ - xpa->nshead = ns; - } - else{ - for(cur=xpa->nshead; cur->next!=NULL; cur=cur->next) - ; - cur->next = ns; - } - } - /* check version with xpans */ - snprintf(tbuf, SZ_LINE, "version %s\n", XPA_VERSION); - if( (XPAPuts(xpa, ns->fd, tbuf, stimeout) >0) && - (XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0) ){ - if( word(tbuf, tbuf2, &ip) ){ - if( !strcmp(tbuf2, "XPA$VERSION") ){ - if( word(tbuf, tbuf2, &ip) ){ - /* version check: our server version should be <= xpans version */ - dowarn = (XPAVersionCheck(XPA_VERSION, tbuf2)>0); - } - else{ - strcpy(tbuf2, "unknown/pre-2.1 (noversion)"); - dowarn = 1; - } - } - else{ - strcpy(tbuf2, "unknown/pre-2.1 (badformat)"); - dowarn = 1; - } - } - FPRINTF((stderr, "%sXPANSOpen: version info: %s\n", _sp, tbuf)); - if( dowarn ){ - XPAVersionWarn(XPA_VERSION, tbuf2); - } - } - - /* clean up */ - if( findname != NULL ) xfree(findname); - return(ns); - -nons: - /* if we specified an explicit port, we don't need the name server, - so don't bother with any warning or error messages */ - if( XPAPort(xpa) >0 ) - return NULL; - switch(mtype){ - case XPA_INET: - if( !errinit && verbosity ){ - if( LOCALIP(xnsip) ){ - fprintf(stderr, - "XPA$WARNING: xpans needs to be running on this machine.\n"); - } - else{ - fprintf(stderr, - "XPA$WARNING: xpans needs to be running on machine: "); - fprintf(stderr, "%s\n", getiphost(xnsip)); - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - if( !errinit && verbosity ){ - fprintf(stderr, - "XPA$WARNING: xpans needs to be running on this machine.\n"); - } - break; -#endif - default: - break; - } - if( xpa && verbosity ){ - if( !errinit ){ - /* make up the command users will need to start xpans */ - if( *nscmd == '\0' ){ - switch(mtype){ - case XPA_INET: - snprintf(nscmd, SZ_LINE, "xpans -e -p %d -l %s/xpans_%d.log", - xnsport, tmpdir, xnsport); - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - snprintf(nscmd, SZ_LINE, "xpans -e -f %s -l %s.log", method, method); - break; -#endif - } - } - fprintf(stderr, "Please start xpans using the command:\n\t%s\n", nscmd); - fprintf(stderr, "Once xpans is running, register all xpas in this process using:\n"); - fprintf(stderr, "\txpaset -p %s -nsconnect\n", xpa->method); - } - fprintf(stderr, "For now, contact %s using:", xpa->name); - fprintf(stderr, " xpaset %s .. or xpaget %s ..\n", - xpa->method, xpa->method); - } - errinit++; - -noforce: - if( findname != NULL ) xfree(findname); - return(NULL); -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: _XPAFree - * - * Purpose: free up memory in the XPA record structure - * (internal version) - * - * Results: 0 on success, -1 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static int -_XPAFree (XPA xpa) -#else -static int _XPAFree(xpa) - XPA xpa; -#endif -{ - char tbuf[SZ_LINE]; - XPACmd cmd, tcmd; - XPAComm comm, tcomm; - XPAClip clip, tclip; - NS ns, tns; - - /* make sure we have something to do */ - if( xpa == NULL ) - return(-1); - - FPRINTF((stderr, "%s_XPAFree: freeing xpa struct\n", _sp)); - /* remove this xpa from public availability */ - if( xpa->type != NULL ) - XPANSDel(xpa, NULL, NULL); - - /* free all sub-commands */ - for(cmd=xpa->commands; cmd!=NULL; ){ - tcmd = cmd->next; - XPACmdDel(xpa, cmd); - cmd = tcmd; - } - - /* remove from list of xpas */ - XPAListDel(&xpahead, xpa); - - /* close down listening socket */ - if( xpa->fd >= 0 ) - xclose(xpa->fd); - - /* perform method-specific cleanup */ - switch(mtype){ -#if HAVE_SYS_UN_H - case XPA_UNIX: - /* delete the unix socket files */ - unlink(xpa->method); - snprintf(tbuf, SZ_LINE, "%s_data", xpa->method); - unlink(tbuf); - break; -#endif - default: - break; - } - - /* free up space */ - if( xpa->version ) xfree(xpa->version); - if( xpa->type ) xfree(xpa->type); - if( xpa->method ) xfree(xpa->method); - if( xpa->xclass ) xfree(xpa->xclass); - if( xpa->name ) xfree(xpa->name); - if( xpa->help ) xfree(xpa->help); - if( xpa->sendian ) xfree(xpa->sendian); - - /* call the select free routine for the listening socket and loop type. - we use an indirect routine to avoid having to link Xt, Tcl, etc. */ - if( xpa->seldel && xpa->selptr ){ - (xpa->seldel)(xpa->selptr); - xpa->selptr = NULL; - } - - /* close communication channels */ - for(comm=xpa->commhead; comm!=NULL; ){ - tcomm = comm->next; - CommFree(xpa, comm, 1); - comm = tcomm; - } - - /* free up clipboards */ - for(clip=xpa->cliphead; clip!=NULL; ){ - tclip = clip->next; - ClipBoardFree(xpa, clip); - clip = tclip; - } - - /* 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 up record struct */ - xfree((char *)xpa); - - return(0); -} - -#if HAVE_ATEXIT -/* - *--------------------------------------------------------------------------- - * - * Routine: _XPAAtExit - * - * Purpose: XPA cleanup on exit - * The main purpose of this routine is to try to delete the - * unix socket files when an XPA server exits. - * - * Results: none - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -static void -_XPAAtExit (void) -#else -static void _XPAAtExit() -#endif -{ - XPA xpa, txpa; - static int done=0; - - if( !done ){ - /* return if we were not initialized */ - if( !atexitinit ) return; - /* return if I am not the process who initialized (I'm a child) */ - if( atexitinit != getpid() ) return; - FPRINTF((stderr, "calling XPAAtExit\n")); - for(xpa=xpahead; xpa!=NULL; ){ - /* use temp in case we destroy structure in the cleanup */ - txpa = xpa->next; - _XPAFree(xpa); - xpa = txpa; - } - /* platform-dependent cleanup */ - xsocketcleanup(); - /* done with cleanup */ - done++; - } -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAAtExit - * - * Purpose: set up XPA cleanup on exit - * - * Results: none - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAAtExit (void) -#else -void XPAAtExit() -#endif -{ - if( !atexitinit ){ - atexit(_XPAAtExit); - atexitinit = getpid(); - } -} - -#endif - -/* - *---------------------------------------------------------------------------- - * - * - * Semi-Public Routines - * (mainly used by xpaset and xpaget) - * - * - *---------------------------------------------------------------------------- - */ - -/* - *--------------------------------------------------------------------------- - * - * Routine: _XPAValid - * - * Purpose: see if the xpa struct is valid - * - * Results: 1 on success, 0 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -_XPAValid (XPA head, XPA xpa, char *type) -#else -int _XPAValid(head, xpa, type) - XPA head; - XPA xpa; - char *type; -#endif -{ - XPA cur; - - if( xpa == NULL ) - return(0); - for(cur=head; cur!=NULL; cur=cur->next){ - if( (cur == xpa) && !strcspn(cur->type, type) ){ - return(1); - } - } - return(0); -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAValid - * - * Purpose: see if the xpa struct is valid - * - * Results: 1 on success, 0 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAValid (XPA xpa) -#else -int XPAValid(xpa) - XPA xpa; -#endif -{ - if( _XPAValid(xpahead, xpa, XPA_ACLS) ) - return(1); - else - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAEndian - * - * Purpose: semi-public routine to return the endian-ness of this - * machine - * - * Results: 0 if little endian, 1 if bigendian - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAEndian(void) -#else -int XPAEndian() -#endif -{ - union - { - long l; - char c[sizeof (long)]; - } u; - u.l = 1; - return(u.c[sizeof (long) - 1] == 1); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAListHead - * - * Purpose: semi-public routine to return the head of the xpa list - * - * Results: XPA list pointer on success - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -XPA -XPAListHead (void) -#else -XPA XPAListHead() -#endif -{ - return(xpahead); -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAListAdd - * - * Purpose: add a member of an xpa list - * - * Results: 1 on success, 0 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAListAdd (XPA *head, XPA xpa) -#else -void XPAListAdd(head, xpa) - XPA *head; - XPA xpa; -#endif -{ - XPA cur; - - if( *head == NULL ){ - *head = xpa; - } - else{ - for(cur=*head; cur->next!=NULL; cur=cur->next) - ; - cur->next = xpa; - } -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAListDel - * - * Purpose: remove a member of an xpa list - * - * Results: 1 on success, 0 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAListDel (XPA *head, XPA xpa) -#else -void XPAListDel(head, xpa) - XPA *head; - XPA xpa; -#endif -{ - XPA cur; - - /* remove from list of xpas */ - if( *head ){ - if( *head == xpa ){ - *head = xpa->next; - } - else{ - for(cur=*head; cur!=NULL; cur=cur->next){ - if( cur->next == xpa ){ - cur->next = xpa->next; - break; - } - } - } - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAActive - * - * Purpose: make the xpa, cmd and data fds active or inactive for select - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAActive (XPA xpa, XPAComm comm, int flag) -#else -int XPAActive(xpa, comm, flag) - XPA xpa; - XPAComm comm; - int flag; -#endif -{ - int prev=0; - - /* sanity check */ - if( !xpa ) return(0); - - switch(flag){ - /* remove this xpa from the active list */ - case 0: - if( (xpa->fd >= 0) && (xpa->fd < FD_SETSIZE) ){ - FPRINTF((stderr, "%sXPAActive: clearing fd %d\n", _sp, xpa->fd)); - prev = activefds[xpa->fd]; - activefds[xpa->fd] = 0; - if( xpa->seloff && xpa->selptr ) - (xpa->seloff)(xpa->selptr); - } - if( comm ){ - if( (comm->cmdfd >= 0) && (comm->cmdfd < FD_SETSIZE) ){ - activefds[comm->cmdfd] = 0; - if( xpa->seloff && comm->selcptr ) - (xpa->seloff)(comm->selcptr); - } - if( (comm->datafd >= 0) && (comm->datafd < FD_SETSIZE) ){ - activefds[comm->datafd] = 0; - if( xpa->seloff && comm->seldptr ) - (xpa->seloff)(comm->seldptr); - } - } - break; - /* add this xpa/comm to the active list */ - case 1: - if( (xpa->fd >= 0) && (xpa->fd < FD_SETSIZE) ){ - FPRINTF((stderr, "%sXPAActive: activating fd %d\n", _sp, xpa->fd)); - prev = activefds[xpa->fd]; - activefds[xpa->fd] = 1; - if( xpa->selon && xpa->selptr ) - (xpa->selon)(xpa->selptr); - } - if( comm ){ - if( (comm->cmdfd >= 0) && (comm->cmdfd < FD_SETSIZE) ){ - activefds[comm->cmdfd] = 1; - if( xpa->selon && comm->selcptr ) - (xpa->selon)(comm->selcptr); - } - if( (comm->datafd >= 0) && (comm->datafd < FD_SETSIZE) ){ - activefds[comm->datafd] = 1; - if( xpa->selon && comm->seldptr ) - (xpa->selon)(comm->seldptr); - } - } - break; - default: - break; - } - return(prev); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAActiveFd - * - * Purpose: semi-public routine to return flag if fd is active - * - * Results: 1 is active, 0 is inactive - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAActiveFd (int fd) -#else -int XPAActiveFd(fd) - int fd; -#endif -{ - if( (fd >= 0) && (fd < FD_SETSIZE) && (activefds[fd] > 0) ) - return(1); - else - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAAddSelect - * - * Purpose: add one or more xpa sockets to the select flags - * - * Return: number of xpas that were added to the select flags - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAAddSelect (XPA xpa, fd_set *readfdsptr) -#else -int XPAAddSelect(xpa, readfdsptr) - XPA xpa; - fd_set *readfdsptr; -#endif -{ - XPA cur; - XPAComm comm; - int got=0; - - /* better have some place to set the flags */ - if( readfdsptr == NULL ) - return(0); - - /* if a specific xpa was specified, just set its select flags */ - if( xpa != NULL ){ - if( XPAActiveFd(xpa->fd) ){ - FD_SET(xpa->fd, readfdsptr); - got++; - /* note that we only select on coms if the main fd is active */ - for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ - if( XPAActiveFd(comm->cmdfd) ){ - FD_SET(comm->cmdfd, readfdsptr); - got++; - } - if( XPAActiveFd(comm->datafd) && (comm->datafd != comm->cmdfd) ){ - FD_SET(comm->datafd, readfdsptr); - got++; - } - } - } - } - /* otherwise set select flags for all xpas */ - else{ - for(cur=xpahead; cur!=NULL; cur=cur->next){ - if( XPAActiveFd(cur->fd) ){ - FPRINTF((stderr, "%sXPAAddSelect: adding fd %d\n", _sp, cur->fd)); - FD_SET(cur->fd, readfdsptr); - got++; - /* note that we only select on coms if the main fd is active */ - for(comm=cur->commhead; comm!=NULL; comm=comm->next){ - if( XPAActiveFd(comm->cmdfd) ){ - FPRINTF((stderr, "%sXPAAddSelect: adding cmdfd %d\n", - _sp, comm->cmdfd)); - FD_SET(comm->cmdfd, readfdsptr); - got++; - } - if( XPAActiveFd(comm->datafd) && (comm->datafd != comm->cmdfd) ){ - FPRINTF((stderr, "%sXPAAddSelect: adding datafd %d\n", - _sp, comm->datafd)); - FD_SET(comm->datafd, readfdsptr); - got++; - } - } - } - } - } - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAProcessSelect - * - * Purpose: process xpas that have pending reads or writes - * - * Return: number of xpas processed - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAProcessSelect (fd_set *readfdsptr, int maxreq) -#else -int XPAProcessSelect(readfdsptr, maxreq) - fd_set *readfdsptr; - int maxreq; -#endif -{ - int got=0; - XPA xpa; - XPAComm comm; -#ifdef OLD - XPA txpa; - XPAComm tcomm; -#endif - - /* <= 0 means do all of them */ - if( maxreq < 0 ){ - maxreq = 0; - } - -again: - for(xpa=xpahead; xpa!=NULL; xpa=xpa->next){ - /* handle command requests */ - for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ - if( (comm->cmdfd >=0) && FD_ISSET(comm->cmdfd, readfdsptr) ){ - FD_CLR(comm->cmdfd, readfdsptr); - XPAHandler(xpa, comm->cmdfd); - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - } - /* handle data requests */ - for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ - if( (comm->datafd >=0) && FD_ISSET(comm->datafd, readfdsptr) ){ - FD_CLR(comm->datafd, readfdsptr); - XPAHandler(xpa, comm->datafd); - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - } - /* handle new requests */ - if( (xpa->fd >= 0) && FD_ISSET(xpa->fd, readfdsptr) ){ - FD_CLR(xpa->fd, readfdsptr); - XPAHandler(xpa, xpa->fd); - got++; - if( maxreq && (got >= maxreq) ) return(got); - goto again; - } - } - -#ifdef OLD - for(xpa=xpahead; xpa!=NULL; ){ - txpa = xpa->next; - /* handle command requests */ - for(comm=xpa->commhead; comm!=NULL; ){ - tcomm = comm->next; - if( (comm->cmdfd >=0) && FD_ISSET(comm->cmdfd, readfdsptr) ){ - FD_CLR(comm->cmdfd, readfdsptr); - FPRINTF((stderr, "%sXPAProcessSelect: cmd %d\n", _sp, comm->cmdfd)); - /* if we got an error on this xpa, skip processing rest of it */ - if( XPAHandler(xpa, comm->cmdfd) != XPA_RTN_OK ){ - goto nextxpa; - } - got++; - /* if we freed this xpa, skip processing rest of it */ - if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ - goto nextxpa; - } - /* if we are have processed the max reqests, we are done */ - if( maxreq && (got >= maxreq) ){ - return(got); - } - } - comm = tcomm; - } - /* handle data requests */ - for(comm=xpa->commhead; comm!=NULL; ){ - tcomm = comm->next; - if( (comm->datafd >=0) && FD_ISSET(comm->datafd, readfdsptr) ){ - FD_CLR(comm->datafd, readfdsptr); - FPRINTF((stderr, "%sXPAProcessSelect: data %d\n", _sp, comm->datafd)); - /* if we got an error on this xpa, skip processing rest of it */ - if( XPAHandler(xpa, comm->datafd) != XPA_RTN_OK ){ - goto nextxpa; - } - got++; - /* if we freed this xpa, skip processing rest of it */ - if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ - goto nextxpa; - } - /* if we are have processed the max reqests, we are done */ - if( maxreq && (got >= maxreq) ){ - return(got); - } - } - comm = tcomm; - } - /* handle new requests */ - if( (xpa->fd >= 0) && FD_ISSET(xpa->fd, readfdsptr) ){ - FD_CLR(xpa->fd, readfdsptr); - FPRINTF((stderr, "%sXPAProcessSelect: xpa %d\n", _sp, xpa->fd)); - /* if we got an error on this xpa, skip processing rest of it */ - if( XPAHandler(xpa, xpa->fd) != XPA_RTN_OK ){ - goto nextxpa; - } - got++; - /* if we freed this xpa, skip processing rest of it */ - if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ - goto nextxpa; - } - /* if we are have processed the max reqests, we are done */ - if( maxreq && (got >= maxreq) ){ - return(got); - } - } - -nextxpa: - /* must check to see if last xpa freed the next xpa */ - if( _XPAValid(xpahead, txpa, XPA_ACLS) ) - xpa = txpa; - else - break; - } -#endif - FPRINTF((stderr, "%sXPAProcessSelect: returns %d\n", _sp, got)); - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPACloseData - * - * Purpose: close data fd if its not the cmd fd - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPACloseData (XPA xpa, XPAComm comm) -#else -void XPACloseData(xpa, comm) - XPA xpa; - XPAComm comm; -#endif -{ - /* we close the data channel if its not the command channel */ - if( comm && (comm->datafd >=0) ){ - if( comm->cmdfd != comm->datafd ){ - FPRINTF((stderr, "%sXPACloseData: close fd %d for cmd fd %d\n", _sp, - comm->datafd, comm->cmdfd)); - /* remove from active */ - if( comm->datafd < FD_SETSIZE ) - activefds[comm->datafd] = 0; - /* delete the comm data fd specially from a non-select event loop */ - if( xpa && xpa->seldel && comm->seldptr ){ - (xpa->seldel)(comm->seldptr); - comm->seldptr = NULL; - } - /* close file */ - xclose(comm->datafd); - } - /* reset data channel to impossible value */ - comm->datafd = -1; - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAHandler - * - * Purpose: handle one request for an xpaset or xpaget - * - * Return: 0 on success, xpa error code on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAHandler (XPA xpa, int fd) -#else -int XPAHandler(xpa, fd) - XPA xpa; - int fd; -#endif -{ - char tbuf[SZ_LINE]; - char tbuf2[SZ_LINE]; - char lbuf[SZ_LINE]; - char cmd[SZ_LINE]; - char target[SZ_LINE]; - char method[SZ_LINE]; - char ctmpl[SZ_LINE]; - char ntmpl[SZ_LINE]; - char *paramlist=NULL; - char *acl; - int save_ack; - int tcmd; - int got=0; - int lp=0; - int cmdfd=-1; - unsigned short port=0; - unsigned int ip=0; - struct timeval tv; - XPAComm comm=NULL, tcomm=NULL, xcomm=NULL, ocomm=NULL; - XPA txpa=NULL; - NS ns=NULL; - fd_set readfds; - FPRINTF((stderr, "%sXPAHandler: entering with fd %d\n", _sp, fd)); - - /* this is a defensive measure: we have to guard against an external - loop calling the XPA handler with a bogus XPA record. This has been - seen with the Tcl event loop. - */ - for(txpa=xpahead; txpa!=NULL; txpa=txpa->next){ - if( txpa == xpa ) break; - } - if( txpa == NULL ){ - FPRINTF((stderr, "%sXPAHandler: xpa record %p is not in list\n", - _sp, xpa)); - return(XPA_RTN_NOCMD); - } - - /* this is a defensive measure: we have to ensure that there really - * is a request read. It is possible that a user-defined select loop - * might call us to handle a request that we had already handled - * (i.e. we handle a request but can't reset someone else's select flags) - */ - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - while( xselect(fd+1, &readfds, NULL, NULL, &tv) <=0 ){ - if( xerrno == EINTR ) - continue; - FPRINTF((stderr, "%sXPAHandler: xpa fd %d is not ready\n", _sp, fd)); - return(XPA_RTN_NOCMD); - } - - /* if this is a first connection, we create a new comm channel and exit */ - if( fd == xpa->fd ){ - if( (comm = CommNew(xpa, -1, 0, 0, NULL, NULL)) == NULL ) - return(XPA_RTN_NOCONN); - /* Return to prevent xpa from finishing before other xpa's are started. - Otherwise, each xpa's associated with a target template will be - processed serially, which will defeat all the hard work done on - the client side to send data to servers when they ask for it. - */ - else{ - FPRINTF((stderr, "%sXPAHandler: returning after CommNew on fd %d\n", - _sp, fd)); - got = XPA_RTN_OK; - goto end; - } - } - - /* look for a currently active comm channel: cmd or data */ - for(comm=xpa->commhead; comm!= NULL; comm=comm->next){ - if( (fd == comm->cmdfd) || (fd == comm->datafd) ){ - break; - } - } - /* make sure we have something */ - if( comm == NULL ){ - /* read extraenous message */ - if( XPAGets(xpa, fd, tbuf, SZ_LINE, 1) >0 ){ - got = XPA_RTN_UNCMD; - FPRINTF((stderr, "%sXPAHandler: fd %d received extra message:\n%s\n", - _sp, fd, tbuf)); - } - else{ - FPRINTF((stderr, "%sXPAHandler: no active comm record for fd %d\n", - _sp, fd)); - got = XPA_RTN_NOCMD2; - } - goto error; - } - /* but don't recurse */ - if( comm->status & XPA_STATUS_ACTIVE ){ - FPRINTF((stderr, "%sXPAHandler: fd %d returning to avoid recursion\n", - _sp, fd)); - got = 0; - goto end; - } - /* set current comm for this xpa */ - ocomm = xpa->comm; - xpa->comm = comm; - /* no message sent yet */ - comm->message = 0; - - /* data ready on data channel: go right to data handling section */ - if( fd == comm->datafd ){ - FPRINTF((stderr, "%sXPAHandler: jumping to cb for %d\n", _sp, fd)); - goto cb; - } - - /* cmd channel: we are processing a new command */ -retry: - /* reset line buffer pointer for parsing */ - lp = 0; - /* read next command */ - if( XPAGets(xpa, comm->cmdfd, lbuf, SZ_LINE, stimeout) <=0 ){ - FPRINTF((stderr, "%sXPAHandler: fd %d read EOF\n", _sp, comm->cmdfd)); - got = XPA_RTN_OK; - goto eof; - } - /* new-lines imply we entered telnet mode on local host */ - else if( (*lbuf == '\n') || (*lbuf == '\r') || !strcmp(lbuf, "telnet") ){ - if( (mtype == XPA_UNIX) || LOCALIP(comm->cmdip) ){ - if( comm->telnet == 0 ) - XPAPuts(xpa, comm->cmdfd, "Entering telnet mode ...\n", stimeout); - comm->telnet = 1; - comm->ack = 0; - comm->datafd = comm->cmdfd; - stimeout = -1; - goto retry; - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - } - - FPRINTF((stderr, "%sXPAHandler: fd %d read command: %s", - _sp, comm->cmdfd, lbuf)); - - /* validate the command */ - if( !word(lbuf, cmd, &lp) ){ - FPRINTF((stderr, "%sXPAHandler: missing target for fd %d\n", - _sp, comm->cmd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - - /* send help message (local support only) */ - if( !strcmp(cmd, "help") ){ - if( (mtype == XPA_UNIX) || LOCALIP(comm->cmdip) ){ - XPAPuts(xpa, comm->cmdfd, - "xpaset|xpaget|xpainfo|xpaaccess [switches] class:name [params]\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "switches:\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-a\t\tclient wants to accept() data connection\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-e <b|l>\tclient endian-ness: big(b) or little(l)\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-i id\t\tclient id string\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-p <proxyinfo>\t\tfrom xpans (e.g., for proxy processing)\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-n\t\tdon't ack back to client\n", - stimeout); - XPAPuts(xpa, comm->cmdfd, - "\t-t\t\tenter telnet mode (local only)\n", - stimeout); - /* we must be in telnet mode */ - comm->telnet = 1; - comm->ack = 0; - goto retry; - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - } - - /* determine which command was specified */ - if( !strcmp(cmd, "xpaset") ) - tcmd = XPA_SET; - else if( !strcmp(cmd, "xpaget") ) - tcmd = XPA_GET; - else if( !strcmp(cmd, "xpainfo") ) - tcmd = XPA_INFO; - else if( !strcmp(cmd, "xpaaccess") ) - tcmd = XPA_ACCESS; - else if( !strcmp(cmd, "xpadata") ) - tcmd = XPA_DATA; - else if( !strcmp(cmd, "xpaaccept") ) - tcmd = XPA_ACCEPT; - else if( !strcmp(cmd, "xpanagle") || !strcmp(cmd, "XPA$OK") ) - tcmd = XPA_NAGLE; - else{ - FPRINTF((stderr, "%sXPAHandler: unknown command '%s' for fd %d\n", - _sp, cmd, comm->cmdfd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - - /* process switches */ - while( word(lbuf, tbuf, &lp) ){ - if( *tbuf != '-' ) - break; - if( !strcmp(tbuf, "-a") ){ - comm->mode |= COMM_CONNECT; - } - else if( !strcmp(tbuf, "-e") ){ - if( word(lbuf, tbuf, &lp) ){ - if( *tbuf == 'b' ) - comm->cendian = "big"; - else if( *tbuf == 'l' ) - comm->cendian = "little"; - } - else{ - got = XPA_RTN_ILLCMD; - goto error; - } - } - else if( !strcmp(tbuf, "-f") ){ - /* B.Schoenhammer@bit-field.de 2009-09-21 */ -#if HAVE_MINGW32==0 - if( !word(lbuf, tbuf, &lp) || (sscanf(tbuf, "%p", &xcomm) != 1) ){ -#else - if( !word(lbuf, tbuf, &lp) || (sscanf(tbuf, "%x", &xcomm) != 1) ){ -#endif - got = XPA_RTN_ILLCMD; - goto done; - } - if( !word(lbuf, tbuf, &lp) || ((cmdfd = atoi(tbuf)) < 0) ){ - got = XPA_RTN_ILLCMD; - goto done; - } - } - else if( !strcmp(tbuf, "-i") ){ - if( word(lbuf, tbuf, &lp) ){ - if( comm->id != NULL ) xfree(comm->id); - comm->id = xstrdup(tbuf); - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); - got = XPA_RTN_ILLCMD; - goto error; - } - } - else if( !strcmp(tbuf, "-n") ){ - comm->ack = 0; - } - else if( !strcmp(tbuf, "-p") ){ - if( word(lbuf, tbuf, &lp) ){ - if( comm->info != NULL ) xfree(comm->info); - comm->info = xstrdup(tbuf); - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); - got = XPA_RTN_ILLCMD; - goto error; - } - } - else if( !strcmp(tbuf, "-t") ){ - comm->telnet = 1; - } - else{ - break; - } - } - - /* make sure we have some sort of id */ - if( comm->id == NULL ){ - comm->id = xstrdup("?"); - } - - /* process nagle ack */ - if( tcmd == XPA_NAGLE ){ - /* if data is forthcoming, exit and wait for data */ - if( comm->usebuf ){ - got = XPA_RTN_OK; - goto end; - } - /* go process callback */ - else{ - goto cb; - } - } - - /* connect (proxy) request: connect back to client */ - if( tcmd == XPA_ACCEPT ){ - FPRINTF((stderr, "%scmd is xpaaccept from client %d: %s", _sp, fd, lbuf)); - /* syntax: xpaaccept <method> ... */ - lp = 0; - if( !word(lbuf, tbuf, &lp) || - strcmp(tbuf, "xpaaccept") || - !word(lbuf, method, &lp) ){ - got = -1; - goto error; - } - if( (cmdfd=XPAProxyConnect(xpa, method, &ip, &port, tbuf)) <0 ){ - FPRINTF((stderr, "%sXPAProxyConnect failed for: %d\n", _sp, fd)); - got = -1; - goto error; - } - if( (tcomm = CommNew(xpa, cmdfd, ip, port, method, NULL)) == NULL ){ - got = XPA_RTN_NOCONN; - goto error; - } - else{ - /* now exit and wait for client to send command */ - FPRINTF((stderr, - "%sXPAHandler: fd %d exiting after proxy connect\n", _sp, - tcomm->cmdfd)); - got = XPA_RTN_OK; - goto end; - } - } - - /* data request: find associated command request, and process the command */ - if( tcmd == XPA_DATA ){ - FPRINTF((stderr, "%sXPAHandler: processing data fd %d\n", - _sp, comm->cmdfd)); - /* find the cmd record with which this data is associated */ - for(tcomm=xpa->commhead; tcomm!= NULL; tcomm=tcomm->next){ - if( (tcomm == xcomm) && (tcomm->cmdfd == cmdfd) ){ - break; - } - } - /* if we found an associated command, copy in data info and process */ - if( tcomm ){ - /* fill in command comm */ - tcomm->datafd = comm->cmdfd; - tcomm->seldptr = comm->selcptr; - if( tcomm->dataname ) xfree(tcomm->dataname); - tcomm->dataname = xstrdup(comm->cmdname); - /* done with data comm */ - CommFree(xpa, comm, 0); - /* reset comm pointers */ - comm = tcomm; - xpa->comm = comm; - FPRINTF((stderr, "%sXPAHandler: found cmd fd %d for this data fd %d\n", - _sp, comm->cmdfd, comm->datafd)); - if( comm->cmd == XPA_SET ){ - FPRINTF((stderr, "%sXPAHandler: data %d returning await xpaset\n", - _sp, comm->datafd)); - got = XPA_RTN_OK; - goto end; - } - else{ - FPRINTF((stderr, "%sXPAHandler: data %d going on to process data\n", - _sp, comm->datafd)); - goto cb; - } - } - else{ - FPRINTF((stderr, "%sXPAHandler: data fd has no corresponding cmd %d\n", - _sp, comm->cmdfd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); - got = XPA_RTN_ILLCMD; - goto error; - } - } - - /* for a command, the first non-switch word we found was the target */ - if( *tbuf == '\0' ){ - FPRINTF((stderr, "%sXPAHandler: missing target for fd %d\n", - _sp, comm->cmdfd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - else{ - strcpy(target, tbuf); - } - - /* validate the target (except for xpans for use as proxy) */ - if( strcmp(xpa->xclass, XPANS_CLASS) || strcmp(xpa->name, XPANS_NAME) ){ - XPAParseName(target, ctmpl, ntmpl, SZ_LINE); - if( (strcmp(ctmpl,"?") && !tmatch(xpa->xclass, ctmpl)) || - (strcmp(ntmpl,"?") && !tmatch(xpa->name, ntmpl)) ){ - got = XPA_RTN_NOTARG; - goto error; - } - } - if( comm->target != NULL ) xfree(comm->target); - comm->target = xstrdup(target); - - /* the rest of the input string is paramlist */ - paramlist = &(lbuf[lp]); - nowhite(paramlist, paramlist); - if( comm->paramlist != NULL ) xfree(comm->paramlist); - comm->paramlist = xstrdup(paramlist); - /* save command */ - comm->cmd = tcmd; - - FPRINTF((stderr, - "%sXPAHandler: processing command fd %d for target %s (%d)\n", - _sp, comm->cmdfd, target, comm->cmd)); - - /* a reserved command can only be called from the same host as the server, - or from local (unix) sockets */ - lp = 0; - if( XPACmdLookupReserved(xpa, comm->paramlist, &lp) ){ - comm->mode |= COMM_RESERVED; - } - - /* set up command-specific info */ - switch(comm->cmd){ - case XPA_SET: - if( comm->mode & COMM_RESERVED ){ - comm->usebuf = 1; - comm->useacl = guseacl && (mtype != XPA_UNIX); - acl = "s"; - } - else if( xpa->receive_callback ){ - comm->usebuf = (xpa->receive_mode & XPA_MODE_BUF); - comm->useacl = guseacl && - (xpa->receive_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); - acl = "s"; - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_NOREC]); - got = XPA_RTN_NOREC; - goto error; - } - break; - case XPA_GET: - if( comm->mode & COMM_RESERVED ){ - comm->usebuf = 1; - comm->useacl = guseacl && (mtype != XPA_UNIX); - acl = "g"; - } - else if( xpa->send_callback ){ - comm->usebuf = (xpa->send_mode & XPA_MODE_BUF); - comm->useacl = guseacl && - (xpa->send_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); - acl = "g"; - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_NOSEND]); - got = XPA_RTN_NOSEND; - goto error; - } - break; - case XPA_INFO: - if( xpa->info_callback ){ - comm->usebuf = 0; - comm->useacl = guseacl && - (xpa->info_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); - acl = "i"; - } - else{ - XPAError(xpa, xpaMessbuf[XPA_RTN_NOINFO]); - got = XPA_RTN_NOINFO; - goto error; - } - break; - case XPA_ACCESS: - comm->usebuf = 0; - comm->useacl = guseacl && (mtype != XPA_UNIX); - /* may as well check access mode as well */ - snprintf(tbuf2, SZ_LINE, "%sa%s", _sp, comm->paramlist?comm->paramlist:""); - acl = tbuf2; - break; - default: - FPRINTF((stderr, "%sXPAHandler: invalid access control check for fd %d\n", - _sp, comm->cmdfd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); - got = XPA_RTN_NOCMD; - goto error; - } - - /* perform access authentication */ - if( comm->useacl ){ - /* determine acl for this ip, if necessary */ - if( comm->acl[comm->cmd] < 0 ){ - comm->acl[comm->cmd] = XPAAclCheck(xpa, comm->cmdip, acl); - } - /* check acl */ - if( comm->acl[comm->cmd] <= 0 ){ - FPRINTF((stderr, "%sXPAHandler: fd %d FAILED acl check\n", - _sp, comm->cmdfd)); - XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); - got = XPA_RTN_NOAUTH; - goto error; - } - FPRINTF((stderr, "%sXPAHandler: fd %d passed acl check\n", - _sp, comm->cmdfd)); - } - - /* for telnet mode, just use cmdfd for data */ - if( comm->telnet ){ - comm->datafd = comm->cmdfd; - } - /* for xpainfo and no ack, just go to the vallback */ - else if( (comm->cmd == XPA_INFO) && !comm->ack ){ - goto cb; - } - /* in general, we must tell the client how we will handle data */ - else{ - if( comm->usebuf ){ - if( comm->mode & COMM_CONNECT ){ - snprintf(lbuf, SZ_LINE, "%s XPA$DATA accept %p %d (%s:%s %s)\n", - comm->id, comm, comm->cmdfd, - xpa->xclass, xpa->name, xpa->method); - } - else{ - snprintf(lbuf, SZ_LINE, "%s XPA$DATA connect %p %d (%s:%s %s)\n", - comm->id, comm, comm->cmdfd, - xpa->xclass, xpa->name, xpa->method); - } - } - /* no data channel being set up */ - else{ - snprintf(lbuf, SZ_LINE, "%s XPA$NODATA (%s:%s %s)\n", - comm->id, xpa->xclass, xpa->name, xpa->method); - } - FPRINTF((stderr, "%sXPAHandler: fd %d sends string: %s", - _sp, comm->cmdfd, lbuf)); - if( XPAPuts(xpa, comm->cmdfd, lbuf, stimeout) <= 0 ){ - FPRINTF((stderr, "%sXPAHandler: fd %d couldn't send string: %s", - _sp, comm->cmdfd, lbuf)); - got = -1; - goto error; - } - /* now exit and wait for nagle ack and for client to send data */ - FPRINTF((stderr, - "%sXPAHandler: fd %d exiting to wait for nagle or connect req\n", - _sp, comm->cmdfd)); - got = XPA_RTN_OK; - goto end; - } - - /* data channel complete (or no data): ready to execute the user callback */ -cb: - /* we are now active */ - comm->status |= XPA_STATUS_ACTIVE; - - /* remove the current comm from the list of active fds, - in case the server callback re-enters the event loop */ - XPAActive(xpa, comm, 0); - - /* zero out buf and len, just to make sure (don't free buf, in case - application is using previous) */ - comm->buf = NULL; - comm->len = 0; - - /* if we are not ack'ing after callback, do it now so client can exit */ - /* but don't do this for xpainfo/noack */ - if( !comm->ack && (comm->cmd != XPA_INFO) ){ - FPRINTF((stderr, "%sXPAHandler: sending OK to non-acking client %d %d\n", - _sp, comm->cmdfd, comm->datafd)); - comm->ack = 1; - XPAOK(xpa); - comm->ack = 0; - } - - /* process command */ - switch(comm->cmd){ - case XPA_GET: - FPRINTF((stderr, - "%sXPAHandler: processing xpaget for %d %d\n", _sp, - comm->cmdfd, comm->datafd)); - /* check for a reserved command */ - if( comm->mode & COMM_RESERVED ){ - got = XPASendCommands(xpa->send_data, xpa, comm->paramlist, - &(comm->buf), &(comm->len)); - } - else{ - got = (xpa->send_callback)(xpa->send_data, xpa, comm->paramlist, - &(comm->buf), &(comm->len)); - } - if( (got == 0) && (comm->buf != NULL) && (comm->len > 0) ){ - if( XPAPutBuf(xpa, comm->datafd, comm->buf, comm->len, ltimeout) < 0 ){ - PERROR(("XPAHandler write buf")); - XPAError(xpa, "XPA could not write data to client"); - goto done; - } - } - if( (xpa->send_mode & XPA_MODE_FREEBUF) && (comm->buf != NULL) ){ - if( xpa->comm->myfree != NULL ){ - if( xpa->comm->myfree_ptr != NULL ){ - xpa->comm->myfree(xpa->comm->myfree_ptr); - } - else{ - xpa->comm->myfree(comm->buf); - } - } - else{ - xfree(comm->buf); - } - } - /* send client a message, unless its already been done */ - if( !comm->message ){ - if( got ) - XPAError(xpa, "error detected in send callback routine"); - else - XPAOK(xpa); - } - FPRINTF((stderr, - "%sXPAHandler: finished xpaget for %d %d\n", _sp, - comm->cmdfd, comm->datafd)); - break; - case XPA_SET: - FPRINTF((stderr, - "%sXPAHandler: processing xpaset for %d %d\n", _sp, - comm->cmdfd, comm->datafd)); - /* check for a reserved command */ - if( comm->mode & COMM_RESERVED ){ - got=XPAReceiveCommands(xpa->receive_data, xpa, - comm->paramlist, NULL, 0); - } - else{ - /* fill buf if necessary */ - if( (comm->datafd >= 0) && - comm->usebuf && (xpa->receive_mode & XPA_MODE_FILLBUF) ){ - if(XPAGetBuf(xpa, comm->datafd, &(comm->buf), &(comm->len), -1) <0){ - XPAError(xpa, xpaMessbuf[XPA_RTN_NODATA]); - FPRINTF((stderr, "%sXPAHandler: no data for XPAGetBuf on %d\n", _sp, - comm->datafd)); - got = -1; - goto done; - } - else{ - /* close the data fd now that we are done with it */ - XPACloseData(xpa, comm); - } - } - /* execute the receive callback */ - got = (xpa->receive_callback)(xpa->receive_data, xpa, - comm->paramlist, comm->buf, comm->len); - } - if( (xpa->receive_mode & XPA_MODE_FREEBUF) && (comm->buf != NULL) ){ - if( xpa->comm->myfree != NULL ){ - if( xpa->comm->myfree_ptr != NULL ){ - xpa->comm->myfree(xpa->comm->myfree_ptr); - } - else{ - xpa->comm->myfree(comm->buf); - } - } - else{ - xfree(comm->buf); - } - } - /* send client an error message, unless its already been done */ - if( !comm->message ){ - if( got ){ - XPAError(xpa, "error detected in receive callback routine"); - } - else{ - XPAOK(xpa); - } - } - FPRINTF((stderr, - "%sXPAHandler: finished xpaset for %d %d\n", _sp, - comm->cmdfd, comm->datafd)); - break; - case XPA_INFO: - /* send OK before callback because we do not want the client waiting */ - if( comm->ack ) - XPAOK(xpa); - save_ack = comm->ack; - /* don't ever ack in callback */ - comm->ack = 0; - /* execute the info callback -- don't bother checking for errors */ - (xpa->info_callback)(xpa->info_data, xpa, comm->paramlist); - comm->ack = save_ack; - break; - case XPA_ACCESS: - /* return errors -- that how we know if we have access */ - comm->ack = 1; - /* type is in paramlist */ - if( comm->paramlist && *comm->paramlist ){ - char *s; - for(s=comm->paramlist; *s; s++){ - switch(*s){ - case 'g': - if( !xpa->send_callback ){ - XPAError(xpa, "no send callback (i.e., can't xpaget)"); - goto done; - } - break; - case 'i': - if( !xpa->info_callback ){ - XPAError(xpa, "no info callback (i.e., can't xpainfo)"); - goto done; - } - break; - case 's': - if( !xpa->receive_callback ){ - XPAError(xpa, "no receive callback (i.e., can't xpaset)"); - goto done; - } - break; - case 'a': - break; - default: - XPAError(xpa, "unknown xpa access type"); - goto done; - } - } - /* if we got here, its OK */ - XPAOK(xpa); - } - /* no type, anything is OK */ - else - XPAOK(xpa); - break; - default: - /* something is really wrong if we have no command */ - FPRINTF((stderr, "%sXPAHandler: invalid command #%d for fd %d\n", - _sp, comm->cmd, comm->cmdfd)); - got = XPA_RTN_NOCMD; - goto error; - break; - } - -done: - FPRINTF((stderr, - "%sXPAHandler: finished processing %d with status %d\n", _sp, - fd, got)); - /* add xpa back to list of active ones */ - XPAActive(xpa, comm, 1); - - /* finalize comm record */ - if( comm ){ - /* close data channel */ - XPACloseData(xpa, comm); - /* xpa is no longer active */ - comm->status &= ~XPA_STATUS_ACTIVE; - } - - /* join common code */ - goto end; - -eof: - /* on eof, free up comm */ - if( comm ){ - ns = comm->ns; - CommFree(xpa, comm, 1); - comm = NULL; - if( ns && !ns->nproxy && !ns->nxpa ){ - FPRINTF((stderr, "%sXPAHandler: closing ns %s\n", _sp, ns->name)); - XPANSClose(xpa, ns); - } - } - /* join common code */ - goto end; - - -error: - FPRINTF((stderr, "%sXPAHandler ERROR: return code %d on %d\n", - _sp, got, fd)); - /* add xpa back to list of active ones (but not comm) */ - XPAActive(xpa, comm, 1); - /* xpa is no longer using this comm */ - xpa->comm = NULL; - /* don't accidentally close ns on error */ - if( comm ){ - if( comm->ns ) - CommFree(xpa, comm, 0); - else - CommFree(xpa, comm, 1); - comm = NULL; - } - /* join common code */ - goto end; - -end: - /* if a free was requested by the callback, do it now when its safe */ - if( xpa->status & XPA_STATUS_FREE ){ - XPAFree(xpa); - } - /* restore old value of comm */ - else{ - xpa->comm = ocomm; - } - - /* return the status */ - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAMode - * - * Purpose: parse the mode string and set flags - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAMode (char *mode, int *flag, char *name, int mask, int def) -#else -void XPAMode(mode, flag, name, mask, def) - char *mode; - int *flag; - char *name; - int mask; - int def; -#endif -{ - char tbuf[SZ_LINE]; - char s[SZ_LINE]; - - /* keyword routine requires an input buffer that can be modified */ - if( mode && *mode ){ - strncpy(s, mode, SZ_LINE-1); - s[SZ_LINE-1] = '\0'; - } - else - goto error; - /* look for the keyword=<value> string */ - if( keyword(s, name, tbuf, SZ_LINE) ){ - if( istrue(tbuf) ) - *flag |= mask; - else - *flag &= ~mask; - return; - } - else - goto error; - -error: - if( def ) - *flag |= mask; - else - *flag &= ~mask; -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAShortTimeout - * - * Purpose: return short (select, gets) timeout value - * - * Return: timeout in seconds - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAShortTimeout (void) -#else -int XPAShortTimeout() -#endif -{ - return(stimeout); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPALongTimeout - * - * Purpose: return long (fillbuf) timeout value - * - * Return: timeout in seconds - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPALongTimeout (void) -#else -int XPALongTimeout() -#endif -{ - return(ltimeout); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAReceiveLTimeout - * - * Purpose: modify long timeout value for this process - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAReceiveLTimeout (void *client_data, void *call_data, char *paramlist, - char *buf, size_t len) -#else -int XPAReceiveLTimeout(client_data, call_data, paramlist, buf, len) - void *client_data; - void *call_data; - char *paramlist; - char *buf; - size_t len; -#endif -{ - XPA xpa = (XPA)call_data; - char tbuf[SZ_LINE]; - char *s; - - if( paramlist && *paramlist ){ - strncpy(tbuf, paramlist, SZ_LINE-1); - tbuf[SZ_LINE-1] = '\0'; - nocr(tbuf); - culc(tbuf); - if( !strcmp(tbuf, "reset") ){ - ltimeout = XPA_LONG_TIMEOUT; - if( (s=(char *)getenv("XPA_LONG_TIMEOUT")) != NULL ) - ltimeout = atoi(s); - } - else{ - ltimeout = atoi(tbuf); - } - return(0); - } - else{ - XPAError(xpa, "missing long timeout value"); - return(-1); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASendLTimeout - * - * Purpose: return the long timeout for this process - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASendLTimeout (void *client_data, void *call_data, char *paramlist, - char **buf, size_t *len) -#else -int XPASendLTimeout(client_data, call_data, paramlist, buf, len) - void *client_data; - void *call_data; - char *paramlist; - char **buf; - size_t *len; -#endif -{ - XPA xpa = (XPA)call_data; - char tbuf[SZ_LINE]; - - snprintf(tbuf, SZ_LINE, "%d\n", ltimeout); - send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAReceiveSTimeout - * - * Purpose: modify short timeout value for this process - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAReceiveSTimeout (void *client_data, void *call_data, char *paramlist, - char *buf, size_t len) -#else -int XPAReceiveSTimeout(client_data, call_data, paramlist, buf, len) - void *client_data; - void *call_data; - char *paramlist; - char *buf; - size_t len; -#endif -{ - XPA xpa = (XPA)call_data; - char tbuf[SZ_LINE]; - char *s; - - if( paramlist && *paramlist ){ - strncpy(tbuf, paramlist, SZ_LINE-1); - tbuf[SZ_LINE-1] = '\0'; - nocr(tbuf); - culc(tbuf); - if( !strcmp(tbuf, "reset") ){ - stimeout = XPA_SHORT_TIMEOUT; - if( (s=(char *)getenv("XPA_SHORT_TIMEOUT")) != NULL ) - stimeout = atoi(s); - } - else{ - stimeout = atoi(tbuf); - } - return(0); - } - else{ - XPAError(xpa, "missing short timeout value"); - return(-1); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASendSTimeout - * - * Purpose: return the short timeout for this process - * - * Returns: 0 for success, -1 for failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASendSTimeout (void *client_data, void *call_data, char *paramlist, - char **buf, size_t *len) -#else -int XPASendSTimeout(client_data, call_data, paramlist, buf, len) - void *client_data; - void *call_data; - char *paramlist; - char **buf; - size_t *len; -#endif -{ - XPA xpa = (XPA)call_data; - char tbuf[SZ_LINE]; - - snprintf(tbuf, SZ_LINE, "%d\n", stimeout); - send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAVerbosity - * - * Purpose: return verbosity value - * - * Return: verbosity value (0, 1, 2) - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAVerbosity (void) -#else -int XPAVerbosity() -#endif -{ - return(verbosity); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASigusr1 - * - * Purpose: return flag for using sigusr1 - * - * Return: 0 or 1 - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASigusr1 (void) -#else -int XPASigusr1() -#endif -{ - return(sigusr1); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAInitEnv - * - * Purpose: initialize the xpa environment - * - * Return: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAInitEnv (void) -#else -void XPAInitEnv() -#endif -{ - char *s; - - if( !tmpdir ){ - /* determine the communication method */ - mtype=XPAMethod(NULL); - /* enable access controls and port management */ - if( mtype != XPA_UNIX ){ - XPAAclNew(NULL, 0); - XPAPortNew(NULL, 0); - } - /* set short (select,gets) timeout, if necessary */ - if( (s=(char *)getenv("XPA_SHORT_TIMEOUT")) != NULL ) - stimeout = atoi(s); - /* set long (fillbuf) timeout, if necessary */ - if( (s=(char *)getenv("XPA_LONG_TIMEOUT")) != NULL ) - ltimeout = atoi(s); - /* set xpans connect timeout, if necessary */ - if( (s=(char *)getenv("XPA_CONNECT_TIMEOUT")) != NULL ) - ctimeout = atoi(s); - /* set nsdelay timeout, if necessary */ - if( (s=(char *)getenv("XPA_NSDELAY")) != NULL ) - nsdelay = atoi(s); - /* set retries, if necessary */ - if( (s=(char *)getenv("XPA_RETRIES")) != NULL ) - retries = atoi(s); - /* set verbosity level, if necessary */ - if( (s=(char *)getenv("XPA_VERBOSITY")) != NULL ){ - if( istrue(s) ) - verbosity = XPA_VERBOSITY; - else if( isfalse(s) ) - verbosity = 0; - else - verbosity = atoi(s); - if( verbosity < 0 ) - verbosity = 0; - } - /* check for acl enable/disable */ - if( (s=(char *)getenv("XPA_ACL")) != NULL ) - guseacl = istrue(s); - /* check for timestamp on errors */ - if( (s=(char *)getenv("XPA_TIMESTAMP_ERRORS")) != NULL ) - etimestamp = istrue(s); - /* check for xpans register flag */ - if( (s=(char *)getenv("XPA_NSREGISTER")) != NULL ) - nsregister = istrue(s); - /* check for use of siguser1 */ - if( (s=(char *)getenv("XPA_SIGUSR1")) != NULL ) - sigusr1 = istrue(s); - /* check for version checking */ - if( (s=(char *)getenv("XPA_VERSIONCHECK")) != NULL ){ - if( istrue(s) ) - vercheck = 1; - else if( isfalse(s) ) - vercheck = 0; - else - vercheck = atoi(s); - } - /* check for io loop calling xpa */ - if( (s=(char *)getenv("XPA_IOCALLSXPA")) != NULL ){ - if( istrue(s) ){ - XPAIOCallsXPA(1); - } - else if( isfalse(s) ){ - XPAIOCallsXPA(0); - } - } - /* make sure we have a temp dir */ - if( tmpdir == NULL ){ - if( (s=(char *)getenv("XPA_TMPDIR")) != NULL ) - tmpdir = xstrdup(s); - else if( (s=(char *)getenv("TMPDIR")) != NULL ) - tmpdir = xstrdup(s); - else if( (s=(char *)getenv("TMP")) != NULL ) - tmpdir = xstrdup(s); - else - tmpdir = xstrdup(XPA_TMPDIR); - } - /* create directory, if necessary */ - xmkdir(tmpdir, 0777); - xchmod(tmpdir, 0777); -#if HAVE_MINGW32==0 - /* Disable SIGPIPE so we do not die if the client dies. - * Rather, we will get an EOF on reading or writing. - */ - xsignal_sigpipe(); -#endif - /* platform-dependent startup */ - xsocketstartup(); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSAdd - * - * Purpose: add this XPA to the name service - * - * Returns: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPANSAdd (XPA xpa, char *host, char *mode) -#else -int XPANSAdd(xpa, host, mode) - XPA xpa; - char *host; - char *mode; -#endif -{ - char username[SZ_LINE]; - char tbuf[SZ_LINE]; - char xmode[SZ_LINE]; - char *cmd="add"; - char *s; - NS ns; - struct passwd *pw; - - /* sanity check */ - if( !xpa ) - return(0); - - /* handle special case of the name server itself -- its a known entry */ - if( !strcmp(xpa->name, XPANS_NAME) ){ - return(0); - } - - /* look for the proxy=<true|false> string */ - if( mode ){ - strncpy(xmode, mode, SZ_LINE-1); - xmode[SZ_LINE-1] = '\0'; - if( keyword(xmode, "proxy", tbuf, SZ_LINE) && istrue(tbuf) ){ - cmd="addproxy"; - } - } - - /* open a connection to the name service */ - if( (ns=XPANSOpen(xpa, host, 1)) != NULL ){ - /* get the user name, from the environment */ - if( (s=(char *)getenv("XPA_LOGNAME")) != NULL ) - strncpy(username, s, SZ_LINE-1); - else if( (s=(char *)getenv("LOGNAME")) != NULL ) - strncpy(username, s, SZ_LINE-1); -#if HAVE_MINGW32==0 - /* this is a last resort */ - else if( (pw=getpwuid(geteuid())) ) - strncpy(username, pw->pw_name, SZ_LINE-1); -#endif - /* if nothing good has happened, make it "unknown" */ - if( *username == '\0' ) - strcpy(username, "unknown"); - /* null-terminate string */ - username[SZ_LINE-1] = '\0'; - - /* write the command to add this xpa */ - snprintf(tbuf, SZ_LINE, "%s %s %s:%s %s %s\n", - cmd, xpa->method, xpa->xclass, xpa->name, xpa->type, username); - if( XPAPuts(xpa, ns->fd, tbuf, stimeout) < 0 ){ - return(-1); - } - /* get result */ - if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0 ){ - if( !strncmp(tbuf, "XPA$OK", 6) ){ - /* for proxy, we now must listen for xpa requests on this ns */ - if( !strcmp(cmd, "addproxy") && xpa ){ - if( CommNew(xpa, ns->fd, ns->ip, ns->port, ns->name, ns) ){ - /* one more proxy is using this name server */ - ns->nproxy += 1; - } - } - else{ - /* one more access point is using this name server */ - ns->nxpa += 1; - } - return(0); - } - else if( !strncmp(tbuf, "XPA$EXISTS", 10) ) - return(0); - else - return(-1); - } - else{ - return(-1); - } - } - else{ - return(-1); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSDel - * - * Purpose: remove public knowledge of this XPA from the name service - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPANSDel (XPA xpa, char *host, char *mode) -#else -int XPANSDel(xpa, host, mode) - XPA xpa; - char *host; - char *mode; -#endif -{ - int got=0; - char tbuf[SZ_LINE]; - char xmode[SZ_LINE]; - char *cmd="del"; - NS ns; - - /* sanity check */ - if( !xpa ) - return(0); - - /* handle special case of the name server itself -- its a known entry */ - if( xpa->name && !strcmp(xpa->name, XPANS_NAME) ){ - return(0); - } - - /* if there is no method, just return */ - if( (xpa->method == NULL) || (*xpa->method == '\0') ){ - return(0); - } - - /* look for the proxy=<true|false> string */ - if( mode ){ - strncpy(xmode, mode, SZ_LINE-1); - xmode[SZ_LINE-1] = '\0'; - if( keyword(xmode, "proxy", tbuf, SZ_LINE) && istrue(tbuf) ){ - cmd="delproxy"; - } - } - - /* open a connection to the name service */ - if( (ns=XPANSOpen(xpa, host, -1)) != NULL ){ - /* write the command to delete this xpa */ - snprintf(tbuf, SZ_LINE, "%s %s\n", cmd, xpa->method); - XPAPuts(xpa, ns->fd, tbuf, stimeout); - /* get result */ - if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0 ){ - if( !strncmp(tbuf, "XPA$OK", 6) ){ - /* one less access point is using this name server */ - ns->nxpa -= 1; - /* if there are no more access points using this xpans, close it */ - if( !ns->nxpa && !ns->nproxy ){ - XPANSClose(xpa, ns); - } - } - else{ - got = -1; - } - } - else{ - got = -1; - } - } - else - got = -1; - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAVersionCheck - * - * Purpose: check our version vs. xpans version - * - * Returns: -1,0,1 for our<=>xpans - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAVersionCheck (char *serv, char *nsv) -#else -int XPAVersionCheck(serv, nsv) - char *serv; - char *nsv; -#endif -{ - int i; - int ip1=0; - int ip2=0; - int v1=0; - int v2=0; - int got=0; - int vsize=2; - char s1[SZ_LINE]; - char s2[SZ_LINE]; - - /* return if not checking version */ - if( vercheck <=0 ) - return(0); - /* if either does not exist, its a mismatch */ - if( !word(serv, s1, &ip1) || !word(nsv, s2, &ip2) ) - return(1); - /* if strings are equal, versions are equal */ - if( !strcasecmp(s1, s2) ) - return(0); - - /* format for version is maj.min.patch[be]beta */ - newdtable(".be"); - /* we check only the major and minor version for incompatibilities */ - for(i=0; i<vsize; i++){ - if( !word(serv, s1, &ip1) || !word(nsv, s2, &ip2) ){ - break; - } - v1 = atoi(s1); - v2 = atoi(s2); - if( v1 > v2 ){ - got = 1; - break; - } - if( v1 < v2 ){ - got = -1; - break; - } - } - - freedtable(); - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAVersionWarn - * - * Purpose: warn about mismatched versions - * - * Returns: NONE - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAVersionWarn (char *serv, char *nsv) -#else -void XPAVersionWarn(serv, nsv) - char *serv; - char *nsv; -#endif -{ - /* return if not checking version */ - if( vercheck <=0 ) - return; - - /* output warning */ - fprintf(stderr, - "XPA$WARNING: version mismatch detected between XPA-enabled server (%s)\n", serv?serv:"unknown"); - fprintf(stderr, "and xpans (%s).", nsv?nsv:"unknown"); - fprintf(stderr, " You probably will get bad results.\n"); - fprintf(stderr, "Please consider updating XPA to match the XPA-enabled server you are running.\n"); - - /* we did it */ - vercheck--; -} - -/* - *---------------------------------------------------------------------------- - * - * - * Public Routines - * - * - *---------------------------------------------------------------------------- - */ - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAMethod - * - * Purpose: return communication method type - * - * Returns: XPA__INET, XPA_UNIX - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAMethod (char *method) -#else -int XPAMethod(method) - char *method; -#endif -{ - char *s1; - - /* if no method is passed, we return the default method type */ - if( method == NULL ){ - if( mtype == 0 ){ - s1 = (char *)getenv("XPA_METHOD"); - if( s1 == NULL ) - mtype = XPA_INET; - else if( !strcasecmp(s1, "inet") ) - mtype = XPA_INET; - else if( !strcasecmp(s1, "localhost") ){ - mtype = XPA_INET; - use_localhost = 1; - } - else if( !strcasecmp(s1, "unix") ){ -#if HAVE_SYS_UN_H - mtype = XPA_UNIX; -#else - mtype = XPA_INET; - use_localhost = 1; -#endif - } - else if( !strcasecmp(s1, "local") ){ -#if HAVE_SYS_UN_H - mtype = XPA_UNIX; -#else - mtype = XPA_INET; - use_localhost = 1; - -#endif - } - else - mtype = XPA_INET; - } - return(mtype); - } - /* otherwise, we analyze the input method to get the type */ - else{ - /* inet is ip:port, else unix filename */ - if( strchr(method, ':') != NULL ) - return(XPA_INET); - else -#if HAVE_SYS_UN_H - return(XPA_UNIX); -#else - return(XPA_INET); -#endif - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSMethod - * - * Purpose: return string containing name server method - * - * Returns: name server method string - * - *---------------------------------------------------------------------------- - */ - -#ifdef ANSI_FUNC -char * -XPANSMethod (char *host, int flag) -#else -char *XPANSMethod(host, flag) - char *host; - int flag; -#endif -{ - char *s, *t; - char tbuf[SZ_LINE]; - int i; - int ip; - int port; - unsigned int bip; - unsigned short bport; - - switch( XPAMethod(host) ){ - case XPA_INET: - if( (host != NULL) && (*host != '\0') ) - strncpy(nsmethod, host, SZ_LINE-1); - else if( (s=(char *)getenv("XPA_NSINET")) != NULL ) - strncpy(nsmethod, s, SZ_LINE-1); - else - strncpy(nsmethod, XPA_NSINET, SZ_LINE-1); - /* always null-terminate */ - nsmethod[SZ_LINE-1] = '\0'; - /* if flag, we want the XPA access ip and port, not the communication - channel between xpa servers and the name service */ - if( flag ){ - if( (s=strrchr(nsmethod, ':')) != NULL ){ - /* this is where we will overwrite the port */ - t = s+1; - /* get base port for default */ - XPAParseIpPort(nsmethod, &bip, &bport); - newdtable(","); - for(ip=0, i=0; i<=flag; i++){ - if( !word(t, tbuf, &ip) ){ - *tbuf = '\0'; - break; - } - } - freedtable(); - if( *tbuf ) - port = atoi(tbuf); - else - port = bport + flag; - snprintf(t, SZ_LINE, "%d", port); - } - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - if( host != NULL ) - strncpy(nsmethod, host, SZ_LINE-1); - else if( (s=(char *)getenv("XPA_NSUNIX")) != NULL ) - strncpy(nsmethod, s, SZ_LINE-1); - else - snprintf(nsmethod, SZ_LINE, "%s/%s", tmpdir, XPA_NSUNIX); - /* always null-terminate */ - nsmethod[SZ_LINE-1] = '\0'; - /* if flag is set, we are getting the XPA access file, not the - socket file and we have to change the name slightly */ - if( flag ){ - /* replace the ending, if possible */ - s = strrchr(nsmethod, '.'); - t = strrchr(nsmethod, '/'); - if( (s != NULL) && (s > t) ) - *s = '\0'; - snprintf(tbuf, SZ_LINE, ".xpa-%d", flag); - strcat(nsmethod, tbuf); - } - break; -#endif - default: - if( (s=(char *)getenv("XPA_NSINET")) != NULL ) - strncpy(nsmethod, s, SZ_LINE-1); - else - strncpy(nsmethod, XPA_NSINET, SZ_LINE-1); - /* always null-terminate */ - nsmethod[SZ_LINE-1] = '\0'; - break; - } - - /* return the static method string */ - return(nsmethod); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAParseName - * - * Purpose: split the xpaname into a class and name string - * - * Results: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPAParseName (char *xpaname, char *xclass, char *name, int len) -#else -void XPAParseName(xpaname, xclass, name, len) - char *xpaname; - char *xclass; - char *name; - int len; -#endif -{ - char *s; - char *t; - char *cptr=NULL; - char *nptr=NULL; - - /* if nothing is passed to us, allow everything */ - if( (xpaname == NULL) || (*xpaname == '\0') ){ - strncpy(xclass, "*", len-1); - strncpy(name, "*", len-1); - return; - } - - /* split the xpaname into class and name */ - s = xstrdup(xpaname); - if( (t=(char *)strchr(s, ':')) != NULL ){ - cptr = s; - *t = '\0'; - nptr = t+1; - } - else{ - nptr = s; - cptr = "*"; - } - if( *cptr == '\0' ) - cptr = "*"; - if( *nptr == '\0' ) - nptr = "*"; - - strncpy(xclass, cptr, len-1); - strncpy(name, nptr, len-1); - xfree(s); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAParseIpPort - * - * Purpose: split the host into ip and port - * - * Results: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAParseIpPort (char *host, unsigned int *ip, unsigned short *port) -#else -int XPAParseIpPort(host, ip, port) - char *host; - unsigned int *ip; - unsigned short *port; -#endif -{ - char *s1, *s2, *s3, *p1, *p2; - int got; - - /* make sure we have something to work with */ - if( (host == NULL) || (*host == '\0') ) - return(0); - - /* parse up the string and look for a port number (which is essential) */ - s1 = xstrdup(host); - /* if we have a ",", null it out since what comes after is aux info */ - if( (p1 = (char *)strchr(s1, ',')) != NULL ){ - *p1 = '\0'; - } - /* if we have a ":", we will null it out (so that what comes before is - the host name) and bump past it to point to the port */ - if( (p1 = (char *)strchr(s1, ':')) == NULL ){ - /* there is no ":", so the whole string is the port */ - p1 = s1; - s2 = NULL; - } else { - /* null out ':' and bump port pointer */ - *p1 = '\0'; - p1++; - s2 = s1; - } - - /* get port */ - p2 = NULL; - if( p1 && !strcmp(p1, "$port") ) - *port = XPA_NSPORT; - /* NB: port number might be followed by other stuff */ - else - *port = (unsigned short)strtol(p1, &p2, 0); - /* check for bad port number -- we lose */ - if( *port <=0 || (p1 == p2) || (p2 && (*p2 != '\0')) ){ - *ip = 0; - *port = 0; - got = 0; - goto done; - } - - /* get ip */ - if( s2 && *s2 ){ - /* see if this already is a hex address in network byte order */ - *ip = strtoul16(s2, &s3); - if( *s3 == '\0' ){ - got = 1; - goto done; - } - } - /* not hex or proxy -- convert ip string to an ip address */ - if( (*ip = gethostip(s2)) == 0 ){ - *port = 0; - got = 0; - } - else{ - got = 1; - } - -done: - xfree(s1); - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAParseUnixSocket - * - * Purpose: see if host is actually a unix socket file - * - * Results: 1 if its a socket, 0 otherwise - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAParseUnixSocket (char *host) -#else -int XPAParseUnixSocket(host) - char *host; -#endif -{ - struct stat buf; - - /* see if its a file in the right directory */ - if( !strncmp(host, tmpdir, strlen(tmpdir)) && - !stat(host, &buf) ){ - return(1); - } - else{ - return(0); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAOK - * - * Purpose: send an XPA OK message to the client - * - * Returns: 0 on success, -1 on error - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAOK (XPA xpa) -#else -int XPAOK(xpa) - XPA xpa; -#endif -{ - int len; - int status=0; - char tbuf[SZ_LINE]; - - /* make sure we have a valid struct */ - if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) - return(-1); - - /* send message, if necessary */ - if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ - snprintf(tbuf, SZ_LINE, "%s XPA$OK (%s:%s %s)\n", - xpa_id(xpa), xpa_class(xpa), xpa_name(xpa), xpa_method(xpa)); - len = strlen(tbuf); - if( XPAPuts(xpa, xpa_cmdfd(xpa), tbuf, stimeout) != len ){ - status = -1; - } - } - - /* flag that there was a message sent for this xpa */ - xpa->comm->message = 1; - - /* return status */ - return(status); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPATimestamp - * - * Purpose: generate string with current date/time - * - * Returns: time string (in static buffer) - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -char * -XPATimestamp(void) -#else -char *XPATimestamp() -#endif -{ - time_t t; - struct tm *lt; - - *ctimebuf = '\0'; - if( etimestamp ){ - if( (t = time(NULL)) != (time_t)-1 ){ - if( (lt = localtime(&t)) != NULL ){ - snprintf(ctimebuf, SZ_LINE, " %02d/%02d/%d:%d:%d:%d", - lt->tm_mday, lt->tm_mon+1, lt->tm_year+1900, - lt->tm_hour, lt->tm_min, lt->tm_sec); - } - } - } - return ctimebuf; -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAError - * - * Purpose: send an XPA error message to the client - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAError (XPA xpa, char *s) -#else -int XPAError(xpa, s) - XPA xpa; - char *s; -#endif -{ - int status=0; - int ip=0; - char tbuf[SZ_LINE]; - char *t; - char *u; - - /* make sure we have a valid struct */ - if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) - return(-1); - - /* send message, if necessary */ - if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ - t = xstrdup(s); - /* get rid of CR in message -- we add one at the end */ - nowhite(t, t); - if( !strncmp(t, "XPA$", 4) ) - word(t, tbuf, &ip); - u = (char *)xcalloc(strlen(t)+SZ_LINE, sizeof(char)); - /* package up and write the message */ - snprintf(u, SZ_LINE, "%s XPA$ERROR %s (%s:%s %s%s)\n", - xpa_id(xpa), - &t[ip], xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), - XPATimestamp()); - if( XPAPuts(xpa, xpa_cmdfd(xpa), u, stimeout) != (int)strlen(u) ){ - status = -1; - } - if( t ) - xfree(t); - if( u ) - xfree(u); - } - - /* flag that there was a message sent for this xpa */ - xpa->comm->message = 1; - - /* return status */ - return(status); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAMessage - * - * Purpose: send an XPA message to the client - * - * Returns: 0 on success, -1 on error - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAMessage (XPA xpa, char *s) -#else -int XPAMessage(xpa, s) - XPA xpa; - char *s; -#endif -{ - int status=0; - int ip=0; - char tbuf[SZ_LINE]; - char *t; - char *u; - - /* make sure we have a valid struct */ - if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) - return(-1); - - /* send message, if necessary */ - if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ - t = xstrdup(s); - /* get rid of CR in message -- we add one at the end */ - nowhite(t, t); - if( !strncmp(t, "XPA$", 4) ) - word(t, tbuf, &ip); - u = (char *)xcalloc(strlen(t)+SZ_LINE, sizeof(char)); - /* package up and write the message */ - snprintf(u, SZ_LINE, "%s XPA$MESSAGE %s (%s:%s %s%s)\n", - xpa_id(xpa), - &t[ip], xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), - XPATimestamp()); - if( XPAPuts(xpa, xpa_cmdfd(xpa), u, stimeout) != (int)strlen(u) ){ - status = -1; - } - if( t ) - xfree(t); - if( u ) - xfree(u); - } - - /* flag that there was a message sent for this xpa */ - xpa->comm->message = 1; - - /* return status */ - return(status); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAArgvParamlist - * - * Purpose: generate a paramlist string from an argv - * - * Results: allocated paramlist string - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -char * -XPAArgvParamlist (int argc, char **argv, int start) -#else -char *XPAArgvParamlist(argc, argv, start) - int argc; - char **argv; - int start; -#endif -{ - int plen; - int i; - char *paramlist; - - /* get length of paramlist */ - for(plen=0, i=start; i<argc; i++){ - plen += (strlen(argv[i])+1); - } - - /* allocate enough space for it */ - if( (paramlist = (char *)xcalloc(plen+1, sizeof(char))) == NULL ){ - return(NULL); - } - - /* gather up the paramlist */ - for(i=start; i<argc; i++){ - strcat(paramlist, argv[i]); - strcat(paramlist, " "); - } - - /* remove whitespace from beginning and end */ - nowhite(paramlist, paramlist); - - /* return paramlist */ - return(paramlist); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSLookup - * - * Purpose: get name server matches - * - * Returns: number of matches - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPANSLookup (XPA xpa, char *tname, char *ttype, - char ***xclasses, char ***names, char ***methods, char ***infos) -#else -int XPANSLookup(xpa, tname, ttype, xclasses, names, methods, infos) - XPA xpa; - char *tname; - char *ttype; - char ***xclasses; - char ***names; - char ***methods; - char ***infos; -#endif -{ - unsigned short port; - unsigned int ip; - int own; - int lp=0; - int got=0; - int nentry=100; - char *xtype; - char xclass[SZ_LINE]; - char name[SZ_LINE]; - char method[SZ_LINE]; - char info[SZ_LINE]; - char user[SZ_LINE]; - char type[SZ_LINE]; - char tbuf[SZ_LINE]; - char lbuf[SZ_LINE]; - NS ns; - XPA txpa; - - /* do some initialization */ - XPAInitEnv(); - - /* use "*" as default if no type was specified */ - if( (ttype == NULL) || (*ttype == '\0') ) - xtype = "*"; - /* type 'a' means we are only trying to access */ - else if( *ttype == 'a' ) - xtype = "*"; - else - xtype = ttype; - - /* special case of name server */ - if( !strcmp(tname, XPANS_NAME) ){ - *xclasses = (char **)xmalloc(sizeof(char *)); - *names = (char **)xmalloc(sizeof(char *)); - *methods = (char **)xmalloc(sizeof(char *)); - *infos = (char **)xmalloc(sizeof(char *)); - (*xclasses)[0] = xstrdup(XPANS_CLASS); - (*names)[0] = xstrdup(XPANS_NAME); - (*methods)[0] = xstrdup(XPANSMethod(NULL, 1)); - (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); - return(1); - } - - /* special case of a string containing ip:port -- avoid trip to ns */ - if( XPAParseIpPort(tname, &ip, &port) ){ - *xclasses = (char **)xmalloc(sizeof(char *)); - *names = (char **)xmalloc(sizeof(char *)); - *methods = (char **)xmalloc(sizeof(char *)); - *infos = (char **)xmalloc(sizeof(char *)); - (*xclasses)[0] = xstrdup("?"); - (*names)[0] = xstrdup("?"); - (*methods)[0] = xstrdup(tname); - (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); - return(1); - } - - /* special case of a string containing unix socket -- avoid trip to ns */ - if( XPAParseUnixSocket(tname) ){ - *xclasses = (char **)xmalloc(sizeof(char *)); - *names = (char **)xmalloc(sizeof(char *)); - *methods = (char **)xmalloc(sizeof(char *)); - *infos = (char **)xmalloc(sizeof(char *)); - (*xclasses)[0] = xstrdup("?"); - (*names)[0] = xstrdup("?"); - (*methods)[0] = xstrdup(tname); - (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); - return(1); - } - - /* pre-allocate the various arrays to an absurd number */ - *xclasses = (char **)xmalloc(nentry * sizeof(char *)); - *names = (char **)xmalloc(nentry * sizeof(char *)); - *methods = (char **)xmalloc(nentry * sizeof(char *)); - *infos = (char **)xmalloc(nentry * sizeof(char *)); - - /* open a connection to the name service */ - if( (ns=XPANSOpen(xpa, NULL, 0)) != NULL ){ - while( word(tname, lbuf, &lp) ){ - XPAParseName(lbuf, xclass, name, SZ_LINE); - /* write the command to add this xpa */ - snprintf(tbuf, SZ_LINE, "lookup %s:%s %s %s\n", - xclass, name, xtype, nsusers); - FPRINTF((stderr, "%sXPANSLookup: sending command %s", _sp, tbuf)); - XPAPuts(xpa, ns->fd, tbuf, stimeout); - /* read matches from the name server */ - while( 1 ){ - if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) <=0 ){ - FPRINTF((stderr, "%sXPANSLookup: unexpected EOF from xpans\n", _sp)); - break; - } - FPRINTF((stderr, "%sXPANSLookup: receiving %s", _sp, tbuf)); - /* XPA$<result> signals end of input */ - if( !strncmp(tbuf, "XPA$", 4) ) - break; - /* otherwise scan next line */ - if( sscanf(tbuf, "%s %s %s %s %s %s\n", - xclass, name, type, method, user, info) != EOF ){ - /* make sure this entry is not in the current process - (i.e., we can't ever xpa ourselves!) */ - for(own=0, txpa=xpahead; txpa!=NULL; txpa=txpa->next){ - if( !strcmp(txpa->xclass, xclass) && !strcmp(txpa->name, name) && - !strcmp(txpa->method, method) ){ - own = 1; - break; - } - } - /* if this xpa is in the current process, skip it */ - if( own ) - continue; - /* make sure we have enough space */ - if( got >= nentry ){ - nentry *= 2; - *xclasses = (char **)xrealloc(*xclasses, nentry * sizeof(char *)); - *names = (char **)xrealloc(*names, nentry * sizeof(char *)); - *methods = (char **)xrealloc(*methods, nentry * sizeof(char *)); - *infos = (char **)xrealloc(*infos, nentry * sizeof(char *)); - } - /* add this entry to the list */ - (*xclasses)[got] = xstrdup(xclass); - (*names)[got] = xstrdup(name); - (*methods)[got] = xstrdup(method); - (*infos)[got] = xstrdup(info); - got++; - } - } - } - /* if we did not add to an xpa record, close up here */ - if( xpa == NULL ){ - XPANSClose(NULL, ns); - } - } - /* reallocate the exact number of buffers we have */ - if( got > 0 ){ - *xclasses = (char **)xrealloc(*xclasses, got * sizeof(char *)); - *names = (char **)xrealloc(*names, got * sizeof(char *)); - *methods = (char **)xrealloc(*methods, got * sizeof(char *)); - *infos = (char **)xrealloc(*infos, got * sizeof(char *)); - } - else{ - xfree(*xclasses); - xfree(*names); - xfree(*methods); - xfree(*infos); - } - FPRINTF((stderr, "%sXPANSLookup: found %d entries\n", _sp, got)); - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSClose - * - * Purpose: close connection to the name service - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPANSClose (XPA xpa, NS ns) -#else -int XPANSClose(xpa, ns) - XPA xpa; - NS ns; -#endif -{ - NS cur; - XPAComm comm, tcomm; - - if( !ns ) - return(-1); - - /* remove from xpa list */ - if( xpa ){ - if( xpa->nshead ){ - if( xpa->nshead == ns ){ - xpa->nshead = ns->next; - } - else{ - for(cur=xpa->nshead; cur!=NULL; cur=cur->next){ - if( cur->next == ns ){ - cur->next = ns->next; - break; - } - } - } - } - /* close comms associated with this ns */ - for(comm=xpa->commhead; comm!=NULL; ){ - tcomm = comm->next; - if( comm->ns == ns ){ - CommFree(xpa, comm, 0); - } - comm = tcomm; - } - } - - /* close socket */ - if( ns->fd >=0 ){ - xclose(ns->fd); - } - /* free up space */ - if( ns->method) xfree(ns->method); - if( ns->host ) xfree(ns->host); - if( ns->name ) xfree(ns->name); - if( ns ) xfree(ns); - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANSKeepAlive - * - * Purpose: send a 1-byte keep-alive packet to each name server - * - * Returns: -1 on error, else 1 - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPANSKeepAlive (XPA xpa, int type) -#else - int XPANSKeepAlive(xpa, type) - XPA xpa; - int type; -#endif -{ - NS ns; - int got=0; - - /* sanity check */ - if( !xpa ) - return(-1); - - /* use default type, if none specified */ - if( !type ) - type=DEF_KA_TYPE; - - /* send keep-alive to deserving xpans instances */ - for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ - if( ((type&1) && (ns->nxpa>0)) || ((type&2) && (ns->nproxy>0)) ){ - FPRINTF((stderr, "%sXPANSKeepAlive: sending ka to %d\n", _sp, ns->fd)); -#if USE_KA_OOB - /* send as out of band data to avoid mixing with normal data stream */ - got = send(ns->fd, "\n", 1, MSG_OOB); -#else - /* cisco routers can clear the URG flag by default, so use in-band */ - got = send(ns->fd, "\n", 1, 0); -#endif - } - } - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPANew - * - * Purpose: add a new xpa name to a process to allow external - * process to read/write data associated with this name. - * - * If the send callback is defined, it can send to an external process. - * If the receive callback is defined, it can receive from an external process. - * - * Returns: xpa handle associated with this class.name or NULL - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -XPA -XPANew (char *xclass, char *name, char *help, - SendCb send_callback, void *send_data, char *send_mode, - ReceiveCb rec_callback, void *rec_data, char *rec_mode) -#else -XPA XPANew(xclass, name, help, - send_callback, send_data, send_mode, - rec_callback, rec_data, rec_mode) - char *xclass; - char *name; - char *help; - SendCb send_callback; - void *send_data; - char *send_mode; - ReceiveCb rec_callback; - void *rec_data; - char *rec_mode; -#endif -{ - unsigned short port; - unsigned int ip; - int got; - int oum; - int keep_alive=1; - int reuse_addr=1; - char tbuf[SZ_LINE]; - char tbuf2[SZ_LINE]; - char tfile[SZ_LINE]; - char *tfptr; - XPA xpa; - socklen_t slen = sizeof(struct sockaddr_in); - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - - /* do some initialization */ - XPAInitEnv(); - /* init the list of reserved commands */ - XPAInitReserved(); - - /* we need a name, but no ":" allowed in the name */ - if( (name == NULL) || (*name == '\0') || strchr(name, ':') ) - return(NULL); - - /* limit the size of the xclass and name designation */ - if( xclass && *xclass && (strlen(xclass) > XPA_NAMELEN) ){ - if( verbosity ) - fprintf(stderr, "XPA$ERROR: class designator too long\n"); - return(NULL); - } - if( strlen(name) > XPA_NAMELEN ){ - if( verbosity ) - fprintf(stderr, "XPA$ERROR: name designator too long\n"); - return(NULL); - } - - /* we need either a send or a receive or both */ - if( (send_callback == NULL) && (rec_callback == NULL ) ){ - if( verbosity ) - fprintf(stderr, "XPA$ERROR: requires send and/or receive callback\n"); - return(NULL); - } - - /* allocate xpa struct */ - if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) - return(NULL); - - /* fill in the blanks */ - xpa->version = xstrdup(XPA_VERSION); - xpa->type = (char *)xcalloc(10, sizeof(char)); - if( xclass && *xclass ) - xpa->xclass = xstrdup(xclass); - else - xpa->xclass = xstrdup("*"); - xpa->name = xstrdup(name); - xpa->help = xstrdup(help); - /* set the value of the server big-endian-ness */ - xpa->sendian = XPAEndian() ? xstrdup("big") : xstrdup("little"); - - /* fill in send information */ - if( send_callback != NULL ){ - xpa->send_callback = send_callback; - xpa->send_data = send_data; - strcat(xpa->type, "g"); - /* process the mode string */ - xpa->send_mode = XPA_DEF_MODE_SEND; - XPAMode(send_mode, &(xpa->send_mode), "freebuf", XPA_MODE_FREEBUF,1); - XPAMode(send_mode, &(xpa->send_mode), "acl", XPA_MODE_ACL, 1); - } - - /* fill in receive information */ - if( rec_callback != NULL ){ - xpa->receive_callback = rec_callback; - xpa->receive_data = rec_data; - strcat(xpa->type, "s"); - /* process the mode string */ - xpa->receive_mode = XPA_DEF_MODE_REC; - XPAMode(rec_mode, &(xpa->receive_mode), "buf", XPA_MODE_BUF, 1); - XPAMode(rec_mode, &(xpa->receive_mode), "fillbuf", XPA_MODE_FILLBUF, 1); - XPAMode(rec_mode, &(xpa->receive_mode), "freebuf", XPA_MODE_FREEBUF, 1); - XPAMode(rec_mode, &(xpa->receive_mode), "acl", XPA_MODE_ACL, 1); - } - - /* set up communication method */ - switch(mtype){ - case XPA_INET: - /* open a socket and fill in socket information */ - if( (xpa->fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) - goto error; - setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&reuse_addr, sizeof(reuse_addr)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - /* localhost only */ - if( use_localhost ) - sock_in.sin_addr.s_addr = htonl(gethostip("$localhost")); - /* any address will do */ - else - sock_in.sin_addr.s_addr = htonl(INADDR_ANY); - /* handle special case of xpans port */ - if( !strcmp(xpa->name, XPANS_NAME) ){ - XPAParseIpPort(XPANSMethod(NULL, 1), &ip, &port); - sock_in.sin_port = htons(port); - } - else{ - sock_in.sin_port = htons(XPAPort(xpa)); - } - /* bind to the ip:port */ - if( xbind(xpa->fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ) - goto error; - /* we now can determine which port the system assigned */ - if( getsockname(xpa->fd, (struct sockaddr *)&sock_in, &slen) < 0 ) - goto error; - else{ - /* ip:port is the method */ - gethost(tbuf2, SZ_LINE); - snprintf(tbuf, SZ_LINE, "%x:%d", - gethostip(tbuf2), ntohs(sock_in.sin_port)); - xpa->method = xstrdup(tbuf); - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - /* open a socket and fill in socket information */ - if( (xpa->fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) - goto error; - setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&reuse_addr, sizeof(reuse_addr)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_un.sun_family = AF_UNIX; - /* handle special case of xpans */ - if( !strcmp(xpa->name, XPANS_NAME) ){ - strcpy(tbuf, XPANSMethod(NULL, 1)); - } - else{ - /* get filename part, composed of class and name and unique id */ - snprintf(tfile, SZ_LINE, "%s_%s.%d", - xpa->xclass, xpa->name, (int)getpid()); - /* change "/" to "_" for filename */ - for(tfptr = tfile; *tfptr != '\0'; tfptr++){ - if( *tfptr == '/' ) - *tfptr = '_'; - } - /* create full pathname */ - snprintf(tbuf, SZ_LINE, "%s/%s", tmpdir, tfile); - } - /* delete old copy */ - unlink (tbuf); - strcpy(sock_un.sun_path, tbuf); - /* unset umask so that everyone can read and write */ - oum = umask(0); - /* bind to the file */ - got = xbind(xpa->fd, (struct sockaddr *)&sock_un, sizeof(sock_un)); - /* reset umask */ - umask(oum); - /* now check for bind error */ - if( got < 0 ) - goto error; - /* path is the method */ - xpa->method = xstrdup(tbuf); - break; -#endif - default: - goto error; - } - - /* listen for connections */ - if( listen(xpa->fd, XPA_MAXLISTEN) < 0 ) - goto error; - - /* make sure we close on exec */ - xfcntl(xpa->fd, F_SETFD, FD_CLOEXEC); - - /* add this xpa to end of list of xpas */ - XPAListAdd(&xpahead, xpa); - - /* publish this entry to the world */ - if( nsregister ) - XPANSAdd(xpa, NULL, NULL); - - /* make it active */ - XPAActive(xpa, NULL, 1); - -#if NO_AUTOMATIC_HAVE_ATEXIT - /* register XPA atexit funtion */ - if( !atexitinit ){ - atexit(_XPAAtExit); - atexitinit = getpid(); - } -#endif - - /* return good news */ - return(xpa); - -error: - if( verbosity ){ - perror("XPANew"); - } - _XPAFree(xpa); - return(NULL); -} - -/* - *--------------------------------------------------------------------------- - * - * Routine: XPAFree - * - * Purpose: free up alloc'ed memory in the XPA record structure - * - * Results: 0 on success, -1 for failure - * - *--------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAFree (XPA xpa) -#else -int XPAFree(xpa) - XPA xpa; -#endif -{ - /* if status is active, just flag eventual need to free and exit */ - if( _XPAValid(xpahead, xpa, XPA_ACLS) ){ - if( xpa_status(xpa) & XPA_STATUS_ACTIVE ){ - xpa->status |= XPA_STATUS_FREE; - FPRINTF((stderr, "%sXPAFree: marking xpa struct for later free'ing\n", - _sp)); - return(0); - } - else{ - /* call the primitive routine */ - FPRINTF((stderr, "%sXPAFree: freeing xpa struct\n", _sp)); - return(_XPAFree(xpa)); - } - } - else{ - return(-1); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAInfoNew - * - * Purpose: add a new xpa name to a process to allow external - * process to send info messages - * - - * Returns: xpa handle associated with this class.name or NULL - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -XPA -XPAInfoNew (char *xclass, char *name, - InfoCb info_callback, void *info_data, char *info_mode) -#else -XPA XPAInfoNew(xclass, name, info_callback, info_data, info_mode) - char *xclass; - char *name; - InfoCb info_callback; - void *info_data; - char *info_mode; -#endif -{ - int got; - int oum; - int keep_alive=1; - int reuse_addr=1; - char tbuf[SZ_LINE]; - char tbuf2[SZ_LINE]; - char tfile[SZ_LINE]; - char *tfptr; - XPA xpa; - socklen_t slen = sizeof(struct sockaddr_in); - struct sockaddr_in sock_in; -#if HAVE_SYS_UN_H - struct sockaddr_un sock_un; -#endif - - /* do some initialization */ - XPAInitEnv(); - /* init the list of reserved commands */ - XPAInitReserved(); - - /* we need a name, but no ":" allowed in the name */ - if( (name == NULL) || (*name == '\0') || strchr(name, ':') ) - return(NULL); - - /* we need an info callback */ - if( info_callback == NULL ){ - if( verbosity ){ - fprintf(stderr, "XPA$ERROR: requires info callback\n"); - } - return(NULL); - } - - /* allocate xpa struct */ - if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) - return(NULL); - - xpa->version = xstrdup(XPA_VERSION); - xpa->type = (char *)xcalloc(10, sizeof(char)); - /* fill in the blanks */ - if( xclass != NULL ) - xpa->xclass = xstrdup(xclass); - else - xpa->xclass = xstrdup("*"); - xpa->name = xstrdup(name); - - /* fill in send information */ - xpa->info_callback = info_callback; - xpa->info_data = info_data; - strcat(xpa->type, "i"); - /* process the mode string */ - xpa->info_mode = XPA_DEF_MODE_INFO; - XPAMode(info_mode, &(xpa->info_mode), "acl", XPA_MODE_ACL, 1); - - /* set up communication method */ - switch(mtype){ - case XPA_INET: - /* open a socket and fill in socket information */ - if( (xpa->fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) - goto error; - setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&reuse_addr, sizeof(reuse_addr)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_in.sin_family = AF_INET; - /* localhost only */ - if( use_localhost ) - sock_in.sin_addr.s_addr = htonl(gethostip("$localhost")); - /* any address will do */ - else - sock_in.sin_addr.s_addr = htonl(INADDR_ANY); - sock_in.sin_port = htons(XPAPort(xpa)); - /* bind to the ip:port */ - if( xbind(xpa->fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ) - goto error; - /* we now can determine which port the system assigned */ - if( getsockname(xpa->fd, (struct sockaddr *)&sock_in, &slen) < 0 ) - goto error; - else{ - /* ip:port is the method */ - gethost(tbuf2, SZ_LINE); - snprintf(tbuf, SZ_LINE, "%x:%d", - gethostip(tbuf2), ntohs(sock_in.sin_port)); - xpa->method = xstrdup(tbuf); - } - break; -#if HAVE_SYS_UN_H - case XPA_UNIX: - /* get filename part, composed of class and name and unique id */ - snprintf(tfile, SZ_LINE, "%s_%s.%d", - xpa->xclass, xpa->name, (int)getpid()); - /* change "/" to "_" for filename */ - for(tfptr = tfile; *tfptr != '\0'; tfptr++){ - if( *tfptr == '/' ) - *tfptr = '_'; - } - /* create full pathname */ - snprintf(tbuf, SZ_LINE, "%s/%s", tmpdir, tfile); - /* delete old copy */ - unlink (tbuf); - /* open a socket and fill in socket information */ - if( (xpa->fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) - goto error; - setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, - (char *)&keep_alive, sizeof(keep_alive)); - memset((char *)&sock_in, 0, sizeof(sock_in)); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, tbuf); - /* unset umask so that everyone can read and write */ - oum = umask(0); - /* bind to the file */ - got = xbind(xpa->fd, (struct sockaddr *)&sock_un, sizeof(sock_un)); - /* reset umask */ - umask(oum); - /* now check for bind error */ - if( got < 0 ) - goto error; - /* path is the method */ - xpa->method = xstrdup(tbuf); - break; -#endif - default: - goto error; - } - - /* listen for connections */ - if( listen(xpa->fd, XPA_MAXLISTEN) < 0 ) - goto error; - - /* make sure we close on exec */ - xfcntl(xpa->fd, F_SETFD, FD_CLOEXEC); - - /* add this xpa to end of list of xpas */ - XPAListAdd(&xpahead, xpa); - - /* publish this entry to the world */ - if( nsregister ) - XPANSAdd(xpa, NULL, NULL); - - /* make it active */ - XPAActive(xpa, NULL, 1); - -#if NO_AUTOMATIC_HAVE_ATEXIT - /* register XPA atexit funtion */ - if( !atexitinit ){ - atexit(_XPAAtExit); - atexitinit = getpid(); - } -#endif - - /* return good news */ - return(xpa); - -error: - XPAFree(xpa); - return(NULL); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAPoll - * - * Purpose: non-blocking handling of XPA access points - * timeout in millisecs, but if negative, no timeout is used - * - * Returns: number of requests processed (if maxreq >=0) - * number of requests pending (if maxreq <0) - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAPoll (int msec, int maxreq) -#else -int XPAPoll(msec, maxreq) - int msec; - int maxreq; -#endif -{ - int sgot; - int got=0; - fd_set readfds; - struct timeval tv; - struct timeval *tvp; - -again: - if( msec >= 0 ){ - tv.tv_sec = msec / 1000; - tv.tv_usec = (msec % 1000) * 1000; - tvp = &tv; - } - /* negative value means just block and wait */ - else{ - tvp = NULL; - } - FD_ZERO(&readfds); - if( XPAAddSelect(NULL, &readfds) ){ - sgot = xselect(swidth, &readfds, NULL, NULL, tvp); - /* error -- what should we do? */ - if( sgot < 0 ){ - if( xerrno == EINTR ) - goto again; - if( verbosity ){ - perror("XPAPoll() select"); - } - exit(1); - } - /* timeout -- just return */ - else if( sgot == 0 ) - ; - /* finally ... something to do */ - else{ - /* if maxreq < 0, just return how many are ready */ - if( maxreq < 0 ) - return(sgot); - else - got = XPAProcessSelect(&readfds, maxreq); - } - } - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAMainLoop - * - * Purpose: non-X programs event loop for handling XPA - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAMainLoop (void) -#else -int XPAMainLoop() -#endif -{ - int sgot; - int got=0; - fd_set readfds; - - - FD_ZERO(&readfds); - while( XPAAddSelect(NULL, &readfds) ){ - FPRINTF((stderr, "%sXPAMainLoop: waiting for select() ...\n", _sp)); - sgot = xselect(swidth, &readfds, NULL, NULL, NULL); - FPRINTF((stderr, "%sXPAMainLoop: select() returned: %d\n", _sp, sgot)); - /* error -- what should we do? */ - if( sgot < 0 ){ - if( xerrno == EINTR ){ - FD_ZERO(&readfds); - continue; - } - if( verbosity ){ - perror("XPAMainLoop() select"); - } - exit(1); - } - /* can't happen, since we have no timeout */ - else if( sgot == 0 ) - ; - /* finally ... something to do */ - else - got += XPAProcessSelect(&readfds, 0); - FD_ZERO(&readfds); - } - return(got); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASleep - * - * Purpose: sleep for specified milliseconds - * - * Returns: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void -XPASleep (int msec) -#else -void XPASleep(msec) - int msec; -#endif -{ - struct timeval tv; - - if( msec > 0 ){ - tv.tv_sec = msec / 1000; - tv.tv_usec = (msec % 1000) * 1000; - xselect(1, NULL, NULL, NULL, &tv); - } -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPAListHead - * - * Purpose: semi-public routine to return the head of the xpa list - * - * Results: XPA list pointer on success - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPAMtype (void) -#else -int XPAMtype() -#endif -{ - return(mtype); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPATmpdir - * - * Purpose: semi-public routine to return the tmpdir value - * - * Results: tmpdir - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -char * -XPATmpdir (void) -#else -char * XPATmpdir() -#endif -{ - return(tmpdir); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASetBuf - * - * Purpose: set the return buffer in a server send callback - * (use mainly by tcl to transfer tcl buffers to C) - * - * Returns: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASetBuf (XPA xpa, char *buf, size_t len, int xcopy) -#else -int XPASetBuf(xpa, buf, len, xcopy) - XPA xpa; - char *buf; - size_t len; - int xcopy; -#endif -{ - /* sanity check */ - if( !xpa || !xpa->comm ) - return(-1); - /* xcopy >0 => make a copy of the data, else just assign */ - if( xcopy ){ - xpa->comm->len = len; - if( (xpa->comm->buf = (char *)xmalloc(len)) == NULL ) - return(-1); - memcpy(xpa->comm->buf, buf, len); - } - else{ - xpa->comm->len = len; - xpa->comm->buf = buf; - } - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPASetBuf - * - * Purpose: set the return buffer in a server send callback - * (use mainly by tcl to transfer tcl buffers to C) - * - * Returns: 0 on success, -1 on failure - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -int -XPASetFree (XPA xpa, MyFree myfree, void *myfree_ptr) -#else - int XPASetFree(xpa, myfree, myfree_ptr) - XPA xpa; - MyFree myfree; - void *myfree_ptr; -#endif -{ - /* sanity check */ - if( !xpa || !xpa->comm ) return(-1); - /* set the free routine and data pointer */ - xpa->comm->myfree = myfree; - xpa->comm->myfree_ptr = myfree_ptr; - return(0); -} - -/* - *---------------------------------------------------------------------------- - * - * Routine: XPACleanup - * - * Purpose: make valgrind happy by freeing memory - * - * Results: none - * - *---------------------------------------------------------------------------- - */ -#ifdef ANSI_FUNC -void XPACleanup (void) -#else -void XPACleanup () -#endif -{ - XPAFreeReserved(); - XPAAclFree(); - if( tmpdir ){ - xfree(tmpdir); - tmpdir = NULL; - } -} - -#ifdef ANSI_FUNC -void XPASaveJmp(void *env) -#else -void XPASaveJmp(env) - void *env; -#endif -{ -#if HAVE_SETJMP_H - xalloc_savejmp((jmp_buf *)env); -#else - return; -#endif -} |