xpa-2.1.15/0002755000054000000360000000000012173475374011004 5ustar ericheadxpa-2.1.15/acl.c0000644000054000000360000002750112052464153011677 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * acl.c -- xpa access control list management * */ #include /* *---------------------------------------------------------------------------- * * * Private Routines * * *---------------------------------------------------------------------------- */ /* this is the head of the global list -- too lazy to do anything more */ static XACL aclhead=NULL; #ifdef ANSI_FUNC static XACL XPAAclLookup (char *xclass, char *name, unsigned int ip, int exact) #else static XACL XPAAclLookup(xclass, name, ip, exact) char *xclass; char *name; unsigned int ip; int exact; #endif { XACL cur; /* look for exact match */ for(cur=aclhead; cur!=NULL; cur=cur->next){ if( !strcmp(xclass, cur->xclass) && !strcmp(name, cur->name) && ((cur->ip == 0) || (cur->ip == ip)) ){ return(cur); } } /* otherwise look for a template match (unless exact was specified) */ if( !exact ){ for(cur=aclhead; cur!=NULL; cur=cur->next){ if( tmatch(xclass, cur->xclass) && tmatch(name, cur->name) && ((cur->ip == 0) || (cur->ip == ip)) ){ return(cur); } } } return(NULL); } /* *---------------------------------------------------------------------------- * * Routine: XPAAclParse * * Purpose: parse acl list into components * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAAclParse (char *lbuf, char *xclass, char *name, unsigned int *ip, char *acl, int len) #else static int XPAAclParse(lbuf, xclass, name, ip, acl, len) char *lbuf; char *xclass; char *name; unsigned int *ip; char *acl; int len; #endif { char tbuf[SZ_LINE]; int lp=0; /* class:name is required */ if( word(lbuf, tbuf, &lp) ){ XPAParseName(tbuf, xclass, name, len); } else return(-1); /* host is required but can be "*" for "all hosts" */ if( word(lbuf, tbuf, &lp) ){ if( !strcmp(tbuf, "*") ) *ip = 0; else *ip = gethostip(tbuf); } else return(-1); /* acl is required */ if( word(lbuf, tbuf, &lp) ){ if( !strcmp(tbuf, "+") ) strcpy(acl, XPA_ACLS); else if( !strcmp(tbuf, "-") ) *acl = '\0'; else strcpy(acl, tbuf); return(0); } else return(-1); } /* *---------------------------------------------------------------------------- * * * Semi-Public Routines (used by command.c) * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveAcl * * Purpose: add or modify the acl for this access point * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAReceiveAcl (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int XPAReceiveAcl(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; XPAComm comm; int i; int got; char *s=NULL; char lbuf[SZ_LINE]; char tbuf[SZ_LINE]; if( paramlist && *paramlist ){ s = paramlist; while( isspace((int)*s) ) s++; snprintf(tbuf, SZ_LINE, "%s:%s %s\n", xpa->xclass, xpa->name, s); if( XPAAclEdit(tbuf) < 0 ){ snprintf(lbuf, SZ_LINE, "invalid acl: %s\n", tbuf); XPAError(xpa, lbuf); return(-1); } } else{ while((XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPAShortTimeout())>0)&& *lbuf ){ snprintf(tbuf, SZ_LINE, "%s:%s %s\n", xpa->xclass, xpa->name, lbuf); got = XPAAclEdit(tbuf); if( got < 0 ){ snprintf(lbuf, SZ_LINE, "invalid acl: %s\n", tbuf); XPAError(xpa, lbuf); return(-1); } } } /* reset all acl flags for this xpa so acl is recalculated */ for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ for(i=0; i<4; i++){ comm->acl[i] = -1; } } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPASendAcl * * Purpose: return the acl for this access point * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASendAcl (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int XPASendAcl(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; XACL cur; int got = 0; char tbuf[SZ_LINE]; /* zero all flags */ for(cur=aclhead; cur!=NULL; cur=cur->next){ cur->flag = 0; } /* look for exact matches */ for(cur=aclhead; cur!=NULL; cur=cur->next){ if(!strcmp(xpa->xclass, cur->xclass) && !strcmp(xpa->name, cur->name)){ snprintf(tbuf, SZ_LINE, "%s:%s %s %s\n", cur->xclass, cur->name, getiphost(cur->ip), cur->acl); send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); cur->flag = 1; got++; } } /* look for template matches that we have not printed yet */ for(cur=aclhead; cur!=NULL; cur=cur->next){ if( cur->flag == 0 ){ if(tmatch(xpa->xclass, cur->xclass) && tmatch(xpa->name, cur->name)){ snprintf(tbuf, SZ_LINE, "%s:%s %s %s\n", cur->xclass, cur->name, getiphost(cur->ip), cur->acl); send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); got++; } } } /* zero all flags */ for(cur=aclhead; cur!=NULL; cur=cur->next){ cur->flag = 0; } if( got == 0 ){ send(xpa_datafd(xpa), "\n", 1, 0); } return(0); } /* *---------------------------------------------------------------------------- * * * Public Routines * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPAAclEdit * * Purpose: add or modify acl entry in the xpa acl list * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAclEdit (char *lbuf) #else int XPAAclEdit(lbuf) char *lbuf; #endif { XACL cur; char xclass[SZ_LINE]; char name[SZ_LINE]; char acl[SZ_LINE]; unsigned int ip; if( XPAAclParse(lbuf, xclass, name, &ip, acl, SZ_LINE) < 0 ) return(-1); if( ip == 0 ) return(-1); cur = XPAAclLookup(xclass, name, ip, 1); if( cur == NULL ) return(XPAAclAdd(lbuf)); else{ if( *acl == '\0' ){ XPAAclDel(cur); } else{ if( cur->acl ) xfree(cur->acl); cur->acl = xstrdup(acl); } return(0); } } /* *---------------------------------------------------------------------------- * * Routine: XPAAclAdd * * Purpose: add one acl entry to the xpa acl list * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAclAdd (char *lbuf) #else int XPAAclAdd(lbuf) char *lbuf; #endif { XACL xnew; XACL cur; char xclass[SZ_LINE]; char name[SZ_LINE]; char acl[SZ_LINE]; unsigned int ip; /* allocate acl struct */ if( (xnew = (XACL)xcalloc(1, sizeof(XACLRec))) == NULL ) goto error; /* parse info from line buffer */ if( XPAAclParse(lbuf, xclass, name, &ip, acl, SZ_LINE) < 0 ) goto error; /* fill in the blanks */ xnew->xclass = xstrdup(xclass); xnew->name = xstrdup(name); xnew->ip = ip; xnew->acl = xstrdup(acl); /* add this acl to end of list of acl's */ if( aclhead == NULL ){ aclhead = xnew; } else{ for(cur=aclhead; cur->next!=NULL; cur=cur->next) ; cur->next = xnew; } return(0); error: if( xnew ) xfree(xnew); return(-1); } /* *--------------------------------------------------------------------------- * * Routine: XPAAclDel * * Purpose: free up memory in the acl record structure * * Results: 0 on success, -1 for failure * *--------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAclDel (XACL acl) #else int XPAAclDel(acl) XACL acl; #endif { XACL cur; if( acl == NULL ) return(-1); /* remove from list of acl's */ if( aclhead ){ if( aclhead == acl ){ aclhead = aclhead->next; } else{ for(cur=aclhead; cur!=NULL; cur=cur->next){ if( cur->next == acl ){ cur->next = (cur->next)->next; break; } } } } /* free up string space */ if( acl->xclass ) xfree(acl->xclass); if( acl->name ) xfree(acl->name); if( acl->acl ) xfree(acl->acl); /* free up record struct */ xfree((char *)acl); return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPAAclFree * * Purpose: * * Results: 1 on success, 0 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC void XPAAclFree (void) #else void XPAAclFree() #endif { XACL cur, tacl; for(cur=aclhead; cur!=NULL; ){ tacl = cur->next; XPAAclDel(cur); cur = tacl; } } /* *---------------------------------------------------------------------------- * * Routine: XPAAclNew * * Purpose: read or re-read the acl list * * Results: number of lines in list (including default) * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAclNew (char *aname, int flag) #else int XPAAclNew(aname, flag) char *aname; int flag; #endif { int got=0; char lbuf[SZ_LINE]; char hostname[SZ_LINE]; char *s; char *obuf; char *aclname=NULL; char *aclpath=NULL; char *defacl=NULL; char *defcopy=NULL; char *keywords[10]; char *values[10]; int nkeys; FILE *fp=NULL; /* if there is an old list, free it */ if( flag == 0 ) XPAAclFree(); /* get acl file name */ if( aname && *aname ) aclname = aname; else if( (aclname=(char *)getenv("XPA_ACLFILE")) == NULL ) aclname = XPA_ACLFILE; /* get the default acl */ if( (defacl=(char *)getenv("XPA_DEFACL")) == NULL ) defacl = XPA_DEFACL; /* macro-expand it to deal with the host name */ gethost(hostname, SZ_LINE); nkeys = 0; keywords[0] = "host"; values[0] = hostname; nkeys++; /* open the acl file */ if( (aclpath=(char *)Access(aclname, "r")) != NULL ){ if( (fp=fopen(aclpath, "r")) != NULL ){ while( fgets(lbuf, SZ_LINE, fp) ){ if( *lbuf == '#' ){ continue; } if( (obuf=macro(lbuf, keywords, values, nkeys, NULL, NULL)) != NULL ){ if( XPAAclAdd(obuf) == 0 ) got++; xfree(obuf); } } fclose(fp); } xfree(aclpath); } /* add default acl (it very likely was overridden in the file) */ defcopy=(char *)xstrdup(defacl); for(s=(char *)strtok(defcopy,";"); s!=NULL; s=(char *)strtok(NULL,";")){ if( (obuf = macro(s, keywords, values, nkeys, NULL, NULL)) != NULL ){ if( XPAAclAdd(obuf) == 0 ) got++; xfree(obuf); } } if( defcopy) xfree(defcopy); /* return the news */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAAclCheck * * Purpose: validate an acl for a given class, name, and host * * Results: 1 on success, 0 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAclCheck (XPA xpa, unsigned int ip, char *acl) #else int XPAAclCheck(xpa, ip, acl) XPA xpa; unsigned int ip; char *acl; #endif { char *s; XACL cur; if( !(cur = XPAAclLookup(xpa->xclass, xpa->name, ip, 0)) ) return(0); else if( cur->acl == NULL ) return(0); else{ for(s=acl; *s; s++){ if( !strchr(cur->acl, *s) ) return(0); } return(1); } } xpa-2.1.15/client.c0000644000054000000360000023572312054717507012433 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ #include /* *---------------------------------------------------------------------------- * * * Private Routines and Data * * *---------------------------------------------------------------------------- */ /* this is the head of the global list of client xpas */ static XPA xpaclienthead=NULL; static char errbuf[SZ_LINE]; /* holds current error message */ static int id=0; /* id of current command */ #define DATA_CONNECT 1 #define DATA_ACCEPT 2 #define DATA_DATA 4 /* use of a double fork() call is used to prevent zombies which happen if fork is a child of xpans started by an XPA server (i.e., for some reason, the SIGCHLD signal does not get sent to xpans parent) See Stevens, Advanced Programming in te Unix Environment, p. 202 */ #define USE_DOUBLE_FORK 1 #ifndef USE_DOUBLE_FORK #ifdef ANSI_FUNC void sig_chld(int signo) #else #endif { int stat; while(waitpid(-1, &stat, WNOHANG) > 0){ ; } return; } #endif /* *---------------------------------------------------------------------------- * * Routine: rdl * * Purpose: read characters up a new-line * * Returns: number of characters read * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int rdl (int fd, char *buf, size_t len) #else static int rdl(fd, buf, len) int fd; char *buf; int len; #endif { int i=0; int got; /* start out clean */ *buf = '\0'; /* make sure we have a valid channel */ if( fd < 0 ) return(-1); /* grab characters up to a new-line or max len */ while( i < (len-1) ){ got = read(fd, &(buf[i]), 1); if( got < 1 ) break; else if( buf[i++] == '\n' ) break; } buf[i] = '\0'; return(i); } /* *---------------------------------------------------------------------------- * * Routine: XPAProxyAccept * * Purpose: accept a connection from an XPA proxy server * * Return: fd of accepted connection or -1 * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAProxyAccept(XPA xpa, char *method, char *xclass, char *name, int ifd, unsigned int *rip, unsigned short *rport, char *rname) #else static int XPAProxyAccept(xpa, method, xclass, name, ifd, rip, rport, rname) XPA xpa; char *method; char *xclass; char *name; int ifd; unsigned int *rip; unsigned short *rport; char *rname; #endif { int sock; int got; int oum; int ofd; int niter; int swidth=FD_SETSIZE; int keep_alive=1; int reuse_addr=1; unsigned int ip; unsigned short port; char tbuf[SZ_LINE]; char amethod[SZ_LINE]; char *tptr; socklen_t slen; struct sockaddr_in sock_in; #if HAVE_SYS_UN_H struct sockaddr_un sock_un; #endif struct timeval tv; struct timeval *tvp; fd_set readfds; /* initialize results */ if( rip ) *rip = 0; if( rport ) *rport = 0; if( rname ) *rname = '\0'; switch(XPAMethod(method)){ case XPA_INET: if( !XPAParseIpPort(method, &ip, &port) ){ goto error; } /* open a socket for data connections */ if( (sock = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ PERROR(("xpaaccept socket")); goto error; } setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr)); memset((char *)&sock_in, 0, sizeof(sock_in)); sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = htonl(INADDR_ANY); sock_in.sin_port = htons(port); /* bind to the ip:port */ if( xbind(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ PERROR(("xpaaccept bind")); xclose(sock); goto error; } snprintf(amethod, SZ_LINE, "%x:%d", ip, port); break; #if HAVE_SYS_UN_H case XPA_UNIX: ip = 0; port = 0; /* get filename part, composed of class and name and unique id */ snprintf(tbuf, SZ_LINE, "%s_%s.%d", xclass, name, (int)time(NULL)); /* change "/" to "_" for filename */ for(tptr = tbuf; *tptr != '\0'; tptr++){ if( *tptr == '/' ) *tptr = '_'; } /* create full pathname */ snprintf(amethod, SZ_LINE, "%s/%s", XPATmpdir(), tbuf); /* delete old copy */ unlink (amethod); /* open a socket and fill in socket information */ if( (sock = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ goto error; } setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); memset((char *)&sock_un, 0, sizeof(sock_un)); sock_un.sun_family = AF_UNIX; strcpy(sock_un.sun_path, amethod); /* unset umask so that everyone can read and write */ oum = umask(0); /* bind to the file */ got = xbind(sock, (struct sockaddr *)&sock_un, sizeof(sock_un)); /* reset umask to previous */ umask(oum); /* now check for bind error */ if( got < 0 ){ xclose(sock); goto error; } break; #endif default: goto error; } /* send port to client so they can connect */ /* first listen for the connection */ if( listen(sock, XPA_MAXLISTEN) < 0 ){ PERROR(("xpaaccept listen")); xclose(sock); goto error; } /* and tell the client that we are listening */ snprintf(tbuf, SZ_LINE, "xpaaccept %s (%s:%s %s)\n", amethod, xclass, name, method); FPRINTF((stderr, "%sXPAProxyAccept: sending command to %d:\n%s", _sp, ifd, tbuf)); if( XPAPuts(NULL, ifd, tbuf, XPAShortTimeout()) <= 0 ){ PERROR(("client xpaaccept write")); xclose(sock); goto error; } /* we will iterate on xselect */ if( XPAShortTimeout() > 0 ) niter = XPAShortTimeout()*100; else niter = XPA_SHORT_TIMEOUT*100; again: /* this has to be able to time out */ tv.tv_sec = 0; tv.tv_usec = 10000; tvp = &tv; /* wait for this socket and XPA sockets */ FD_ZERO(&readfds); FD_SET(sock, &readfds); XPAAddSelect(NULL, &readfds); /* wait for the connection */ got = xselect(swidth, &readfds, NULL, NULL, tvp); /* process results of select */ if( got > 0 ){ if( !FD_ISSET(sock, &readfds)){ XPAProcessSelect(&readfds, 0); goto again; } switch(XPAMethod(method)){ case XPA_INET: while( 1 ){ slen = sizeof(struct sockaddr_in); if((ofd=xaccept(sock, (struct sockaddr *)&sock_in, &slen)) >= 0){ break; } else{ if( xerrno == EINTR ) continue; else{ PERROR(("xpaaccept acccept")); xclose(sock); goto error; } } } break; #if HAVE_SYS_UN_H case XPA_UNIX: while( 1 ){ slen = sizeof(struct sockaddr_un); if((ofd=xaccept(sock, (struct sockaddr *)&sock_un, &slen)) >= 0){ break; } else{ if( xerrno == EINTR ) continue; else{ PERROR(("xpaaccept acccept")); xclose(sock); goto error; } } } break; #endif default: xclose(sock); goto error; } } /* timeout? */ else if( got == 0 ){ if( --niter > 0 ){ goto again; } else{ xclose(sock); FPRINTF((stderr, "%sXPAProxyAccept: select timed out\n", _sp)); goto error; } } /* error */ else{ if( xerrno == EINTR ){ PERROR(("xpaaccept select")); goto again; } else{ xclose(sock); goto error; } } /* done with listening */ xclose(sock); /* fill in return information */ if( rip ) *rip = ip; if( rport ) *rport = port; if( rname ){ strncpy(rname, amethod, SZ_LINE-1); rname[SZ_LINE-1] = '\0'; } return(ofd); error: return(-1); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientNewInput * * Purpose: allocate a new input struct for reading data from stdin * * Return: input struct, or NULL on error * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static XPAInput XPAClientNewInput(XPA xpa) #else static XPAInput XPAClientNewInput(xpa) XPA xpa; #endif { XPAInput xnew, inp; /* allocate a new record */ if( (xnew=(XPAInput)xcalloc(1, sizeof(XPAInputRec))) == NULL ){ return(NULL); } /* allocate the data buffer */ xnew->buf = (char *)xmalloc(XPA_BIOSIZE); /* this buffer starts (and currently ends) at the current byte count */ xnew->start = xpa->inpbytes; xnew->end = xpa->inpbytes; xnew->bytes = 0; /* add this input to end of list of input's */ if( xpa->inphead == NULL ){ xpa->inphead = xnew; } else{ for(inp=xpa->inphead; inp->next!=NULL; inp=inp->next) ; inp->next = xnew; } /* return the record struct */ return(xnew); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientFreeInput * * Purpose: free a input buffer once its been sent to all targets * * Return: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static void XPAClientFreeInput (XPA xpa, XPAInput inp) #else static void XPAClientFreeInput(xpa, inp) XPA xpa; XPAInput inp; #endif { XPAInput cur; if( !xpa || !inp ) return; if( inp == xpa->inphead ){ xpa->inphead = inp->next; } else{ for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ if( cur->next == inp ){ cur->next = inp->next; break; } } } /* free current record */ if( inp != NULL ){ if( inp->buf != NULL ) xfree(inp->buf ); xfree(inp); } } /* *---------------------------------------------------------------------------- * * Routine: XPAClientFreeAllInputs * * Purpose: free remaining input buffers * * Return: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static void XPAClientFreeAllInputs (XPA xpa) #else static void XPAClientFreeAllInputs(xpa) XPA xpa; #endif { XPAInput cur, tmp; if( !xpa ) return; for(cur=xpa->inphead; cur!=NULL; ){ tmp = cur->next; XPAClientFreeInput(xpa, cur); cur = tmp; } xpa->inpbytes = 0; } /* *---------------------------------------------------------------------------- * * Routine: XPAClientProcessInput * * Purpose: read input from stdin and store in an input struct * * Return: bytes read * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientProcessInput(XPA xpa) #else static int XPAClientProcessInput(xpa) XPA xpa; #endif { static XPAInput cur=NULL; int get, got; /* set up next buffer, if necessary */ for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ if( cur->bytes < XPA_BIOSIZE ) break; } if( cur == NULL ){ cur = XPAClientNewInput(xpa); } /* read data from stdin */ get = MIN(XPA_IOSIZE, XPA_BIOSIZE - cur->bytes); if( isatty(xpa->ifd) ){ got = rdl(xpa->ifd, &(cur->buf[cur->bytes]), get); } else{ got = read(xpa->ifd, &(cur->buf[cur->bytes]), get); } switch(got){ case -1: if( XPAVerbosity() ){ PERROR(("XPA client read")); } return(0); case 0: xpa->ifd = -1; FPRINTF((stderr, "%sXPAClientProcessInput: signalling EOF\n", _sp)); break; default: break; } cur->bytes += got; cur->end += got; xpa->inpbytes += got; #ifdef FIXEDBYCYGWIN #if HAVE_CYGWIN /* on non-NT Windows machines, Cygwin select() does not work once a pipe gets EOF. It should show the fd ready for reading (and read 0 bytes), but does not, so we have to hack a manual check */ /* GetVersion is a Windows call */ if( GetVersion() >= 0x80000000L ){ if( got < get ){ xpa->ifd = -1; } } #endif #endif /* verify to stdout, if necessary */ if( xpa->client_mode & XPA_CLIENT_VERIFY ){ fwrite(&(cur->buf[cur->bytes-got]), sizeof(char), got, stdout); } /* return the number of bytes just read */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientFree * * Purpose: free a client record and remove from list * * Returns: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static void XPAClientFree (XPA xpa, XPAClient client) #else static void XPAClientFree(xpa, client) XPA xpa; XPAClient client; #endif { XPAClient cur; /* remove from list of xpa's */ if( xpa->clienthead ){ if( xpa->clienthead == client ){ xpa->clienthead = client->next; } else{ for(cur=xpa->clienthead; cur!=NULL; cur=cur->next){ if( cur->next == client ){ cur->next = client->next; break; } } } } if( client->cmdfd >= 0 ){ #if HAVE_CYGWIN shutdown(client->cmdfd, SHUT_RDWR); #endif xclose(client->cmdfd); } if( client->datafd >= 0 ){ #if HAVE_CYGWIN shutdown(client->datafd, SHUT_RDWR); #endif xclose(client->datafd); } if( client->dataname ){ unlink(client->dataname); xfree(client->dataname); } if( client->method ) xfree(client->method); if( client->info ) xfree(client->info); if( client->xtemplate ) xfree(client->xtemplate); if( client->xclass ) xfree(client->xclass); if( client->name ) xfree(client->name); if( client->id ) xfree(client->id); /* xpaget's fd mode has an alloc'ed bufptr and lenptr */ if( (client->type == 'g') && (client->mode & XPA_CLIENT_FD) ){ if( client->bufptr && *(client->bufptr) ) xfree(*(client->bufptr)); if( client->bufptr ) xfree(client->bufptr); if( client->lenptr ) xfree(client->lenptr); } xfree(client); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientDataSent * * Purpose: data is sent, so close data channel and change status to * signal that we are waiting for the server * * Returns: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static void XPAClientDataSent (XPA xpa, XPAClient client) #else static void XPAClientDataSent(xpa, client) XPA xpa; XPAClient client; #endif { FPRINTF((stderr, "%sXPAClientDataSent: for cmd %d data %d\n", _sp, client->cmdfd, client->datafd)); /* close the data channel, which should trigger a result from the server */ if( client->datafd >= 0 ){ #if HAVE_CYGWIN shutdown(client->datafd, SHUT_RDWR); #endif xclose(client->datafd); client->datafd = -1; } /* we are now waiting for the server to complete the calllback */ client->status = XPA_CLIENT_WAITING; } /* *---------------------------------------------------------------------------- * * Routine: XPAClientEnd * * Purpose: finish up with this client * * Returns: error message or null * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static char * XPAClientEnd (XPA xpa, XPAClient client) #else static char *XPAClientEnd(xpa, client) XPA xpa; XPAClient client; #endif { char *error=NULL; char *eptr; FPRINTF((stderr, "%sXPAClientEnd: for cmd %d data %d\n", _sp, client->cmdfd, client->datafd)); /* always read the status line -- if we are not ack'ing, we'll get an OK from the server before the calllback and we can exit quickly */ /* don't do this if client is xpainfo and we're not ack'ing */ if( !((client->type == 'i') && !(client->mode & XPA_CLIENT_ACK)) ){ retry: if( XPAGets(NULL, client->cmdfd, errbuf, SZ_LINE, XPALongTimeout()) >0 ){ FPRINTF((stderr, "%sXPAClientEnd: read %s\n", _sp, errbuf)); eptr = errbuf; /* this should never happen */ if( *eptr == '?' ){ snprintf(errbuf, SZ_LINE, "XPA$WARNING: protocol mismatch - missing id\n%s", eptr); error = NULL; } else{ /* make sure we are dealing with a proper message */ if( strncmp(eptr, client->id, strlen(client->id)) ){ if( XPAVerbosity() > 1 ){ fprintf(stderr, "XPA$WARNING: ignoring out of sync server message:\n"); fprintf(stderr, "%s", errbuf); } goto retry; } /* go past id */ eptr += strlen(client->id); while( isspace((int)*eptr) ) eptr++; if( !strncmp(eptr, "XPA$OK", 6) ){ error = NULL; } else{ error = eptr; } } } else{ if( XPAVerbosity() > 1 ){ fprintf(stderr, "XPA$WARNING: no reply from server callback (assuming OK)\n"); } error = NULL; } } else error = NULL; /* store the error return */ if( client->errptr ) *(client->errptr) = xstrdup(error); /* remove this client if we are not meant to persist */ if( !xpa->persist ){ XPAClientFree(xpa, client); } /* otherwise mark as inactive */ else{ client->status = XPA_CLIENT_IDLE; client->bytes = 0; } /* return error status */ return(error); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientNew * * Purpose: allocate a new xpa client * * Returns: xpa client struct * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static XPAClient XPAClientNew (XPA xpa, char *mode, char *xtemplate, int type, char *xclass, char *name, char *method, char *info) #else static XPAClient XPAClientNew(xpa, mode, xtemplate, type, xclass, name, method, info) XPA xpa; char *mode; char *xtemplate; int type; char *xclass; char *name; char *method; char *info; #endif { XPAClient xnew, client; struct sockaddr_in sock_in; #if HAVE_SYS_UN_H struct sockaddr_un sock_un; #endif char xmode[SZ_LINE]; char tbuf[SZ_LINE]; char amethod[SZ_LINE]; char *s=NULL; unsigned short port; unsigned int ip=0; int fd; int pfd; int tries=0; int nsproxy=0; int keep_alive=1; FPRINTF((stderr, "%sXPAClientNew: entering with %s %s %s %s\n", _sp, xclass, name, method, info)); /* no errors as yet */ *errbuf = '\0'; /* look for reuse of xpans fd (used in conjunction with the xpans proxy) */ *xmode = '\0'; if( mode ){ strncpy(xmode, mode, SZ_LINE-1); xmode[SZ_LINE-1] = '\0'; } if( keyword(xmode, "nsproxy", tbuf, SZ_LINE) ){ nsproxy = 1; pfd = strtol(tbuf, &s, 0); fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), xclass, name, pfd, &ip, &port, amethod); /* make sure we got a valid int fd */ if( fd < 0 ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server on proxyaccept (%s:%s%s)\n", xclass, name, XPATimestamp()); FPRINTF((stderr, "%sXPAClientNew: %s", _sp, errbuf)); PERROR(("XPAClientNew")); return(NULL); } } /* normal usage: connect to server */ else{ switch(XPAMethod(method)){ case XPA_INET: again1: if( !XPAParseIpPort(method, &ip, &port) ) return(NULL); /* use $localhost over $host (we do not trust host to be correct) */ if( (ip == gethostip("$host")) && (tries == 0) ) ip = gethostip("$localhost"); /* connect to the server before we go further */ if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ return(NULL); } setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); memset((char *)&sock_in, 0, sizeof(sock_in)); sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = htonl(ip); sock_in.sin_port = htons(port); /* make the connection with the server */ if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) <0 ){ xclose(fd); /* if localhost doesn't work, make one try with the host ip */ /* we also try again just in case there was an odd error such as "permission denied", which we have seen once or twice */ if( tries < 2 ){ tries++; goto again1; } /* give up */ else{ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server on connect (%s:%s%s)\n", xclass, name, XPATimestamp()); PERROR(("XPAClientNew")); return(NULL); } } /* make sure we close on exec */ xfcntl(fd, F_SETFD, FD_CLOEXEC); FPRINTF((stderr, "%sXPAClientNew: inet connect returns fd %d\n", _sp, fd)); break; #if HAVE_SYS_UN_H case XPA_UNIX: again2: /* open a socket and fill in socket information */ if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ return(NULL); } setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); memset((char *)&sock_un, 0, sizeof(sock_un)); sock_un.sun_family = AF_UNIX; strcpy(sock_un.sun_path, method); /* make the connection with the server */ if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) <0 ){ xclose(fd); /* Unix sockets get ECONNREFUSED when the listen queue is full, so we try a few times to give the server a chance to recover */ if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ tries++; XPASleep(10); goto again2; } /* give up */ else{ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server on connect (%s:%s%s)\n", xclass, name, XPATimestamp()); PERROR(("XPAClientNew")); return(NULL); } } /* make sure we close on exec */ xfcntl(fd, F_SETFD, FD_CLOEXEC); FPRINTF((stderr, "%sXPAClientNew: unix connect returns fd %d\n", _sp, fd)); break; #endif default: return(NULL); } strncpy(amethod, method, SZ_LINE-1); amethod[SZ_LINE-1] = '\0'; } /* allocate new send record */ if( (xnew=(XPAClient)xcalloc(1, sizeof(XPAClientRec))) == NULL ){ xclose(fd); return(NULL); } /* fill in the blanks */ xnew->xtemplate = xstrdup(xtemplate); xnew->type = type; xnew->cmdfd = fd; xnew->datafd = -1; xnew->xclass = xstrdup(xclass); xnew->name = xstrdup(name); xnew->method = xstrdup(amethod); xnew->info = xstrdup(info); xnew->ip = ip; xnew->nsproxy = nsproxy; xnew->status = XPA_CLIENT_ACTIVE; /* now that we have a valid client, add to list */ if( xpa->clienthead == NULL ){ xpa->clienthead = xnew; } else{ for(client=xpa->clienthead; client->next!=NULL; client=client->next) ; client->next = xnew; } FPRINTF((stderr, "%sXPAClientNew: new fd %d\n", _sp, xnew->cmdfd)); /* return the good news */ return(xnew); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientAddSelect * * Purpose: add one or more xpa client sockets to the select flags * * Return: number of clients that were added to the select flags * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAClientAddSelect (XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr) #else int XPAClientAddSelect(xpa, readfdsptr, writefdsptr) XPA xpa; fd_set *readfdsptr; fd_set *writefdsptr; #endif { XPAClient client; int got=0; int loop=0; /* better have some place to set the flags */ if( readfdsptr == NULL ) return(0); /* if no xpa is specified, do them all */ if( xpa == NULL ){ if( xpaclienthead == NULL ) return(0); xpa = xpaclienthead; loop = 1; } loop: /* set select flags for all clients */ for(client=xpa->clienthead; client!=NULL; client=client->next){ /* if this client is processing */ if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >= 0) ){ if( client->type == 'g' ){ FPRINTF((stderr, "%sXPAClientAddSelect(get): adding fd %d\n", _sp, client->datafd)); FD_SET(client->datafd, readfdsptr); got++; } else if( client->type == 's' ){ FPRINTF((stderr, "%sXPAClientAddSelect(set): adding fd %d\n", _sp, client->datafd)); FD_SET(client->datafd, writefdsptr); got++; } } /* if this client is waiting */ else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ FPRINTF((stderr, "%sXPAClientAddSelect(waiting): adding fd %d\n", _sp, client->cmdfd)); FD_SET(client->cmdfd, readfdsptr); got++; } } /* loop if necessary */ if( loop && (xpa=xpa->next) ) goto loop; /* return the news */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientGet * * Purpose: process an xpaget request for a given client * * Return: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientGet (XPA xpa, XPAClient client) #else static int XPAClientGet(xpa, client) XPA xpa; XPAClient client; #endif { int status; char tbuf[SZ_LINE]; /* allocate the first buffer, if necessary */ if( *(client->bufptr) == NULL ){ client->bufsize = XPA_IOSIZE; *(client->bufptr) = (char *)xmalloc(client->bufsize); *(client->lenptr) = 0; } if( (*(client->lenptr) + XPA_IOSIZE) > client->bufsize ){ client->bufsize += (XPA_IOSIZE*10); *(client->bufptr) = (char *)xrealloc(*(client->bufptr), client->bufsize); } /* now retrieve the data from the server */ status = recv(client->datafd, *(client->bufptr) + *(client->lenptr), XPA_IOSIZE, 0); /* status < 0 means error */ switch(status){ /* error */ case -1: /* socket would block */ if((xerrno == EINPROGRESS) || (xerrno == EWOULDBLOCK)){ return(0); } /* clean up after error */ if( *(client->bufptr) ){ xfree(*(client->bufptr)); *(client->bufptr) = NULL; client->bufsize = 0; } *(client->lenptr) = 0; XPAClientDataSent(xpa, client); #ifdef OLD (void)XPAClientEnd(xpa, client); /* we need to flag some sort of error, if nothing came across */ if( *(client->errptr) == NULL ){ *(client->errptr) = xstrdup( "XPA$ERROR: incomplete transmission from server\n"); } #endif break; /* eof */ case 0: /* if we have multiple clients, we now need to write this one */ if( client->mode & XPA_CLIENT_FD ){ if( xpa->nclient > 1 ){ snprintf(tbuf, SZ_LINE, "XPA$BEGIN %s:%s %s\n", client->xclass, client->name, client->method); write(client->fd, tbuf, strlen(tbuf)); } write(client->fd, *(client->bufptr), *(client->lenptr)); if( xpa->nclient > 1 ){ snprintf(tbuf, SZ_LINE, "XPA$END %s:%s %s\n", client->xclass, client->name, client->method); write(client->fd, tbuf, strlen(tbuf)); } /* we can free buf, since its not being passed back */ if( *(client->bufptr) ){ xfree(*(client->bufptr)); *(client->bufptr) = NULL; client->bufsize = 0; } } else{ /* set final buffer size and put a convenience null at the end */ if( *(client->bufptr) ){ client->bufsize = *(client->lenptr)+1; *(client->bufptr) = (char *)xrealloc(*(client->bufptr),client->bufsize); *(*(client->bufptr)+*(client->lenptr)) = '\0'; } } /* for all clients, we need to clean up */ XPAClientDataSent(xpa, client); #ifdef OLD (void)XPAClientEnd(xpa, client); #endif break; /* status > 0: bytes read */ default: *(client->lenptr) += status; /* for single client fd mode, we write immediately -- this deals with the important case of one client with a large amount of data */ if( (client->mode & XPA_CLIENT_FD) && (xpa->nclient == 1) ){ write(client->fd, *(client->bufptr), *(client->lenptr)); /* reset buf for next read */ if( *(client->bufptr) ) xfree(*(client->bufptr)); *(client->bufptr) = NULL; *(client->lenptr) = 0; } break; } return(status); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientSet * * Purpose: process an xpaset request for a given client * * Return: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientSet (XPA xpa, XPAClient client) #else static int XPAClientSet(xpa, client) XPA xpa; XPAClient client; #endif { int status; int left; int got; int len; XPAInput inp; if( client->mode & XPA_CLIENT_BUF ){ while( 1 ){ len = MIN(XPA_IOSIZE, client->len - client->bytes); /* see if we have written it all */ if( len == 0 ){ status = 1; goto done; } /* write the next chunk */ FPRINTF((stderr, "%sXPAClientSet: fd %d sending %lu bytes (%lu - %lu)\n", _sp, client->datafd, (unsigned long)len, (unsigned long)client->len, (unsigned long)client->bytes)); got=send(client->datafd, &(client->buf[client->bytes]), len, 0); if( got >= 0 ){ client->bytes += got; if( XPALevelGet() >0 ) return(got); } else{ PERROR(("XPAClientSet")); /* check for error */ if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ status = -1; goto done; } /* write would block, so we return and wait the server */ else{ return(0); } } } } /* reading from stdin and writing to servers */ else{ /* find the input buf that contains the data we need */ for(inp=xpa->inphead; inp!=NULL; inp=inp->next){ if( (client->bytes >= inp->start) && (client->bytes < inp->end) ){ break; } } /* if we can't find a buffer ... */ if( !inp ){ /* ... and we have all the input, we are done */ if( xpa->ifd < 0 ){ FPRINTF((stderr, "%sXPAClientSet: all data read\n", _sp)); status = 1; goto done; } /* ... but there is more input to come, return */ else{ return(0); } } /* optimization: don't write a buffer until its full (or until eof) */ if( (xpa->ifd >=0) && (inp->bytes < XPA_BIOSIZE) ){ return(0); } /* write bytes until we would block or until end of this buffer, etc */ while( 1 ){ len = MIN(XPA_IOSIZE, inp->end - client->bytes); FPRINTF((stderr, "%sXPAClientSet: has %lu=min(%d,(%lu-%lu)) [%d]\n", _sp, (unsigned long)len, XPA_IOSIZE, (unsigned long)inp->end, (unsigned long)client->bytes, client->status)); /* if we are done with this buffer, just return */ if( (client->status == XPA_CLIENT_PROCESSING) && (len <=0) ){ /* see if everyone else is done with this buffer as well, in which case we can free it */ left = 0; for(client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type != 's') || !(client->mode & XPA_CLIENT_FD) ) continue; /* in order to be totally written out, the following must be true: * 1. send->bytes must be past the end of this buffer * and * 2. this buffer must be filled or else we hit eof */ FPRINTF((stderr, "%sXPAClientSet: %lu>=%lu && ((%lu>=%d) or %d<0)) .. ", _sp, client->bytes, (unsigned long)inp->end, (unsigned long)inp->bytes, XPA_BIOSIZE, xpa->ifd)); if( (client->bytes >= inp->end) && ((inp->bytes >= XPA_BIOSIZE) || (xpa->ifd < 0)) ){ /* buffer complete written */ FPRINTF((stderr, "%sEOF (%lu)\n", _sp, (unsigned long)xpa->inpbytes)); ; } else{ FPRINTF((stderr, "%s\n", _sp)); /* buffer not complete written */ left++; break; } } /* if nothing is left, we can free this input struct */ if( !left ){ XPAClientFreeInput(xpa, inp); } return(0); } /* write to the server */ FPRINTF((stderr, "%sXPAClientSet: fd %d sending %lu bytes (%lu):\n", _sp, client->datafd, (unsigned long)len, (unsigned long)client->bytes)); got = send(client->datafd, &(inp->buf[client->bytes-inp->start]),len,0); /* check for success */ if( got >= 0 ){ /* update the number of bytes we wrote */ client->bytes += got; FPRINTF((stderr, "%sXPAClientSet: sent %lu bytes (total is %lu)\n", _sp, (unsigned long)got, (unsigned long)client->bytes)); /* go back for more */ if( XPALevelGet() >0 ) return(got); else continue; } /* check for error */ else{ PERROR(("XPAClientSet")); /* anything but a "would block" error is bad */ if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ status = -1; goto done; } /* write would block, so we return and wait the server */ else{ FPRINTF((stderr, "%sXPAClientSet: waiting for more data\n", _sp)); return(0); } } } } done: XPAClientDataSent(xpa, client); #ifdef OLD (void)XPAClientEnd(xpa, client); #endif return(status); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientProcessSelect * * Purpose: process xpas that have pending reads or writes * * Return: number of xpas processed * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAClientProcessSelect (XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr, int maxreq) #else int XPAClientProcessSelect(xpa, readfdsptr, writefdsptr, maxreq) XPA xpa; fd_set *readfdsptr; fd_set *writefdsptr; int maxreq; #endif { int got=0; int loop=0; XPAClient client; /* <= 0 means do all of them */ if( maxreq < 0 ){ maxreq = 0; } /* if no xpa is specified, do them all */ if( xpa == NULL ){ if( xpaclienthead == NULL ) return(0); xpa = xpaclienthead; loop = 1; } loop: /* first process any new input before we write output */ if( xfd_isset_stdin(xpa->ifd, readfdsptr) ){ xfd_clr_stdin(xpa->ifd, readfdsptr); XPAClientProcessInput(xpa); } /* look at all clients */ again: for(client=xpa->clienthead; client!=NULL; client=client->next){ /* if we are processing */ if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd>=0) ){ /* then handle new requests */ if((client->type == 'g') && FD_ISSET(client->datafd, readfdsptr)){ FD_CLR(client->datafd, readfdsptr); XPAClientGet(xpa, client); got++; if( maxreq && (got >= maxreq) ) return(got); goto again; } else if((client->type == 's') && FD_ISSET(client->datafd, writefdsptr)){ FD_CLR(client->datafd, writefdsptr); /* if the return is > 0, we completed the send */ if( XPAClientSet(xpa, client) > 0 ) got++; if( maxreq && (got >= maxreq) ) return(got); goto again; } } /* if this client is waiting */ else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ if( FD_ISSET(client->cmdfd, readfdsptr)){ FD_CLR(client->cmdfd, readfdsptr); XPAClientEnd(xpa, client); got++; if( maxreq && (got >= maxreq) ) return(got); goto again; } } } /* loop if necessary */ if( loop && (xpa=xpa->next) ) goto loop; /* return the news */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientLoop * * Purpose: non-X programs event loop for handling XPA client events * * Returns: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientLoop (XPA xpa, int mode) #else static int XPAClientLoop(xpa, mode) XPA xpa; int mode; #endif { int got=0; int sgot; int doxpa=1; int ltimeout; char *s=NULL; fd_set readfds; fd_set writefds; static int width=0; struct timeval tv; struct timeval *tvp; /* set width once */ if( width == 0 ){ width = FD_SETSIZE; } /* allow environment to turn off xpa server processing in client loop */ if( (s=getenv("XPA_CLIENT_DOXPA")) && isfalse(s) ){ doxpa = 0; } ltimeout = XPALongTimeout(); FD_ZERO(&readfds); FD_ZERO(&writefds); while( XPAClientAddSelect(xpa, &readfds, &writefds) ){ /* add other XPA's and process them as we process the client */ if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ FPRINTF((stderr, "%sXPAClientLoop: will handle server reqs ...\n", _sp)); XPAAddSelect(NULL, &readfds); } /* hopefully, a server will respond in a finite amount of time */ if( ltimeout > 0 ){ tv.tv_sec = ltimeout; tv.tv_usec = 0; tvp = &tv; } /* wait forever, if necessary */ else{ tvp = NULL; } /* add stdin to select, if there is one */ if( xpa->ifd >= 0 ){ xfd_set_stdin(xpa->ifd, &readfds); #if HAVE_MINGW32 /* BUT: for windows, we can't add stdin to select and therefore we must set a short timeout and look manually */ tv.tv_sec = 0; tv.tv_usec = 10000; /* this is the number of window iterations we will perform */ if( ltimeout > 0 ) ltimeout *= 100; tvp = &tv; #endif } /* wait for a server to respond */ FPRINTF((stderr, "%sXPAClientLoop: waiting on select() ...\n", _sp)); sgot = xselect(width, &readfds, &writefds, NULL, tvp); FPRINTF((stderr, "%sXPAClientLoop: select returns: %d\n", _sp, sgot)); /* error -- what should we do? */ if( sgot < 0 ){ if( xerrno == EINTR ){ FD_ZERO(&readfds); FD_ZERO(&writefds); continue; } if( XPAVerbosity() ){ perror("XPAClientLoop() select"); } exit(1); } /* timed out -- no one responded */ else if( sgot == 0 ){ #if HAVE_MINGW32 if( xpa->ifd >= 0 ){ if( ltimeout > 0 ){ if( --ltimeout <= 0 ) break; } } else{ break; } #else break; #endif } else{ got += XPAClientProcessSelect(xpa, &readfds, &writefds, 0); if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ got += XPAProcessSelect(&readfds, 0); } } FD_ZERO(&readfds); FD_ZERO(&writefds); } return(got); } #if HAVE_MINGW32==0 /* *---------------------------------------------------------------------------- * * Routine: XPAClientLoopFork * * Purpose: non-X programs forked event loop for handling XPA client events * * Returns: number of clients "processed" * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientLoopFork (XPA xpa, int mode) #else static int XPAClientLoopFork(xpa, mode) XPA xpa; int mode; #endif { XPAClient client, tclient; pid_t pid; int got; int fd[2]; char active=1; #ifndef USE_DOUBLE_FORK struct sigaction act; /* set up the signal handler to reap children (to avoid zombies) */ act.sa_handler = sig_chld; sigemptyset(&act.sa_mask); act.sa_flags = 0; #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif #ifdef SA_NOCLDWAIT act.sa_flags |= SA_NOCLDWAIT; #endif sigaction(SIGCHLD, &act, NULL); #endif if( pipe(fd) < 0 ){ got = 0; } else if( (pid = fork()) < 0 ){ close(fd[0]); close(fd[1]); got=0; } else if( pid == 0 ){ /* child */ /* child write to parent that he is active */ close(fd[0]); write(fd[1], &active, 1); close(fd[1]); #ifdef USE_DOUBLE_FORK /* second fork prevents zombies: when child/parent exits, second child is inherited by init and thus is not a child of original parent */ if( (pid = fork()) >= 0 ){ /* child/parent exits */ if( pid > 0 ) exit(0); /* new child goes on under init ... */ } #endif /* enter the main loop and process */ XPAIOCallsXPA(0); XPAClientLoop(xpa, mode); exit(0); } else { /* parent */ /* parent waits for child to wake up */ close(fd[1]); read(fd[0], &active, 1); close(fd[0]); #ifdef USE_DOUBLE_FORK /* for double fork, also wait for intermediate process to exit */ waitpid(pid, NULL, 0); #endif /* fake end of clients */ for(got=0, client=xpa->clienthead; client!=NULL; ){ got++; tclient = client->next; if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >=0) ){ #if HAVE_CYGWIN /* In Cygwin, we call shutdown (as well as close) to avoid Windows problems. The parent can't do this since the child is using the sockets, so we just close the sockets explicitly here */ xclose(client->datafd); client->datafd = -1; if( !xpa->persist ){ xclose(client->cmdfd); client->cmdfd = -1; } #endif client->errptr = NULL; /* remove this client if we are not meant to persist */ if( !xpa->persist ){ XPAClientFree(xpa, client); } /* otherwise mark as inactive */ else{ client->status = XPA_CLIENT_IDLE; client->bytes = 0; } } client = tclient; } } return(got); } #endif /* *---------------------------------------------------------------------------- * * Routine: XPAClientConnect * * Purpose: go to name service and get new names, merge with old, * and connect to servers * * Returns: number of connections * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientConnect (XPA xpa, char *mode, char *xtemplate, int type) #else static int XPAClientConnect(xpa, mode, xtemplate, type) XPA xpa; char *mode; char *xtemplate; int type; #endif { int i; int n; int got; int lp=0; int total=0; char **xclasses; char **names; char **methods; char **infos; char xtype[2]; char xmode[SZ_LINE]; char tbuf[SZ_LINE]; char lbuf[SZ_LINE]; XPAClient client; /* do some initialization */ XPAInitEnv(); /* make sure we have a target */ if( !xtemplate || !*xtemplate ) return(0); /* make a string out of the type for the lookup */ xtype[0] = type; xtype[1] = '\0'; /* reset the number of clients we are processing */ xpa->nclient = 0; /* look for specific proxy info */ *xmode = '\0'; if( mode ){ strncpy(xmode, mode, SZ_LINE-1); xmode[SZ_LINE-1] = '\0'; } if( keyword(xmode, "ns", lbuf, SZ_LINE) ){ FPRINTF((stderr, "%sXPAClientConnect: using ns info: %s\n", _sp, lbuf)); newdtable("(),"); xclasses = (char **)xmalloc(sizeof(char *)); names = (char **)xmalloc(sizeof(char *)); methods = (char **)xmalloc(sizeof(char *)); infos = (char **)xmalloc(sizeof(char *)); if( word(lbuf, tbuf, &lp) ) xclasses[0] = xstrdup(tbuf); if( word(lbuf, tbuf, &lp) ) names[0] = xstrdup(tbuf); if( word(lbuf, tbuf, &lp) ) methods[0] = xstrdup(tbuf); infos[0] = xstrdup(XPA_DEF_CLIENT_INFO); n = 1; freedtable(); } /* else ask xpans for access points matching the template */ else{ n = XPANSLookup(xpa, xtemplate, xtype, &xclasses, &names, &methods, &infos); } /* mark existing clients who do not match this template */ for(got=0, client=xpa->clienthead; client !=NULL; client=client->next){ for(i=0; itype == type) && (!strcmp(client->xclass, xclasses[i])) && (!strcmp(client->name, names[i])) && (!strcmp(client->method, methods[i])) && (!strcmp(client->info, infos[i])) ){ got++; } } /* don't unmark if its a different type -- someone else might be active */ if( !got && (client->type == type) ){ client->status = XPA_CLIENT_IDLE; } } /* add new clients for this type */ for(i=0; iclienthead; client !=NULL; client=client->next){ if( (client->type == type) && (!strcmp(client->xclass, xclasses[i])) && (!strcmp(client->name, names[i])) && (!strcmp(client->method, methods[i])) && (!strcmp(client->info, infos[i])) ){ /* might have to change the template */ if( strcmp(client->xtemplate, xtemplate) ){ xfree(client->xtemplate); client->xtemplate = xstrdup(xtemplate); } client->status = XPA_CLIENT_ACTIVE; got++; total++; FPRINTF((stderr, "%sXPAClientConnect: existing match: %s %s %s\n", _sp, xclasses[i], names[i], methods[i])); break; } } if( !got ){ FPRINTF((stderr, "%sXPAClientConnect: calls XPAClientNew for %s:%s %s\n", _sp, xclasses[i], names[i], methods[i])); if( XPAClientNew(xpa, mode, xtemplate, type, xclasses[i], names[i], methods[i], infos[i]) ) total++; } /* done with these strings */ xfree(xclasses[i]); xfree(names[i]); xfree(methods[i]); xfree(infos[i]); } /* free up arrays alloc'ed by names server */ if( n > 0 ){ xfree(xclasses); xfree(names); xfree(methods); xfree(infos); } return(total); } /* *---------------------------------------------------------------------------- * * Routine: XPAClientStart * * Purpose: send init string to server and perform other authentication * tasks * * Returns: 0 if success, -1 otherwise * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAClientStart (XPA xpa, XPAClient client, char *paramlist, char *mode) #else static int XPAClientStart(xpa, client, paramlist, mode) XPA xpa; XPAClient client; char *paramlist; char *mode; #endif { int fd=0; int lp=0; int flags; int tries=0; int dmode=0; int keep_alive=1; unsigned int ip=0; unsigned short port; char tbuf[SZ_LINE]; char tbuf2[SZ_LINE]; char lbuf[SZ_LINE]; char *cmd=NULL; char *method=NULL; struct sockaddr_in sock_in; #if HAVE_SYS_UN_H struct sockaddr_un sock_un; #endif switch(client->type){ case 'a': cmd = "xpaaccess"; break; case 'g': cmd = "xpaget"; break; case 'i': cmd = "xpainfo"; break; case 's': cmd = "xpaset"; break; } /* get mode flags */ XPAMode(mode, &(client->mode), "ack", XPA_CLIENT_ACK, 1); if( client->type == 's' ) XPAMode(mode, &(xpa->client_mode), "verify", XPA_CLIENT_VERIFY, 0); /* package up and send the initialization message */ strcpy(lbuf, cmd); /* set and save the id value */ snprintf(tbuf, SZ_LINE, "%c%d", client->type, id++); if( client->id ) xfree(client->id); client->id = xstrdup(tbuf); /* if we are using the xpans proxy, we will want to call accept() (server calls connect()) for the data channel */ if( client->nsproxy ) strcat(lbuf, " -a"); /* set the value of the client big-endian-ness */ snprintf(tbuf, SZ_LINE, " -e %s", XPAEndian() ? "big" : "little"); strcat(lbuf, tbuf); snprintf(tbuf, SZ_LINE, " -i %s", client->id); strcat(lbuf, tbuf); if( !(client->mode & XPA_CLIENT_ACK) ) strcat(lbuf, " -n"); if( strcmp(client->info, XPA_DEF_CLIENT_INFO) ){ snprintf(tbuf, SZ_LINE, " -p %s", client->info); strcat(lbuf, tbuf); } snprintf(tbuf, SZ_LINE, " %s:%s", client->xclass, client->name); strcat(lbuf, tbuf); if( paramlist && *paramlist ){ strcat(lbuf, " "); strncat(lbuf, paramlist, MAX(0,(int)(SZ_LINE-(int)strlen(lbuf)-2))); } strcat(lbuf, "\n"); FPRINTF((stderr, "%sXPAClientStart: fd %d sends:\n%s", _sp, client->cmdfd, lbuf)); if( XPAPuts(NULL, client->cmdfd, lbuf, XPAShortTimeout()) <= 0 ){ goto error; } /* if xpainfo and no ack'ing, we are basically done */ if( (client->type == 'i') && !(client->mode & XPA_CLIENT_ACK) ){ goto done; } /* authentication */ retry: lp = 0; if( XPAGets(NULL, client->cmdfd, lbuf, SZ_LINE, XPAShortTimeout()) >0 ){ FPRINTF((stderr, "%sXPAClientStart: fd %d received cmd:\n%s", _sp, client->cmdfd, lbuf)); /* this should never happen */ if( !word(lbuf, tbuf, &lp) || (*tbuf == '?') ){ snprintf(errbuf, SZ_LINE, "XPA$WARNING: Protocol mismatch: id\n%s", lbuf); goto error; } /* make sure we are dealing with a proper message */ if( strcmp(tbuf, client->id) ){ FPRINTF((stderr, "%sXPA$WARNING: ignoring out of sync message:\n", _sp)); FPRINTF((stderr, "%s", lbuf)); if( XPAVerbosity() > 1 ){ fprintf(stderr, "XPA$WARNING: ignoring out of sync server message:\n"); fprintf(stderr, "%s", lbuf); } goto retry; } /* this should never happen */ if( !word(lbuf, tbuf, &lp) ){ snprintf(errbuf, SZ_LINE, "XPA$WARNING: missing BUF request\n%s", lbuf); goto error; } if( !strcmp(tbuf, "XPA$NODATA") || !strcmp(tbuf, "XPA$NOBUF") ){ xpa->nclient += 1; goto started; } /* support 2.2 (DATA) and 2.0,2.1 (BUF) */ else if( !strcmp(tbuf, "XPA$DATA") || !strcmp(tbuf, "XPA$BUF") ){ if( !strcmp(tbuf, "XPA$DATA") ){ dmode |= DATA_DATA; if( !word(lbuf, tbuf, &lp) ){ snprintf(errbuf, SZ_LINE, "XPA$WARNING: missing DATA request type\n%s", lbuf); goto error; } if( !strcmp(tbuf, "connect") ){ method = client->method; dmode |= DATA_CONNECT; } else if( !strcmp(tbuf, "accept") ){ method = client->method; dmode |= DATA_ACCEPT; } else{ snprintf(errbuf, SZ_LINE, "XPA$WARNING: invalid data connection request: %s (%s:%s)\n", tbuf, client->xclass, client->name); goto error; } } else if( !strcmp(tbuf, "XPA$BUF") ){ if( !word(lbuf, tbuf, &lp) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: missing data buffer method (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); goto error; } method = tbuf; dmode |= DATA_CONNECT; } /* handle connect-type requests */ if( dmode & DATA_CONNECT ){ switch(XPAMethod(method)){ case XPA_INET: XPAParseIpPort(method, &ip, &port); /* connect to the server before we go further */ if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); if( XPAVerbosity() ){ perror("XPA client socket"); } goto error; } setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); memset((char *)&sock_in, 0, sizeof(sock_in)); sock_in.sin_family = AF_INET; /* connect using the same ip we used for the command channel (i.e., could be localhost) */ sock_in.sin_addr.s_addr = htonl(client->ip); sock_in.sin_port = htons(port); FPRINTF((stderr, "%sXPAClientStart: attempting dchan connect: %s\n", _sp, method)); if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ PERROR(("dchan connect")); snprintf(errbuf, SZ_LINE, "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); if( XPAVerbosity() ){ perror("XPA client connect"); } xclose(fd); goto error; } break; #if HAVE_SYS_UN_H case XPA_UNIX: again: /* open a socket and fill in socket information */ if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); if( XPAVerbosity() ){ perror("XPA client socket"); } goto error; } setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)); memset((char *)&sock_un, 0, sizeof(sock_un)); sock_un.sun_family = AF_UNIX; strcpy(sock_un.sun_path, method); FPRINTF((stderr, "%sXPAClientStart: attempting dchan connect: %s\n", _sp, method)); if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) < 0 ){ PERROR(("dchan connect")); xclose(fd); if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ tries++; xclose(fd); XPASleep(10); goto again; } /* give up */ else{ snprintf(errbuf, SZ_LINE, "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); if( XPAVerbosity() ){ perror("XPA client connect"); } goto error; } } break; #endif default: snprintf(errbuf, SZ_LINE, "XPA$ERROR: unknown connection method (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); goto error; } } /* handle "doaccept" requests */ else if( dmode & DATA_ACCEPT ){ fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), client->xclass, client->name, client->cmdfd, NULL, NULL, tbuf2); if( fd < 0 ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: can't connect to proxy server (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); goto error; } else if( *tbuf2 ){ client->dataname = xstrdup(tbuf2); } } /* common code for either type of data connect request */ client->datafd = fd; /* make sure we close on exec */ xfcntl(client->datafd, F_SETFD, FD_CLOEXEC); /* for senders, set to no block mode */ if( client->type == 's' ){ /* save state and set in non-blocking mode */ xfcntl_nonblock(client->datafd, flags); } xpa->nclient += 1; goto started; } /* handle error message */ else if( !strcmp(tbuf, "XPA$ERROR") ){ snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); goto error; } /* everything else is an error */ else{ snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); goto error; } } else{ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server during handshake (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); goto error; } error: FPRINTF((stderr, "Error in XPAClientStart: %s", errbuf)); XPAClientFree(xpa, client); return(-1); started: /* it is necessary to add this this extra hack/ack between the authentication ack and the error return (both from the server) to avoid getting Nagle buffered. if we already did an accept, however, we already sent a message and need not repeat it */ if( !(dmode & DATA_ACCEPT) ){ FPRINTF((stderr, "%sXPAClientStart: %d sending nagle\n", _sp, client->cmdfd)); XPAPuts(NULL, client->cmdfd, "xpanagle\n", XPAShortTimeout()); } /* write a "data request" to the server on the data channel, supplying the arguments to allow the server to find the associated command */ if( dmode & DATA_DATA ){ if( !word(lbuf, tbuf, &lp) ) strcpy(tbuf, "?"); if( !word(lbuf, tbuf2, &lp) ) strcpy(tbuf2, "?"); snprintf(lbuf, SZ_LINE, "xpadata -f %s %s\n", tbuf, tbuf2); FPRINTF((stderr, "%sXPAClientStart: sending data channel %d request: %s", _sp, client->datafd, lbuf)); if( XPAPuts(NULL, client->datafd, lbuf, XPAShortTimeout()) <0 ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: unable to issue data request: %s (%s:%s%s)\n", lbuf, client->xclass, client->name, XPATimestamp()); FPRINTF((stderr, "%sXPAClientStart: error returned is %s", _sp, errbuf)); goto error; } } done: /* mark as active and started */ client->status = XPA_CLIENT_PROCESSING; return(0); } /* *---------------------------------------------------------------------------- * * * Public Routines * * *---------------------------------------------------------------------------- */ /* *--------------------------------------------------------------------------- * * Routine: XPAClientValid * * Purpose: see if the xpa client struct is valid * * Results: 1 on success, 0 for failure * *--------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAClientValid (XPA xpa) #else int XPAClientValid(xpa) XPA xpa; #endif { return(_XPAValid(xpaclienthead, xpa, "c")); } /* *---------------------------------------------------------------------------- * * Routine: XPAOpen * * Purpose: open a persistent XPA client connection * * Returns: XPA struct on success * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPA XPAOpen (char *mode) #else XPA XPAOpen(mode) char *mode; #endif { XPA xpa; /* allocate xpa struct */ if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) return(NULL); /* add version */ xpa->version = xstrdup(XPA_VERSION); /* mark this as a client struct */ xpa->type = xstrdup("c"); /* mark as persistent so we don't destroy at the end of the transfer */ xpa->persist = 1; /* add this xpa to end of list of client xpas */ XPAListAdd(&xpaclienthead, xpa); return(xpa); } /* *---------------------------------------------------------------------------- * * Routine: XPAClose * * Purpose: close a persistent XPA client connection * * Returns: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC void XPAClose (XPA xpa) #else void XPAClose(xpa) XPA xpa; #endif { XPAClient client, tclient; NS ns, tns; /* ignore struct if its not a client struct */ if( !XPAClientValid(xpa) ) return; /* remove from list of client xpas */ XPAListDel(&xpaclienthead, xpa); /* free each remaining client */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; XPAClientFree(xpa, client); client = tclient; } /* close down the name server and all of the remotes for this xpa */ for(ns=xpa->nshead; ns!=NULL; ){ tns = ns->next; XPANSClose(xpa, ns); ns = tns; } /* free string space */ if( xpa->version ) xfree(xpa->version); if( xpa->type ) xfree(xpa->type); if( xpa ) xfree(xpa); } /* *---------------------------------------------------------------------------- * * Routine: XPAGet * * Purpose: get XPA values * * Returns: 0 for success, -1 for failure * len bytes of data returned in buf * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAGet (XPA xpa, char *xtemplate, char *paramlist, char *mode, char **bufs, size_t *lens, char **names, char **messages, int n) #else int XPAGet(xpa, xtemplate, paramlist, mode, bufs, lens, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; char *mode; char **bufs; size_t *lens; char **names; char **messages; int n; #endif { int i; int oldmode=0; int xmode=0; int type='g'; int idef=1; int got=0; char tbuf[SZ_LINE]; XPAClient client, tclient; FPRINTF((stderr, "%sXPAGet: starting\n", _sp)); /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* these arrays are required */ if( (bufs == NULL) || (lens == NULL) ){ got = -1; goto done; } /* flag that we don't read from stdin */ xpa->ifd = -1; /* zero out the return buffers */ memset((char *)bufs, 0, ABS(n)*sizeof(char *)); memset((char *)lens, 0, ABS(n)*sizeof(size_t)); if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ /* retrieve data from n active clients */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ /* we fill buffers */ client->mode |= XPA_CLIENT_BUF; client->bufptr = &(bufs[got]); client->lenptr = &(lens[got]); if( names != NULL ) client->nameptr = &(names[got]); if( messages != NULL ) client->errptr = &(messages[got]); } else{ if( messages != NULL ) messages[got] = xstrdup(errbuf); } got++; } client = tclient; } /* if we have active clients */ if( got ){ #if HAVE_MINGW32==0 /* check for loop modes */ XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); /* dofork implies don't do xpa */ if( xmode & XPA_CLIENT_SEL_FORK ) idef = 0; XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); if( xmode & XPA_CLIENT_SEL_FORK ){ XPAClientLoopFork(xpa, xmode); } else{ /* enter the main loop and process */ XPAClientLoop(xpa, xmode); } #else XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); XPAClientLoop(xpa, xmode); #endif } } done: /* look for clients who timed out */ for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAGetFd * * Purpose: get XPA values * * Returns: 0 for success, -1 for failure * len bytes of data returned in buf * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAGetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, int *fds, char **names, char **messages, int n) #else int XPAGetFd(xpa, xtemplate, paramlist, mode, fds, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; int *fds; char *mode; char **names; char **messages; int n; #endif { int i; int oldmode=0; int xmode=0; int got=0; int type='g'; int idef=1; char tbuf[SZ_LINE]; XPAClient client, tclient; FPRINTF((stderr, "%sXPAGetFd: starting\n", _sp)); /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* flag that we don't read from stdin */ xpa->ifd = -1; /* zero out the return buffers */ if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) > 0 ){ /* retrieve data from n active clients */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ /* we write to an fd */ client->mode |= XPA_CLIENT_FD; /* negative value => one channel for all clients */ if( n < 0 ) client->fd = fds[0]; else client->fd = fds[got]; client->bufptr = (char **)xcalloc(1, sizeof(char *)); client->lenptr = (size_t *)xcalloc(1, sizeof(size_t)); if( names != NULL ) client->nameptr = &(names[got]); if( messages != NULL ) client->errptr = &(messages[got]); } else{ if( messages != NULL ) messages[got] = xstrdup(errbuf); } got++; } client = tclient; } /* if we have active clients */ if( got ){ #if HAVE_MINGW32==0 /* check for loop modes */ XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); /* dofork implies don't do xpa */ if( xmode & XPA_CLIENT_SEL_FORK ) idef = 0; XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); if( xmode & XPA_CLIENT_SEL_FORK ){ XPAClientLoopFork(xpa, xmode); } else{ /* enter the main loop and process */ XPAClientLoop(xpa, xmode); } #else XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); XPAClientLoop(xpa, xmode); #endif } } /* look for clients who timed out */ for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPASet * * Purpose: set XPA values * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASet (XPA xpa, char *xtemplate, char *paramlist, char *mode, char *buf, size_t len, char **names, char **messages, int n) #else int XPASet(xpa, xtemplate, paramlist, mode, buf, len, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; char *mode; char *buf; size_t len; char **names; char **messages; int n; #endif { int i; int oldmode=0; int xmode=0; int got=0; int type='s'; int idef=1; char tbuf[SZ_LINE]; XPAClient client, tclient; FPRINTF((stderr, "%sXPASet: starting\n", _sp)); /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* flag that we don't read from stdin */ xpa->ifd = -1; /* zero out the return buffers */ if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ /* retrieve data from n active clients */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ /* we fill buffers */ client->mode |= XPA_CLIENT_BUF; client->buf = buf; client->len = len; if( names != NULL ) client->nameptr = &(names[got]); if( messages != NULL ) client->errptr = &(messages[got]); } else{ if( messages != NULL ) messages[got] = xstrdup(errbuf); } got++; } client = tclient; } /* if we have active clients */ if( got ){ #if HAVE_MINGW32==0 /* check for loop modes */ XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); /* dofork implies don't do xpa */ if( xmode & XPA_CLIENT_SEL_FORK ) idef = 0; XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); if( xmode & XPA_CLIENT_SEL_FORK ){ XPAClientLoopFork(xpa, xmode); } else{ /* enter the main loop and process */ XPAClientLoop(xpa, xmode); } #else XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); XPAClientLoop(xpa, xmode); #endif } } /* look for clients who timed out */ for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPASetFd * * Purpose: set XPA values * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, int fd, char **names, char **messages, int n) #else int XPASetFd(xpa, xtemplate, paramlist, mode, fd, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; char *mode; int fd; char **names; char **messages; int n; #endif { int i; int oldmode=0; int xmode=0; int got=0; int got2=0; int type='s'; int idef=1; int flags; char *s; char tbuf[SZ_LINE]; XPAClient client, tclient; FPRINTF((stderr, "%sXPASetFd: starting\n", _sp)); /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* Set non-blocking mode for the input fd, if its not a tty */ xpa->ifd = fd; if( isatty(xpa->ifd) == 0 ){ /* save state and set in non-blocking mode */ xfcntl_nonblock(xpa->ifd, flags); } /* zero out the return buffers */ if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ /* open clients all at once */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ /* we fill buffers */ client->mode |= XPA_CLIENT_FD; if( names != NULL ) client->nameptr = &(names[got]); if( messages != NULL ) client->errptr = &(messages[got]); } else{ if( messages != NULL ) messages[got] = xstrdup(errbuf); } got++; } client = tclient; } /* if we have active clients */ if( got ){ /* if fd is null, user did not want to send data, just the paramlist */ if( fd < 0 ){ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotclienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* reset flags, if necessary */ if( xpa->ifd >=0 && (isatty(xpa->ifd) ==0) ){ xfcntl(xpa->ifd, F_SETFL, flags); } /* free all input structs */ XPAClientFreeAllInputs(xpa); /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAInfo * * Purpose: send XPA info * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAInfo (XPA xpa, char *xtemplate, char *paramlist, char *mode, char **names, char **messages, int n) #else int XPAInfo(xpa, xtemplate, paramlist, mode, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; char *mode; char **names; char **messages; int n; #endif { int i; int oldmode=0; int got=0; char type='i'; char *s; char tbuf[SZ_LINE]; XPAClient client, tclient; /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* flag that we don't read from stdin */ xpa->ifd = -1; /* zero out the return buffers */ if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ /* retrieve data from n active clients */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ XPAClientDataSent(xpa, client); s = XPAClientEnd(xpa, client); if( (messages != NULL) && (messages[got] == NULL) ) messages[got] = xstrdup(s); } else{ if( (messages != NULL) && (messages[got] == NULL) ) messages[got] = xstrdup(errbuf); } got++; } client = tclient; } } /* look for clients who timed out */ for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAAccess * * Purpose: determine if XPA access point is available * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAAccess (XPA xpa, char *xtemplate, char *paramlist, char *mode, char **names, char **messages, int n) #else int XPAAccess(xpa, xtemplate, paramlist, mode, names, messages, n) XPA xpa; char *xtemplate; char *paramlist; char *mode; char **names; char **messages; int n; #endif { int i; int oldmode=0; int xmode=0; int got=0; int type='a'; char *s; char *ind1, *ind2; char tbuf[SZ_LINE]; XPAClient client, tclient; /* if not persistent, we need a temp xpa struct; (also ignore passed struct if its not a client struct) */ if( (xpa == NULL) || strcmp(xpa->type, "c") ){ if( (xpa = XPAOpen(NULL)) == NULL ) return(-1); /* mark this as not persistent */ xpa->persist = 0; } /* save xpa mode -- this call might override */ else{ /* make sure we have a valid client handle */ if( !XPAClientValid(xpa) ){ if( XPAVerbosity() ){ fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); } return(-1); } oldmode = xpa->client_mode; } /* flag that we don't read from stdin */ xpa->ifd = -1; /* zero out the return buffers */ if( names != NULL ) memset((char *)names, 0, ABS(n)*sizeof(char *)); if( messages != NULL ) memset((char *)messages, 0, ABS(n)*sizeof(char *)); /* connect to clients and grab data */ if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ /* retrieve data from n active clients */ for(client=xpa->clienthead; client!=NULL; ){ tclient = client->next; if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (gotxclass, client->name, client->method); names[got] = xstrdup(tbuf); } if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ XPAClientDataSent(xpa, client); s = XPAClientEnd(xpa, client); if( (messages != NULL) && (messages[got] == NULL) ) messages[got] = xstrdup(s); } else{ if( (messages != NULL) && (messages[got] == NULL) ) messages[got] = xstrdup(errbuf); } /* might have to fix the name if was an explicit mach:port */ if( names && names[got] && *errbuf && !strncmp(names[got], "?:?", 3) && (ind1=strrchr(errbuf, '(')) && (ind2=strrchr(errbuf, ')')) ){ ind1++; strncpy(tbuf, ind1, ind2-ind1); tbuf[ind2-ind1] = '\0'; xfree(names[got]); names[got] = xstrdup(tbuf); } got++; } client = tclient; } /* if we have active clients */ if( got ){ /* check for loop modes */ XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, 1); /* enter the main loop and process */ XPAClientLoop(xpa, xmode); } } /* look for clients who timed out */ for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && (istatus == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ snprintf(errbuf, SZ_LINE, "XPA$ERROR: no response from server callback (%s:%s%s)\n", client->xclass, client->name, XPATimestamp()); messages[i] = xstrdup(errbuf); } } } /* remove this xpa if we are not meant to persist */ if( xpa && !xpa->persist ) XPAClose(xpa); /* restore xpa mode -- this call might override */ else xpa->client_mode = oldmode; /* return number of clients processes (including errors) */ return(got); } xpa-2.1.15/clipboard.c0000644000054000000360000001477612052464706013115 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * remote.c -- xpa access control list management * */ #include /* *---------------------------------------------------------------------------- * * * Private Routines * * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static XPAClip ClipBoardNew(XPA xpa, char *name) #else static XPAClip ClipBoardNew(xpa, name) XPA xpa; char *name; #endif { XPAClip cur, xnew; if( (xnew = (XPAClip)xcalloc(1, sizeof(XPAClipRec))) == NULL ) return(NULL); /* fill in record structure */ xnew->name = xstrdup(name); xnew->ip = xpa->comm->cmdip; /* add to the end of list */ if( xpa->cliphead == NULL ){ xpa->cliphead = xnew; } else{ for(cur=xpa->cliphead; cur->next!=NULL; cur=cur->next){ ; } cur->next = xnew; } return xnew; } #ifdef ANSI_FUNC static XPAClip ClipBoardLookup(XPA xpa, char *name) #else static XPAClip ClipBoardLookup(xpa, name) XPA xpa; char *name; #endif { XPAClip cur; /* look for reserved keywords that have callbacks */ for(cur=xpa->cliphead; cur!=NULL; cur=cur->next){ if( !strcmp(name, cur->name) && (xpa->comm->cmdip == cur->ip) ){ return(cur); } } return NULL; } #ifdef ANSI_FUNC static int ClipBoardAdd(XPA xpa, char *name, char *paramlist, char *buf) #else static int ClipBoardAdd(xpa, name, paramlist, buf) XPA xpa; char *name; char *paramlist; char *buf; #endif { XPAClip cur; if( !(cur = ClipBoardLookup(xpa, name)) ) cur = ClipBoardNew(xpa, name); if( !cur ) return -1; if( cur->value ) xfree(cur->value); cur->value = xstrdup(buf); return 0; } #ifdef ANSI_FUNC static int ClipBoardAppend(XPA xpa, char *name, char *paramlist, char *buf) #else static int ClipBoardAppend(xpa, name, paramlist, buf) XPA xpa; char *name; char *paramlist; char *buf; #endif { XPAClip cur; if( !(cur = ClipBoardLookup(xpa, name)) ) cur = ClipBoardNew(xpa, name); if( !cur ) return -1; if( cur->value ){ if( (cur->value = (char *)xrealloc(cur->value, strlen(cur->value)+strlen(buf)+1)) ) strcat(cur->value, buf); else return -1; } else{ cur->value = xstrdup(buf); } return 0; } #ifdef ANSI_FUNC static int ClipBoardDelete(XPA xpa, char *name, char *paramlist) #else static int ClipBoardDelete(xpa, name, paramlist) XPA xpa; char *name; char *paramlist; #endif { XPAClip cur; if( (cur = ClipBoardLookup(xpa, name)) ){ ClipBoardFree(xpa, cur); return 0; } else return -1; } /* *---------------------------------------------------------------------------- * * * Semi-Public Routines (used by xpa.c and command.c) * * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int ClipBoardFree(XPA xpa, XPAClip clip) #else int ClipBoardFree(xpa, clip) XPA xpa; XPAClip clip; #endif { XPAClip cur; if( !clip ) return 0; /* remove from list */ if( xpa->cliphead ){ if( xpa->cliphead == clip ){ xpa->cliphead = clip->next; } else{ for(cur=xpa->cliphead; cur!=NULL; cur=cur->next){ if( cur->next == clip ){ cur->next = clip->next; break; } } } } if( clip->name ) xfree(clip->name); if( clip->value ) xfree(clip->value); xfree(clip); return 1; } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveClipboard * * Purpose: add a new clipboard entry * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAReceiveClipboard (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int XPAReceiveClipboard(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 cmd[SZ_LINE]; char name[SZ_LINE]; char tbuf[SZ_LINE]; int lp=0; int status = -1; *cmd = '\0'; *name = '\0'; if( paramlist && *paramlist ){ if( !word(paramlist, cmd, &lp) || !word(paramlist, name, &lp) ) goto done; /* lookup the command */ if( !strcmp(cmd, "add") ){ status = ClipBoardAdd(xpa, name, ¶mlist[lp], buf); } else if( !strncmp(cmd, "app", 3) ){ status = ClipBoardAppend(xpa, name, ¶mlist[lp], buf); } else if( !strncmp(cmd, "del", 3) ){ status = ClipBoardDelete(xpa, name, ¶mlist[lp]); } #ifdef LATER else if( !strncmp(cmd, "loa", 3) ){ status = ClipBoardLoad(xpa, name, ¶mlist[lp], buf); } else if( !strncmp(cmd, "sav", 3) ){ status = ClipBoardSave(xpa, name, ¶mlist[lp]); } #endif } done: if( status < 0 ){ if( !*cmd || !*name ){ XPAError(xpa, "XPA clipboard requires: add|append|delete name\n"); } else{ snprintf(tbuf, SZ_LINE, "XPA clipboard invalid cmd or name: %s %s\n", cmd, name); XPAError(xpa, tbuf); } } return(status); } /* *---------------------------------------------------------------------------- * * Routine: XPASendClipboard * * Purpose: return clipboard information * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASendClipboard (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int XPASendClipboard(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 name[SZ_LINE]; char tbuf[SZ_LINE]; int lp=0; int status = -1; XPAClip cur; *name = '\0'; if( paramlist && *paramlist ){ if( !word(paramlist, name, &lp) ) goto done; if( !(cur = ClipBoardLookup(xpa, name)) ) goto done; if( cur->value ){ send(xpa_datafd(xpa), cur->value, strlen(cur->value), 0); status = 0; } } done: if( status < 0 ){ if( !*name ){ XPAError(xpa, "XPA clipboard requires: name\n"); } else{ snprintf(tbuf, SZ_LINE, "XPA clipboard invalid name: %s\n", name); XPAError(xpa, tbuf); } } return(status); } /* *---------------------------------------------------------------------------- * * * Public Routines * * *---------------------------------------------------------------------------- */ xpa-2.1.15/command.c0000644000054000000360000007324112052464442012561 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ #include /* *---------------------------------------------------------------------------- * * * Private Routines and Data * * *---------------------------------------------------------------------------- */ /* this is the static xpa struct that holds the reserved commands */ static XPA rxpa=NULL; /* *---------------------------------------------------------------------------- * * Routine: XPACmdParseNames * * Purpose: massage a name string, changing multiple sequential spaces * into a single space * * Returns: new name, with spaces massaged (also number of spacess) * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static char * XPACmdParseNames(char *lbuf, int *ntokens) #else static char *XPACmdParseNames(lbuf, ntokens) char *lbuf; int *ntokens; #endif { char tbuf[SZ_LINE]; int lp=0; char *buf; /* can't be larger than the original string */ buf = (char *)xmalloc(strlen(lbuf)+1); *buf = '\0'; *ntokens = 0; /* pick off each word, separating by a single space */ while( word(lbuf, tbuf, &lp)){ if( *buf != '\0' ) strcat(buf, " "); strcat(buf, tbuf); *ntokens += 1; } /* make the string the right size */ buf = (char *)xrealloc(buf, strlen(buf)+1); return(buf); } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveNSConnect * * Purpose: reset and re-establish connection to name server * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAReceiveNSConnect (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else static int XPAReceiveNSConnect(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; XPA txpa; char tbuf[SZ_LINE]; int doall=0; int lp=0; if( paramlist && *paramlist ){ if( word(paramlist, tbuf, &lp) && !strcmp(tbuf, "-all") ){ doall = 1; } } if( doall ){ for(txpa=XPAListHead(); txpa!=NULL; txpa=txpa->next){ XPANSAdd(txpa, NULL, NULL); } } else{ XPANSAdd(xpa, NULL, NULL); } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveNSDisconnect * * Purpose: break connection to name server * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAReceiveNSDisconnect (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else static int XPAReceiveNSDisconnect(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; XPA txpa; NS ns, tns; char tbuf[SZ_LINE]; int doall=0; int lp=0; if( paramlist && *paramlist ){ if( word(paramlist, tbuf, &lp) && !strcmp(tbuf, "-all") ){ doall = 1; } } if( doall ){ for(txpa=XPAListHead(); txpa!=NULL; txpa=txpa->next){ for(ns=txpa->nshead; ns!= NULL; ){ tns = ns->next; XPANSClose(txpa, ns); ns = tns; } } } else{ for(ns=xpa->nshead; ns!= NULL; ){ tns = ns->next; XPANSClose(xpa, ns); ns = tns; } } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveEnv * * Purpose: set an environment variable * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAReceiveEnv (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else static int XPAReceiveEnv(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 name[SZ_LINE]; char value[SZ_LINE]; char *tbuf; int lp=0; if( word(paramlist, name, &lp) ){ if( word(paramlist, value, &lp) ){ tbuf = (char *)xmalloc(strlen(name)+1+strlen(value)+1); snprintf(tbuf, SZ_LINE, "%s=%s", name, value); putenv(tbuf); return(0); } else{ if( strchr(name, '=') != NULL ){ tbuf = xstrdup(name); putenv(tbuf); return(0); } else{ XPAError(xpa, "XPA setenv requires name and value pair\n"); return(-1); } } } else{ XPAError(xpa, "XPA setenv requires name and value pair\n"); return(-1); } } /* *---------------------------------------------------------------------------- * * Routine: XPASendEnv * * Purpose: return an environment variable to client * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPASendEnv (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else static int XPASendEnv(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char **buf; size_t *len; #endif { int tlen; char *tbuf; char *ebuf; if( (ebuf = (char *)getenv(paramlist)) != NULL ){ tlen = strlen(ebuf)+2; tbuf = (char *)xmalloc(tlen); snprintf(tbuf, tlen, "%s\n", ebuf); *buf = tbuf; *len = strlen(tbuf); } else{ *buf = xstrdup("\n"); *len = 1; } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveReserved * * Purpose: execute reserved command * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAReceiveReserved (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else static int XPAReceiveReserved(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char *buf; size_t len; #endif { char *cmd = (char *)client_data; XPA xpa = (XPA)call_data; if( !strcmp(cmd, "end") ){ xpa->comm->status |= XPA_STATUS_ENDBUF; return(0); } else if( !strcmp(cmd, "exec") ){ xpa->comm->status |= XPA_STATUS_READBUF; return(0); } else{ return(-1); } } /* *---------------------------------------------------------------------------- * * Routine: XPASendHelp * * Purpose: send help strings * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPASendHelp (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else static int XPASendHelp(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; XPACmd cmd; int lp=0; int slen; char tbuf[SZ_LINE]; char lbuf[SZ_LINE]; char *sbuf; if( !paramlist || !*paramlist ){ if( xpa->version != NULL ){ snprintf(lbuf, SZ_LINE, "XPA version: %s\n", xpa->version); send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); } } if( xpa->commands == NULL ){ if( xpa->help != NULL ){ slen = strlen(xpa->help)+SZ_LINE; sbuf = (char *)xmalloc(slen); snprintf(sbuf, slen, "%s\n", xpa->help); send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); xfree(sbuf); } else{ strcpy(lbuf, "\n"); send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); } } else{ if( paramlist && *paramlist ){ while( word(paramlist, tbuf, &lp) ){ for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ if( !strcmp(tbuf, cmd->name) ){ if( cmd->help != NULL ){ slen = strlen(cmd->name)+strlen(cmd->help)+SZ_LINE; sbuf = (char *)xmalloc(slen); snprintf(sbuf, slen, "%s:\t%s\n", cmd->name, cmd->help); send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); xfree(sbuf); } else{ snprintf(lbuf, SZ_LINE, "%s:\t(no help available)\n", cmd->name); send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); } } } } } else{ for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ if( cmd->help != NULL ){ slen = strlen(cmd->name)+strlen(cmd->help)+SZ_LINE; sbuf = (char *)xmalloc(slen); snprintf(sbuf, slen, "%s:\t%s\n", cmd->name, cmd->help); send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); xfree(sbuf); } else{ snprintf(lbuf, SZ_LINE, "%s:\t(no help available)\n", cmd->name); send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); } } } } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPASendVersion * * Purpose: send XPA version string * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPASendVersion (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else static int XPASendVersion(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 lbuf[SZ_LINE]; if( xpa->version != NULL ) snprintf(lbuf, SZ_LINE, "%s\n", xpa->version); else strcpy(lbuf, "\n"); send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); return(0); } /* *---------------------------------------------------------------------------- * * * Semi-Public Routines and Data * * These routines are used by XPAHandler and XPANew * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPAInitReserved * * Purpose: add the reserved commands to the reserved xpa struct * * Results: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC void XPAInitReserved (void) #else void XPAInitReserved() #endif { if( !rxpa ){ if( (rxpa = (XPA)xcalloc(1, sizeof(struct xparec))) == NULL ) return; /* XPACmdAdd requires that the callbacks be defined explicitly in rxpa */ rxpa->send_callback = XPASendCommands; rxpa->receive_callback = XPAReceiveCommands; /* add reserved commands */ XPACmdAdd(rxpa, "-acl", "\tget (set) the access control list\n\t\t options: host type acl", XPASendAcl, NULL, NULL, XPAReceiveAcl, NULL, "fillbuf=false"); XPACmdAdd(rxpa, "-env", "\tget (set) an environment variable\n\t\t options: name (value)", XPASendEnv, NULL, NULL, XPAReceiveEnv, NULL, NULL); XPACmdAdd(rxpa, "-exec", "\texecute commands from buffer\n\t\t options: none", NULL, NULL, NULL, XPAReceiveReserved, (void *)"exec", NULL); XPACmdAdd(rxpa, "-help", "\treturn help string for specified XPA\n\t\t options: cmd name (commands only)", XPASendHelp, NULL, NULL, NULL, NULL, NULL); XPACmdAdd(rxpa, "-ltimeout", "\tget (set) long timeout\n\t\t options: seconds|reset", XPASendLTimeout, NULL, NULL, XPAReceiveLTimeout, NULL, NULL); XPACmdAdd(rxpa, "-nsconnect", "\tre-establish name server connection to this XPA\n\t\t options: -all", NULL, NULL, NULL, XPAReceiveNSConnect, NULL, NULL); XPACmdAdd(rxpa, "-nsdisconnect", "\tbreak name server connection to this XPA\n\t\t options: -all", NULL, NULL, NULL, XPAReceiveNSDisconnect, NULL, NULL); XPACmdAdd(rxpa, "-remote", "\tconnect to remote name service with specified acl \n\t\t options: host:port +|-|acl -proxy", XPASendRemote, NULL, NULL, XPAReceiveRemote, NULL, "fillbuf=false"); XPACmdAdd(rxpa, "-clipboard", "\tset/get clipboard information \n\t\t options: [cmd] name", XPASendClipboard, NULL, NULL, XPAReceiveClipboard, NULL, NULL); XPACmdAdd(rxpa, "-stimeout", "\tget (set) short timeout\n\t\t options: seconds|reset", XPASendSTimeout, NULL, NULL, XPAReceiveSTimeout, NULL, NULL); XPACmdAdd(rxpa, "-version", "\treturn XPA version string\n\t\t options: none", XPASendVersion, NULL, NULL, NULL, NULL, NULL); } } #ifdef ANSI_FUNC void XPAFreeReserved (void) #else void XPAFreeReserved() #endif { XPACmd cmd, tcmd; if( !rxpa ) return; /* free reserved commands */ for(cmd=rxpa->commands; cmd!=NULL; ){ tcmd = cmd->next; XPACmdDel(rxpa, cmd); cmd = tcmd; } xfree(rxpa); rxpa = NULL; } /* *---------------------------------------------------------------------------- * * Routine: XPACmdLookupReserved * * Purpose: lookup a reserved command name * * Results: cmd struct or null * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPACmd XPACmdLookupReserved (XPA xpa, char *lbuf, int *lp) #else XPACmd XPACmdLookupReserved(xpa, lbuf, lp) XPA xpa; char *lbuf; int *lp; #endif { XPACmd cmd; int lp2=0; char *lptr; char name[SZ_LINE]; /* make sure we have something to work with */ if( (rxpa==NULL) || (lbuf==NULL) || (lbuf[*lp]=='\0') ) return(NULL); /* this is where we start parsing */ lptr = &(lbuf[*lp]); /* to simplify life, we assume reserved words are 1 token */ if( !word(lptr, name, &lp2) ) return(NULL); /* look for reserved keywords that have callbacks */ for(cmd=rxpa->commands; cmd!=NULL; cmd=cmd->next){ if( !strcmp(name, cmd->name) ){ *lp += lp2; return(cmd); } } /* nothing, nowhere */ return(NULL); } /* *---------------------------------------------------------------------------- * * Routine: XPACmdLookup * * Purpose: lookup a user-defined command name * * Results: cmd struct or null * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPACmd XPACmdLookup (XPA xpa, char *lbuf, int *lp) #else XPACmd XPACmdLookup(xpa, lbuf, lp) XPA xpa; char *lbuf; int *lp; #endif { XPACmd cmd; int i; int lp2; int len, tlen; char *lptr; char tbuf[SZ_LINE]; char name[SZ_LINE]; /* make sure we have something to work with */ if( (xpa==NULL) || (lbuf==NULL) || (lbuf[*lp]=='\0') ) return(NULL); /* this is where we start parsing */ lptr = &(lbuf[*lp]); /* look up commands for this name */ for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ /* make up a name with the required number of tokens for this command */ *name = '\0'; lp2 = 0; tlen = 0; for(i=0; intokens; i++){ if( word(lptr, tbuf, &lp2)){ len = strlen(tbuf)+1; if( (tlen+len) <= (SZ_LINE-1) ){ if( *name != '\0' ) strcat(name, " "); strcat(name, tbuf); tlen += len; } /* not enough room */ else{ *name = '\0'; break; } } } /* we now have the name, see if its what we want */ if( *name && !strcmp(cmd->name, name) ){ *lp += lp2; return(cmd); } } /* did not find the command in this xpa -- now look through reserved */ return(XPACmdLookupReserved(xpa, lbuf, lp)); } /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveCommands * * Purpose: process a list of commands from xpaset * * Results: number of commands processed * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAReceiveCommands (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int XPAReceiveCommands(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; XPACmd cmd; int lp; int savelp; int plen; int bgot; int got=0; int gotbuf=0; int freebuf=1; char lbuf[SZ_LINE]; char tbuf[SZ_LINE]; char tbuf1[SZ_LINE]; /* use ";" as a command separator (as well as \n) */ newdtable(";"); /* if we already have buf, there will be no need to get it */ if( buf ) gotbuf++; /* if we have no paramlist, we read from the socket */ if( (xpa_datafd(xpa) >=0) && (!paramlist || (*paramlist == '\0')) ){ xpa->comm->status |= XPA_STATUS_READBUF; XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPALongTimeout()); FPRINTF((stderr, "%sXPAReceiveCommands: read %s\n", _sp, lbuf)); } else{ xpa->comm->status &= ~XPA_STATUS_READBUF; nowhite(paramlist, lbuf); } /* we must have something to start with */ if( *lbuf == '\0' ){ XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD2]); got = -1; goto done; } /* This look either executes the one set of commands in paramlist, or reads one line at a time from the socket and executes commands. In the latter case, each callback can read the socket as well */ while( 1 ){ FPRINTF((stderr, "%sXPAReceiveCommands: top of loop: %s\n", _sp, lbuf)); lp = 0; while( lbuf[lp] != '\0' ){ if( (cmd = XPACmdLookup(xpa, lbuf, &lp)) == NULL ){ XPAError(xpa, xpaMessbuf[XPA_RTN_UNCMD]); got = -1; goto done; } /* reserved commands can only be called from the same host as the server, or from local (unix) sockets */ if( (cmd->xpa == rxpa) && strcmp(cmd->name, "-help") && strcmp(cmd->name, "-version") ){ if( XPAMtype() == XPA_INET ){ if( (!xpa->comm || !LOCALIP(xpa->comm->cmdip)) ){ FPRINTF((stderr, "%sXPAReceiveCommands: rejecting reserved: %s\n", _sp, cmd->name)); XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); got = -1; goto done; } } } FPRINTF((stderr, "%sXPAReceiveCommands: cmd->name: %s\n", _sp, cmd->name)); *tbuf = '\0'; if( (lastdelim() != ';') && (lastdelim() != '\n') ){ /* skip white space between command and params */ while( isspace((int)lbuf[lp]) ) lp++; /* here is where the params start */ savelp = lp; /* look for command delimiter -- the end of the params */ while( word(lbuf, tbuf1, &lp) ){ if( (lastdelim() == ';') || (lastdelim() == '\n') ){ break; } /* make sure a command-ending delim is not next */ while( isspace((int)lbuf[lp]) ) lp++; if( (lbuf[lp] == ';') || (lbuf[lp] == '\n') ){ break; } } /* get length of parameter list */ plen = lp - savelp; /* but skip final delim */ if( (plen>0) && ((lastdelim() == ';')||(lastdelim() == '\n')) ) plen--; /* copy the params up to the command delimiter */ if( plen > 0 ){ strncpy(tbuf, &(lbuf[savelp]), plen); tbuf[plen] = '\0'; } } /* execute the associated XPA callback */ if( cmd->receive_callback != NULL ){ /* get buf now, if its needed */ if( !gotbuf && (xpa_datafd(xpa) >= 0) && (cmd->receive_mode & XPA_MODE_FILLBUF) ){ /* read buf -- this buf will stay around for all commands */ FPRINTF((stderr, "%sXPAReceiveCommands: at XPAGetBuf\n", _sp)); bgot = XPAGetBuf(xpa, xpa_datafd(xpa), &buf, &len, -1); /* close the data channel */ XPACloseData(xpa, xpa->comm); if( bgot >= 0 ){ /* got the buffer */ gotbuf++; } /* error getting buf */ else{ XPAError(xpa, xpaMessbuf[XPA_RTN_NODATA]); got = -1; goto done; } } got = (cmd->receive_callback)(cmd->receive_data, call_data, tbuf, buf, len); /* if we don't want to free the buffer, mark it for saving */ if( (buf != NULL) && !(cmd->receive_mode & XPA_MODE_FREEBUF) ){ freebuf=0; } if( got != 0 ){ goto done; } } else{ XPAError(xpa, xpaMessbuf[XPA_RTN_NOREC]); got = -1; goto done; } } /* conditions for exiting the command loop: */ /* if we processed the END command, we are done */ if( xpa->comm->status & XPA_STATUS_ENDBUF ) break; /* if we are not reading the data buffer, we are done */ if( !(xpa->comm->status & XPA_STATUS_READBUF) ) break; /* if we got EOF or error reading the data buffer, we are done */ if( XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPALongTimeout()) <=0 ) break; } done: /* if no one wants buf, free it now */ if( freebuf ) xfree(buf); /* restore last delimiter table */ freedtable(); /* return error code */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPASendCommands * * Purpose: process a list of commands from xpaget * * Results: number of commands processed (currently 0 or 1) * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASendCommands (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int XPASendCommands(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; XPACmd cmd; char tbuf[SZ_LINE]; int lp=0; int got=0; /* return help as default */ if( *paramlist == '\0' ){ paramlist = "-help"; } /* lookup the command and execute */ if( (cmd = XPACmdLookup(xpa, paramlist, &lp)) != NULL ){ /* reserved commands can only be called from the same host as the server, or from local (unix) sockets */ if( (cmd->xpa == rxpa) && strcmp(cmd->name, "-help") && strcmp(cmd->name, "-version") ){ if( XPAMtype() == XPA_INET ){ if( (!xpa->comm || !LOCALIP(xpa->comm->cmdip)) ){ FPRINTF((stderr, "%sXPAReceiveCommands: rejecting reserved: %s\n", _sp, cmd->name)); XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); got = -1; goto done; } } } /* execute the associated XPA send callback, using the remaining command string as an argument */ strcpy(tbuf, ¶mlist[lp]); nocr(tbuf); if( !strcmp(tbuf, "-help") ){ if( cmd->help != NULL ) snprintf(tbuf, SZ_LINE, "%s\n", cmd->help); else snprintf(tbuf, SZ_LINE, "\n"); send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); got = 0; } else if( cmd->send_callback != NULL ){ got = (cmd->send_callback)(cmd->send_data, call_data, ¶mlist[lp], buf, len); } else{ XPAError(xpa, xpaMessbuf[XPA_RTN_NOSEND]); got = -1; goto done; } } else{ XPAError(xpa, xpaMessbuf[XPA_RTN_UNCMD]); got = -1; goto done; } done: /* return error code */ return(got); } /* *---------------------------------------------------------------------------- * * * Public Routines and Data * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPACmdNew * * Purpose: define a named command access point * * Results: XPA struct or NULL * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPA XPACmdNew (char *xclass, char *name) #else XPA XPACmdNew(xclass, name) char *xclass; char *name; #endif { XPA xpa; char tbuf[SZ_LINE]; /* we need a name */ if( (name == NULL) || (*name == '\0') ) return(NULL); /* we need some valid class */ if( (xclass == NULL) || (*xclass == '\0') ) xclass = "*"; /* help string */ snprintf(tbuf, SZ_LINE, "XPA commands for %s:%s\n\t\t options: see -help", xclass, name); /* create a new XPA with command callbacks */ xpa = XPANew(xclass, name, tbuf, XPASendCommands, NULL, NULL, XPAReceiveCommands, NULL, "fillbuf=false"); /* return the good news */ return(xpa); } /* *---------------------------------------------------------------------------- * * Routine: XPACmdAdd * * Purpose: add a command to a named command access point * * Results: 0 on success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPACmd XPACmdAdd (XPA xpa, char *name, char *help, SendCb send_callback, void *send_data, char *send_mode, ReceiveCb rec_callback, void *rec_data, char *rec_mode) #else XPACmd XPACmdAdd(xpa, name, help, send_callback, send_data, send_mode, rec_callback, rec_data, rec_mode) XPA xpa; char *name; char *help; SendCb send_callback; void *send_data; char *send_mode; ReceiveCb rec_callback; void *rec_data; char *rec_mode; #endif { XPACmd xnew; XPACmd cur; XPACmd prev; /* make sure we have a valid command record */ if( !xpa || (xpa->send_callback != XPASendCommands) || (xpa->receive_callback != XPAReceiveCommands) ){ return(NULL); } /* we need either a send or a receive or both */ if( (send_callback == NULL) && (rec_callback == NULL ) ){ return(NULL); } /* limit the size of the cmd name designation */ if( strlen(name) > XPA_NAMELEN ){ return(NULL); } /* allocate space for a new record */ xnew = (XPACmd)xcalloc(1, sizeof(struct xpacmdrec)); /* backlink to xpa */ xnew->xpa = xpa; /* fill in the blanks */ xnew->name = XPACmdParseNames(name, &(xnew->ntokens)); xnew->help = xstrdup(help); /* receive callback */ xnew->send_callback = send_callback; xnew->send_data = send_data; xnew->send_mode = XPA_DEF_MODE_SEND; XPAMode(send_mode, &(xnew->send_mode), "freebuf", XPA_MODE_FREEBUF,1); /* acl is a global mode */ XPAMode(send_mode, &(xpa->send_mode), "acl", XPA_MODE_ACL, 1); /* receive callback */ xnew->receive_callback = rec_callback; xnew->receive_data = rec_data; /* process the mode string */ xnew->receive_mode = XPA_DEF_MODE_REC; XPAMode(rec_mode, &(xnew->receive_mode), "usebuf", XPA_MODE_BUF,1); XPAMode(rec_mode, &(xnew->receive_mode), "fillbuf", XPA_MODE_FILLBUF,1); XPAMode(rec_mode, &(xnew->receive_mode), "freebuf", XPA_MODE_FREEBUF,1); /* acl is a global mode */ XPAMode(rec_mode, &(xpa->receive_mode), "acl", XPA_MODE_ACL, 1); /* enter into list, in alphabetical order */ if( xpa->commands == NULL ){ xpa->commands = xnew; return(xnew); } else{ for(prev=NULL, cur=xpa->commands; cur!=NULL; prev=cur, cur=cur->next){ /* if new name is an existing name, add it before */ if( strcmp(xnew->name, cur->name) ==0 ) goto addname; /* if existing name is a subset of new name, add it before */ else if( !strncmp(xnew->name, cur->name, strlen(cur->name)) ) goto addname; /* if new name is a subset of existing name, add it after */ else if( !strncmp(xnew->name, cur->name, strlen(xnew->name)) ) continue; /* if new name is lexically greater than existing name, add it after */ else if( strcmp(xnew->name, cur->name) >0 ) continue; addname: /* add the new name here and return */ if( prev == NULL ){ xpa->commands = xnew; xnew->next = cur; return(xnew); } else{ prev->next = xnew; xnew->next = cur; return(xnew); } } /* if we are still here, we did not find a place to insert, i.e., we are at the end of the list */ prev->next = xnew; return(xnew); } } /* *---------------------------------------------------------------------------- * * Routine: XPACmdDel * * Purpose: free a named command access point * * Results: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPACmdDel (XPA xpa, XPACmd cmd) #else int XPACmdDel(xpa, cmd) XPA xpa; XPACmd cmd; #endif { XPACmd cur; int got=0; /* gotta have something to free */ if( cmd == NULL ) return(-1); /* remove from list of xpa's commands */ if( xpa && xpa->commands ){ if( xpa->commands == cmd ){ xpa->commands = cmd->next; got++; } else{ for(cur=xpa->commands; cur!=NULL; cur=cur->next){ if( cur->next == cmd ){ cur->next = cmd->next; got++; break; } } } } /* free up space */ if( got ){ if( cmd->name ) xfree(cmd->name); if( cmd->help ) xfree(cmd->help); xfree(cmd); return(0); } else{ return(-1); } } /* *---------------------------------------------------------------------------- * * Routine: XPACmdInternalReceive * * Purpose: internal execute of the receive callback for this command * * Results: number of commands processed * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPACmdInternalReceive (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int XPACmdInternalReceive(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; /* make sure we have something */ if( xpa == NULL ) return(-1); /* make the call */ return(XPAReceiveCommands(client_data, xpa, paramlist, buf, len)); } /* *---------------------------------------------------------------------------- * * Routine: XPACmdInternalSend * * Purpose: internal execute of the send callback for this command * * Results: number of commands processed (currently 0 or 1) * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPACmdInternalSend (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int XPACmdInternalSend(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; /* make sure we have something */ if( xpa == NULL ) return(-1); /* make the call */ return(XPASendCommands(client_data, xpa, paramlist, buf, len)); } /* *---------------------------------------------------------------------------- * * Routine: XPAGetReserved * * Purpose: return xpa handle for reserved xpa commands * * Return: xpa handle * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC XPA XPAGetReserved (void) #else XPA XPAGetReserved() #endif { return(rxpa); } xpa-2.1.15/conf.h0000644000054000000360000000377112173263307012077 0ustar erichead/* conf.h. Generated from conf.h.in by configure. */ /* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* Define as 1 if you have string.h */ #define HAVE_STRING_H 1 /* Define as 1 if you have stdlib.h */ #define HAVE_STDLIB_H 1 /* Define as 1 if you have malloc.h */ #define HAVE_MALLOC_H 1 /* Define as 1 if you have unistd.h */ #define HAVE_UNISTD_H 1 /* Define as 1 if you have getopt.h */ #define HAVE_GETOPT_H 1 /* Define as 1 if you have pwd.h */ #define HAVE_PWD_H 1 /* Define as 1 if you have values.h */ #define HAVE_VALUES_H 1 /* Define as 1 if you have dlfcn.h */ #define HAVE_DLFCN_H 1 /* Define as 1 if you have sys/un.h */ #define HAVE_SYS_UN_H 1 /* Define as 1 if you have sys/shm.h */ #define HAVE_SYS_SHM_H 1 /* Define as 1 if you have sys/mman.h */ #define HAVE_SYS_MMAN_H 1 /* Define as 1 if you have sys/ipc.h */ #define HAVE_SYS_IPC_H 1 /* Define as 1 if you have setjmp.h */ #define HAVE_SETJMP_H 1 /* Define as 1 if you have socklen_t */ #define HAVE_SOCKLEN_T 1 /* Define as 1 if you have strchr */ #define HAVE_STRCHR 1 /* Define as 1 if you have memcpy */ #define HAVE_MEMCPY 1 /* Define as 1 if you have snprintf */ #define HAVE_SNPRINTF 1 /* Define as 1 if you have setenv */ #define HAVE_SETENV 1 /* Define as 1 if you have posix_spawn */ /* #undef HAVE_POSIX_SPAWN */ /* Define as 1 if you have crt_externs.h */ /* #undef HAVE_CRT_EXTERNS_H */ /* Define as 1 if you have NSGetEvniron */ /* #undef HAVE__NSGETENVIRON */ /* Define as 1 if you have atexit */ #define HAVE_ATEXIT 1 /* Define as 1 if you have pthread library */ /* #undef HAVE_LIBPTHREAD */ /* Define as 1 if you need reentrant errno, etc. */ /* #undef _REENTRANT */ /* Define as 1 if you have Tcl */ /* #undef HAVE_TCL */ /* Define as 1 if you have Xt */ #define HAVE_XT 1 /* Define as 1 if you have Gtk */ /* #undef HAVE_GTK */ /* Define as 1 if you are running Cygwin. */ /* #undef HAVE_CYGWIN */ /* Define as 1 if you are running MinGW. */ /* #undef HAVE_MINGW32 */ xpa-2.1.15/ctest.c0000644000054000000360000003552112151275600012260 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * ctest -- client test for xpa * */ #include extern char *optarg; extern int optind; int quiet=0; int dowait=0; int n=0; int don=0; int save_bytes=-1; int exitonerror=0; char *save_buf=NULL; char *mode=""; char name[SZ_LINE]; #define MAX_FPS 4 #ifdef ANSI_FUNC int send_cb (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int send_cb(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char **buf; size_t *len; #endif { char *s = (char *)client_data; XPA xpa = (XPA)call_data; char tbuf[SZ_LINE]; int sendbuf=0; /* introduce ourselves */ if( !quiet ){ fprintf(stdout, "SEND_CB #%d: %s:%s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), s); } /* process special paramlist tokens */ if( paramlist && *paramlist ){ if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); if( !strncmp(paramlist, "buf", 3) ){ sendbuf=1; } else if( !strncmp(paramlist, "error", 5) ){ if( !quiet ) fprintf(stdout, "\treturning error: %s\n", ¶mlist[6]); *len = 0; *buf = NULL; XPAError(xpa, ¶mlist[6]); return(-1); } else if( !strcmp(paramlist, "exit") ){ if( !quiet ) fprintf(stdout, "Exiting\n"); exit(0); } else if( !strcmp(paramlist, "wait") ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } } else if( dowait ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } /* return information about this xpa */ if( !sendbuf ){ snprintf(tbuf, SZ_LINE, "nclass: %s\nname: %s\nmethod: %s\nsendian: %s\ncendian: %s\n", xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), xpa_sendian(xpa), xpa_cendian(xpa)); if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); *len = 0; *buf = NULL; if( !quiet) fprintf(stdout, "\tcallback writes %d bytes to client\n", (int)strlen(tbuf)); } /* return the buffer and let xpa transmit it */ else{ *len = strlen(tbuf); *buf = (char *)xmalloc(*len); memcpy(*buf, tbuf, *len); if( !quiet) fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", (int)strlen(tbuf)); } } /* return the last buffer we were sent */ else{ if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ send(xpa_datafd(xpa), save_buf, save_bytes, 0); *len = 0; *buf = NULL; if( !quiet) fprintf(stdout, "\tcallback writes %d bytes to client\n", save_bytes); } /* return the buffer and let xpa transmit it */ else{ *len = save_bytes; *buf = (char *)xmalloc(*len); memcpy(*buf, save_buf, *len); if( !quiet) fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", save_bytes); } } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int receive_cb (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int receive_cb(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 *s = (char *)client_data; char tbuf[SZ_LINE]; char *errs[1]; int i; int ip; int got; int xwait; if( !quiet ){ fprintf(stdout, "RECEIVE_CB #%d: %s:%s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), s); } if( !quiet ){ fprintf(stdout, "\tbuf: %lu bytes\n", (unsigned long)len); } /* process param list */ if( paramlist && *paramlist ){ if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); if( !strcmp(paramlist, "free") ){ if( !quiet ) fprintf(stdout, "Freeing xpa struct\n"); XPAFree(xpa); return(0); } else if( !strncmp(paramlist, "error", 5) ){ if( !quiet ) fprintf(stdout, "Processing error: %s\n", ¶mlist[6]); XPAError(xpa, ¶mlist[6]); return(-1); } else if( !strcmp(paramlist, "exit") ){ if( !quiet ) fprintf(stdout, "Exiting\n"); exit(0); } else if( !strcmp(paramlist, "wait") ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } else if( !strncmp(paramlist, "xpaset", 6) ){ ip = 0; word(paramlist, tbuf, &ip); if( word(paramlist, tbuf, &ip) ){ if( !quiet ) fprintf(stdout, "calling XPASet(%s, \"%s\")\n", tbuf, &(paramlist[ip])); got = XPASet(NULL, tbuf, &(paramlist[ip]), mode, paramlist, strlen(paramlist), NULL, errs, 1); if( got == 0 ){ if( !quiet ) fprintf(stdout, "no XPA access points matched template %s\n", tbuf); } else if( errs[0] != NULL ){ if( !quiet ) fprintf(stdout, "Error on xpaset to %s: %s\n", tbuf, errs[0]); xfree(errs[0]); if( exitonerror ) exit(1); } else{ if( !quiet ) fprintf(stdout, "XPASet to %s successful\n", tbuf); } } return(0); } } else if( dowait ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } /* reset save buffer */ if( save_buf != NULL ){ xfree(save_buf); save_buf = NULL; } save_bytes = 0; xwait = dowait; if( !(xpa->receive_mode & XPA_MODE_FILLBUF) ){ while( (got=recv(xpa_datafd(xpa), tbuf, SZ_LINE, 0)) >0 ){ if( xwait >0 ){ fprintf(stdout, "got %d bytes ... press to continue ...", got); fgets(tbuf, SZ_LINE, stdin); xwait--; } i = save_bytes; save_bytes += got; if( save_buf == NULL ) save_buf = (char *)xmalloc(save_bytes); else save_buf = (char *)xrealloc(save_buf, save_bytes); memcpy(&save_buf[i], tbuf, got); } if( !quiet ) fprintf(stdout, "callback read %d bytes\n", save_bytes); } else{ save_bytes = len; save_buf = (char *)xmalloc(len); memcpy(save_buf, buf, len); } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int info_cb (void *client_data, void *call_data, char *paramlist) #else int info_cb(client_data, call_data, paramlist) void *client_data; void *call_data; char *paramlist; #endif { XPA xpa = (XPA)call_data; char *s = (char *)client_data; char xtemplate[SZ_LINE]; char *names[MAX_FPS]; char *bufs[MAX_FPS]; char *errs[MAX_FPS]; size_t lens[MAX_FPS]; int i; int ip; int got; if( !quiet ){ fprintf(stdout, "INFO_CB #%d: %s:%s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), s); } if( paramlist && *paramlist ){ if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); ip = 0; word(paramlist, xtemplate, &ip); if( !strcmp(xtemplate, "xpaget") ){ word(paramlist, xtemplate, &ip); got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, bufs, lens, names, errs, MAX_FPS); if( !quiet ) fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); for(i=0; i 0 ){ fprintf(stdout, "contents (%lu bytes):\n", (unsigned long)lens[i]); write(fileno(stdout), bufs[i], lens[i]); } if( !quiet ) fprintf(stdout, "\n"); } else{ write(fileno(stdout), errs[i], strlen(errs[i])); if( exitonerror ) exit(1); } if( bufs[i] ) xfree(bufs[i]); if( names[i] ) xfree(names[i]); if( errs[i] ) xfree(errs[i]); } } } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int main (int argc, char **argv) #else int main(argc, argv) int argc; char **argv; #endif { char *plist=NULL; char *paramlist=NULL; char *xtemplate="*:*"; char *smode=NULL; char tbuf[SZ_LINE]; char name[SZ_LINE]; char cmd[SZ_LINE]; char fxpa[SZ_LINE]; char *names[MAX_FPS]; char *bufs[MAX_FPS]; char *dbufs[MAX_FPS]; char *errs[MAX_FPS]; char *buf=NULL; int c; size_t lens[MAX_FPS]; size_t dlens[MAX_FPS]; int i; int got; int maxbufs; int j=0; int loop=1; int delay=0; int get=1; int set=0; int info=0; int access=0; int pipe=0; int tiny=0; int doxpa = 0; int xpaopen=0; int wait=0; XPA xpa=NULL; XPA xpa1=NULL; int fds[1]; #if HAVE_MINGW32==0 setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #endif *cmd = '\0'; /* process switch arguments */ while ((c = getopt(argc, argv, "abd:ef:gil:m:nopqstwx:")) != -1){ switch(c){ case 'a': get = 0; set = 0; info = 0; access = 1; break; case 'b': get = 1; set = 1; info = 0; access = 0; break; case 'd': delay = atoi(optarg); break; case 'e': exitonerror++; break; case 'f': snprintf(cmd, SZ_LINE, "stest %s &\n", optarg); snprintf(fxpa, SZ_LINE, "%s1", optarg); break; case 'g': get = 1; set = 0; info = 0; access = 0; break; case 'i': get = 0; set = 0; info = 1; access = 0; break; case 'l': loop = atoi(optarg); break; case 'm': smode = xstrdup(optarg); break; case 'n': don = 1; break; case 'o': xpaopen = 1; break; case 'p': pipe = 1; fds[0] = fileno(stdout); break; case 'q': quiet = 1; break; case 's': get = 0; set = 1; info = 0; access = 0; break; case 't': tiny = 1; break; case 'w': wait = 1; break; case 'x': doxpa = 1; strcpy(name, optarg); break; } } if( optind < argc ){ xtemplate = argv[optind]; optind++; } /* make up the paramlist */ plist = XPAArgvParamlist(argc, argv, optind); if( !don ) paramlist = plist; else paramlist = (char *)xcalloc(strlen(plist)+SZ_LINE, sizeof(char)); /* for setting, make up a number of dbufs that we will send */ if( set ){ /* must be less than MAX_FPS */ maxbufs = 2; dbufs[0] = (char *)xmalloc(SZ_LINE); strcpy(dbufs[0], "this is a short string"); dlens[0] = strlen(dbufs[0]); if( tiny ) dlens[1] = 256+1; else dlens[1] = 256*1000+1; dbufs[1] = (char *)xmalloc(dlens[1]); for(j=0, buf=dbufs[1]; j 1 ){ if( !quiet ){ fprintf(stdout, "CLIENT #%d: %s\n", j, xtemplate); if( paramlist && *paramlist ) fprintf(stdout, "\tparamlist: %s\n", paramlist); } } /* make up paramlist, if necessary */ if( don ) snprintf(paramlist, SZ_LINE, "%s %d", plist, j); /* XPAGet, XPAGetFd */ if( get ){ if( pipe ){ got = XPAGetFd(xpa, xtemplate, paramlist, smode, fds, names, errs, -MAX_FPS); } else{ got = XPAGet(xpa, xtemplate, paramlist, smode, bufs, lens, names, errs, MAX_FPS); for(i=0; i 0 ){ write(fileno(stdout), bufs[i], lens[i]); } if( strcmp(paramlist, "buf") ) fprintf(stdout, "\n"); } else{ write(fileno(stdout), errs[i], strlen(errs[i])); if( exitonerror ) exit(1); } } if( bufs[i] ) xfree(bufs[i]); if( names[i] ) xfree(names[i]); if( errs[i] ) xfree(errs[i]); } } } /* XPASet, XPASetFd */ if( set ){ if( pipe ){ if( !quiet ) fprintf(stdout, "\tsending data from stdin\n"); got =XPASetFd(xpa, xtemplate, paramlist, smode, fileno(stdin), names, errs, MAX_FPS); } else{ got = XPASet(xpa, xtemplate, paramlist, smode, dbufs[j%maxbufs], dlens[j%maxbufs], names, errs, MAX_FPS); } for(i=0; i to continue ..."); fgets(tbuf, SZ_LINE, stdin); } /* delay */ if( delay ) XPASleep(delay); } /* XPAOpen/XPAClose */ if( xpaopen ){ XPAClose(xpa); } /* free up space */ if( set ){ for(j=0; j #include #include #include /* gethostbyname() */ #define SZ_LINE 1024 int main(int argc, char **argv) { int i; char host[SZ_LINE]; struct hostent *hostent; if( argc > 1 ) strcpy(host, argv[1]); else{ fprintf(stderr, "calling gethostname() ...\n"); if( gethostname(host, SZ_LINE) == -1 ){ perror("gethostname"); exit(1); } else{ fprintf(stderr, "host name is %s\n", host); } } fprintf(stderr, "calling gethostbyname(host) ...\n"); if( !(hostent = gethostbyname(host)) ){ perror("gethostbyname"); exit(1); } else{ fprintf(stderr, "gethostbyname() succeeded\n"); } fprintf(stderr, "printing ip address(es) for this host ...\n"); if( hostent ){ for(i=0; hostent->h_addr_list[i]; i++){ fprintf(stderr, "%x\n", *(int *)hostent->h_addr_list[i]); } } else{ fprintf(stderr, "ERROR: can't look up: %s\n", host); } return(0); } xpa-2.1.15/find.c0000644000054000000360000002373511341504666012071 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * Find.c -- find files via the path environment variable * (and related routines) * */ #include /* * * private routines * */ #define MAXBUFSIZE 8192 #ifndef HAVE_UNISTD_H #define F_OK 0 /* does file exist */ #define X_OK 1 /* is it executable by caller */ #define W_OK 2 /* is it writable by caller */ #define R_OK 4 /* is it readable by caller */ #endif /* not part of unistd.h but we need to differentiate directories */ #ifdef D_OK #undef D_OK #endif #define D_OK 256 /* is it a directory */ #ifdef ANSI_FUNC static int amparse (char *mode) #else static int amparse(mode) char *mode; #endif { int xmode = 0; xmode |= ( strpbrk(mode, "r") != NULL ? R_OK : 0 ); xmode |= ( strpbrk(mode, "w") != NULL ? W_OK : 0 ); xmode |= ( strpbrk(mode, "x") != NULL ? X_OK : 0 ); xmode |= ( strpbrk(mode, "f") != NULL ? F_OK : 0 ); xmode |= ( strpbrk(mode, "d") != NULL ? D_OK : 0 ); return xmode; } #ifdef ANSI_FUNC static char * findpath (char *name, char *mode, char *path) #else static char *findpath(name, mode, path) char *name; char *mode; char *path; #endif { char pathbuff[MAXBUFSIZE]; char namebuff[MAXBUFSIZE]; char tempbuff[MAXBUFSIZE]; char backmode[MAXBUFSIZE]; char *here, *found; int len; int mark = 0; int skip = strpbrk(mode, ">") != NULL; int pick = strpbrk(mode, "<") != NULL; if ( skip && pick ) return NULL; if ( (path==NULL) || ( name[0] == '.' && name[1] == '/' ) || name[0] == '/' ) return Access(name, mode); strncpy(pathbuff, path, MAXBUFSIZE-1); pathbuff[MAXBUFSIZE-1] = '\0'; path = pathbuff; if ( (here = strpbrk(pathbuff, ":;")) ) { mark = *here; *here++ = '\0'; } while ( path ) { /* if there is an environment variable ... */ if ( strchr(path, '$') ) { /* exand it */ ExpandEnv(path, tempbuff, MAXBUFSIZE); /* make sure we could expand it (otherwise we get an infinite loop) */ if( !strchr(tempbuff, '$') ){ if ( (found = findpath(name, mode, tempbuff)) ) return found; } } else { if ( !skip ) { if ( !strcmp(".", path) ) path[0] = '\0'; strncpy(namebuff, path, MAXBUFSIZE-1); namebuff[MAXBUFSIZE-1] = '\0'; len = strlen(namebuff); if ( namebuff[0] && namebuff[len-1] != '/' ){ if( (len+1) <= (MAXBUFSIZE-1) ){ strcat(namebuff, "/"); len++; } /* filename is too large, so we can't find it */ else return NULL; } if( len+strlen(name) <= MAXBUFSIZE-1 ) strcat(namebuff, name); /* filename is too large, so we can't find it */ else return NULL; if ( (found = Access(namebuff, mode)) ) return found; } } if ( mark == ';' ) { if ( skip ) { skip = 0; /* Knock down the skip mode to select all * directories in path after the first ";" */ strncpy(backmode, mode, MAXBUFSIZE-1); backmode[MAXBUFSIZE-1] = '\0'; mode = backmode; } if ( pick ) return NULL; } path = here; if ( here && (here = strpbrk(here, ":;")) ) { mark = *here; *here++ = '\0'; } } return NULL; } /* * * public routines * */ /* * * ResolvePath -- resolve the path to remove . and .. entries * */ #ifdef ANSI_FUNC char * ResolvePath (char *ibuf, char *obuf, int maxlen) #else char *ResolvePath(ibuf, obuf, maxlen) char *ibuf; char *obuf; int maxlen; #endif { char path[MAXBUFSIZE]; char *part[MAXBUFSIZE]; char *tbuf; int i, j; int len; int npart=0; /* if we have no path separators, we really don't have much to do! */ if( strchr(ibuf, '/') == NULL ){ strncpy(obuf, ibuf, maxlen-1); obuf[maxlen-1] = '\0'; return(obuf); } /* if its just "/" or "/.", its easy */ if( !strcmp(ibuf, "/") || !strcmp(ibuf, "/.") ){ strncpy(obuf, "/", maxlen-1); obuf[maxlen-1] = '\0'; return(obuf); } /* if we have a relative path to deal with, get current directory */ if( (*ibuf == '.') || ( (strchr(ibuf, '/') != NULL) && (*ibuf != '/') ) ){ getcwd(path, MAXBUFSIZE); } else{ *path = '\0'; } /* construct the total string we have to deal with */ len = strlen(path) + strlen(ibuf) + 1; tbuf = (char *)xmalloc(len+1); if( *path ){ strcpy(tbuf, path); strcat(tbuf, "/"); strcat(tbuf, ibuf); } else{ strcpy(tbuf, ibuf); } /* construct the parts array from this string, removing / characters and null-terminating each part */ for(i=0; i=0; j--){ if( part[j] ){ part[j] = NULL; break; } } } } /* construct a new string from the remaining parts */ *obuf = '\0'; len = 0; for(i=0; i #endif #include #include #if HAVE_UNISTD_H #include #endif #if HAVE_STRING_H #include #endif #include #include #include #include _PRbeg char *ResolvePath _PRx((char *ibuf, char *obuf, int maxlen)); void ExpandEnv _PRx((char *name, char *fullname, int maxlen)); char *Access _PRx((char *name, char *mode)); char *Find _PRx((char *name, char *mode, char *extn, char *path)); _PRend #endif xpa-2.1.15/gtkloop.c0000644000054000000360000001074511027747036012626 0ustar erichead/* * Copyright (c) 2006 Smithsonian Astrophysical Observatory */ #include #ifdef HAVE_GTK #include #include /*---------------------------------------------------------------------------- * * Private Routines and Data * *---------------------------------------------------------------------------- */ /* record struct for maintining gtk info in gtk select loop */ typedef struct xpagtkrec{ int fd; void *client_data; int id; } *XPAGtk, XPAGtkRec; /*---------------------------------------------------------------------------- * * Routine: XPAGtkHandler * * Purpose: handle one request for an xpaset or xpaget * * Return: none * *---------------------------------------------------------------------------- */ static gboolean XPAGtkHandler(GIOChannel *gio, GIOCondition condition, gpointer data) { XPAGtk xptr = (XPAGtk)data; if( (xptr == NULL) || (xptr->client_data == NULL) ) return TRUE; XPAHandler((XPA)xptr->client_data, xptr->fd); return TRUE; } /*---------------------------------------------------------------------------- * * Routine: XPAGtkEnableOneInput * * Purpose: Enable 1 XPA entry from the Xt event loop * * Results: none * *---------------------------------------------------------------------------- */ static void XPAGtkEnableOneInput (void *client_data) { XPAGtk xptr = (XPAGtk)client_data; if( xptr && !xptr->id ){ GIOChannel* ioc = g_io_channel_unix_new(xptr->fd); xptr->id = g_io_add_watch(ioc, (G_IO_IN | G_IO_HUP | G_IO_NVAL), XPAGtkHandler, xptr); } } /*---------------------------------------------------------------------------- * * Routine: XPAGtkDisableOneInput * * Purpose: Disable 1 XPA entry from the Xt event loop * * Results: none * *---------------------------------------------------------------------------- */ static void XPAGtkDisableOneInput (void *client_data) { XPAGtk xptr = (XPAGtk)client_data; if(xptr && xptr->id){ g_source_remove(xptr->id); xptr->id = 0; } } /*---------------------------------------------------------------------------- * * Routine: XPAGtkAddOneInput * * Purpose: Add 1 XPA entry to the gtk event loop * * Results: none * *---------------------------------------------------------------------------- */ static void* XPAGtkAddOneInput (void *client_data, int fd) { XPAGtk xptr; if( fd < 0 ) return(NULL); xptr = (XPAGtk)calloc(1, sizeof(XPAGtkRec)); xptr->fd = fd; xptr->client_data = client_data; XPAGtkEnableOneInput(xptr); return(xptr); } /*---------------------------------------------------------------------------- * * Routine: XPAGtkDelOneInput * * Purpose: Delete 1 XPA entry from the gtk event loop (called by XPAFree) * * Results: none * *---------------------------------------------------------------------------- */ static void XPAGtkDelOneInput (void *client_data) { XPAGtk xptr = (XPAGtk)client_data; if( xptr == NULL) return; XPAGtkDisableOneInput(xptr); free(xptr); } /*---------------------------------------------------------------------------- * * Public Routines and Data * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * * Routine: XPAGtkAddInput * * Purpose: Add XPA entries to the Xt event loop * * Results: number of xpa entried added * *---------------------------------------------------------------------------- */ int XPAGtkAddInput (XPA xpa) { XPA cur; int got=0; /* if a specific xpa was specified, just add it */ if( xpa != NULL ){ /* remove old one */ if( xpa->seldel && xpa->selptr ){ (xpa->seldel)(xpa->selptr); } /* add new one */ xpa->seldel = XPAGtkDelOneInput; xpa->seladd = XPAGtkAddOneInput; xpa->selon = XPAGtkEnableOneInput; xpa->seloff = XPAGtkDisableOneInput; xpa->selptr = XPAGtkAddOneInput((void *)xpa, xpa->fd); got = 1; } /* otherwise set up all xpa's */ else{ for(cur=(XPA)XPAListHead(); cur!=NULL; cur=cur->next){ /* remove old one */ if( cur->seldel && cur->selptr ){ (cur->seldel)(cur->selptr); } /* add new one */ cur->seldel = XPAGtkDelOneInput; cur->seladd = XPAGtkAddOneInput; cur->selon = XPAGtkEnableOneInput; cur->seloff = XPAGtkDisableOneInput; cur->selptr = XPAGtkAddOneInput((void *)cur, cur->fd); got++; } } return(got); } int xpa_gtk = 1; #else int xpa_gtk = 0; #endif xpa-2.1.15/oxpa.h0000644000054000000360000003435211764270125012121 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * xpa.h - include file for the X Public Access mechanism * */ #ifndef __xpa_h #define __xpa_h #include #include #include #define XPA_MAJOR_VERSION 2 #define XPA_MINOR_VERSION 1 #define XPA_PATCH_LEVEL 14 #define XPA_VERSION "2.1.14" /* #define XPA_DEBUG 1 */ #ifdef XPA_DEBUG #define FPRINTF(x) fprintf x #define PERROR(x) perror x #else #define FPRINTF(x) #define PERROR(x) #endif /* types of xpa request */ #define XPA_SET 1 #define XPA_GET 2 #define XPA_INFO 3 #define XPA_ACCESS 4 /* not actually commands but ... */ #define XPA_DATA 5 #define XPA_ACCEPT 6 #define XPA_NAGLE 7 /* this is the number of actual commands we have above */ #define XPA_CMDS 4 /* comm modes */ #define COMM_RESERVED 1 #define COMM_CONNECT 2 /* the ever-present */ #ifndef SZ_LINE #define SZ_LINE 4096 #endif /* limit the length of the name and xclass strings */ /* at least 2 of these should fit into SZ_LINE with lots of room to spare */ #define XPA_NAMELEN 1024 /* defines the types of callback procedure we use */ typedef int (*SendCb)( #ifdef ANSI_FUNC void *client_data, void *call_data, char *paramlist, char **buf, int *len #endif ); typedef int (*ReceiveCb)( #ifdef ANSI_FUNC void *client_data, void *call_data, char *paramlist, char *buf, int len #endif ); typedef int (*InfoCb)( #ifdef ANSI_FUNC void *client_data, void *call_data, char *paramlist #endif ); typedef void *(*SelAdd)( #ifdef ANSI_FUNC void *client_data, int fd #endif ); typedef void (*SelDel)( #ifdef ANSI_FUNC void *client_data #endif ); typedef void (*SelOn)( #ifdef ANSI_FUNC void *client_data #endif ); typedef void (*SelOff)( #ifdef ANSI_FUNC void *client_data #endif ); typedef void (*MyFree)( #ifdef ANSI_FUNC void *buf #endif ); typedef void Sigfunc( #ifdef ANSI_FUNC int #endif ); /* * * * xpa access control record structure * */ typedef struct aclrec{ struct aclrec *next; char *xclass; char *name; unsigned int ip; char *acl; int flag; } *XACL, XACLRec; /* * * * port management record structure * */ typedef struct portrec{ struct portrec *next; char *xclass; char *name; int port; } *PORT, PORTRec; /* * * * xpa name server management * */ typedef struct nsrec{ struct nsrec *next; char *method; int nxpa; int nproxy; char *host; int fd; FILE *in; FILE *out; /* for AF_INET */ unsigned int ip; int port; /* for AF_UNIX */ char *name; } *NS, NSRec; /* * * * xpa communication structure for each connection * */ typedef struct xpacommrec{ struct xpacommrec *next; int status; int message; int n; int cmd; int mode; int telnet; int usebuf; int useacl; char *id; char *info; char *target; char *paramlist; int cmdfd; int datafd; char *cendian; int ack; /* buf and len passed to callbacks */ char *buf; int len; /* for AF_INET */ unsigned int cmdip; int cmdport; int dataport; /* for AF_UNIX */ char *cmdname; char *dataname; int acl[XPA_CMDS+1]; /* for handling fd's in non-select event loops */ void *selcptr; /* cmdfd struct for seldel */ void *seldptr; /* datafd struct for seldel */ /* pointer to associated name server */ struct nsrec *ns; /* myfree routine */ MyFree myfree; void *myfree_ptr; } *XPAComm, XPACommRec; /* * * * clipboard record structure * */ typedef struct cliprec{ struct cliprec *next; unsigned int ip; char *name; char *value; } *XPAClip, XPAClipRec; /* * * record struct for receiving data from stdin * */ typedef struct xpainputrec{ struct xpainputrec *next; int start; int end; int bytes; char *buf; } *XPAInput, XPAInputRec; /* * * * xpa command record structure * */ typedef struct xpacmdrec{ struct xpacmdrec *next; struct xparec *xpa; char *name; char *help; int ntokens; /* send callback info */ SendCb send_callback; void *send_data; int send_mode; /* receive callback info */ ReceiveCb receive_callback; void *receive_data; int receive_mode; } *XPACmd, XPACmdRec; /* * * * xpa client record structure * */ typedef struct xpaclientrec{ struct xpaclientrec *next; int status; char *id; char *xtemplate; int type; char *xclass; char *name; char *method; char *info; char *dataname; unsigned int ip; int cmdfd; int datafd; int mode; int nsproxy; /* xpaget parameters */ char **bufptr; int *lenptr; int bufsize; int fd; /* xpaset parameters */ char *buf; int len; int bytes; /* fork parameters */ pid_t pid; /* common parameters */ char **nameptr; char **errptr; } *XPAClient, XPAClientRec; /* * * * main xpa record structure * * explanation of send_mode and receive_mode flags: * * receive-specific callback modes: * * r (raw) -- don't read data into buf (callback will read) * * general callback modes: * * r (raw) -- write raw data without protocol info to client * s (save) -- 's' save passed buf (don't free it) * */ typedef struct xparec{ /* xpa version */ char *version; /* status of this xpa */ int status; /* "g", "s", "i" are server types; "c" for client */ char *type; /* * THE SERVER SIDE */ struct xparec *next; char *xclass; char *name; char *help; /* send callback info */ SendCb send_callback; void *send_data; int send_mode; /* receive callback info */ ReceiveCb receive_callback; void *receive_data; int receive_mode; /* info callback info */ InfoCb info_callback; void *info_data; int info_mode; /* list of sub-commands for this access point */ XPACmd commands; /* communication info */ int fd; /* listening socket file descriptor */ char *method; /* method string: host:ip or unix_filename */ NS nshead; /* name servers associated with this access point */ XPAComm commhead; /* linked list of communcation records */ XPAClip cliphead; /* linked list of cliboard records */ char *filename; /* file name (unix sockets) for listening */ char *sendian; /* endian-ness of server */ /* request-specific info */ XPAComm comm; /* current comm if we are processing a request */ /* select loop info */ SelDel seldel; /* routine to remove xpa socket from select loop */ SelAdd seladd; /* routine to add xpa command sockets to select loop */ SelOn selon; /* routine to enable xpa command sockets */ SelOff seloff; /* routine to disable xpa command sockets */ void *selptr; /* additional info for seldelete() */ /* * THE CLIENT SIDE */ int persist; /* flag whether this is a persistent client */ int nclient; /* number of clients -- used in processing headers */ int client_mode; /* global client mode */ XPAClient clienthead; /* linked list of active clients */ int ifd; /* input fd for XPASetFd() */ int inpbytes; /* total number of bytes in input lists */ XPAInput inphead; /* linked list of input structs */ } *XPA, XPARec; /* macros to access the xpa struct */ #define xpa_name(xpa) ((xpa)->name) #define xpa_class(xpa) ((xpa)->xclass) #define xpa_method(xpa) ((xpa)->method) #define xpa_sendian(xpa) ((xpa)->sendian) #define xpa_comm(xpa) (xpa&&(xpa)->comm?(xpa)->comm:NULL) #define xpa_cendian(xpa) (((xpa)->comm&&(xpa)->comm->cendian)?(xpa)->comm->cendian:"?") #define xpa_cmdfd(xpa) ((xpa)->comm?(xpa)->comm->cmdfd:-1) #define xpa_datafd(xpa) ((xpa)->comm?(xpa)->comm->datafd:-1) #define xpa_ack(xpa) ((xpa)->comm?(xpa)->comm->ack:1) #define xpa_status(xpa) ((xpa)->comm?(xpa)->comm->status:0) #define xpa_id(xpa) (((xpa)->comm&&(xpa)->comm->id)?(xpa)->comm->id:"?") extern char *xpaMessbuf[]; _PRbeg XPA XPAListHead _PRx((void)); void XPAListAdd _PRx((XPA *head, XPA xpa)); void XPAListDel _PRx((XPA *head, XPA xpa)); int XPAActive _PRx((XPA xpa, XPAComm comm, int flag)); int XPAActiveFd _PRx((int fd)); int XPAAddSelect _PRx((XPA xpa, fd_set *readfdsptr)); int XPAProcessSelect _PRx((fd_set *readfdsptr, int maxreq)); void XPACloseData _PRx((XPA xpa, XPAComm comm)); int XPAHandler _PRx((XPA xpa, int fd)); void XPAMode _PRx((char *mode, int *flag, char *name, int mask, int def)); int XPAEndian _PRx((void)); char *XPATmpdir _PRx((void)); void XPACleanup _PRx((void)); int XPASetBuf _PRx((XPA xpa, char *buf, int len, int xcopy)); int XPASetFree _PRx((XPA xpa, MyFree myfree, void *myfree_ptr)); int XPAShortTimeout _PRx((void)); int XPALongTimeout _PRx((void)); int XPASendLTimeout _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); int XPAReceiveLTimeout _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPASendSTimeout _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); int XPAReceiveSTimeout _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPADebug _PRx((void)); int XPASigusr1 _PRx((void)); int XPAVerbosity _PRx((void)); void XPAInitEnv _PRx((void)); void XPAParseName _PRx((char *xpaname, char *xclass, char *name, int len)); int XPAParseIpPort _PRx((char *host, unsigned int *ip, unsigned short *port)); int XPAParseUnixSocket _PRx((char *host)); int _XPAValid _PRx((XPA head, XPA xpa, char *type)); int XPAValid _PRx((XPA xpa)); char *XPATimestamp _PRx((void)); int XPAError _PRx((XPA xpa, char *s)); int XPAOK _PRx((XPA xpa)); int XPAMessage _PRx((XPA xpa, char *s)); char *XPAArgvParamlist _PRx((int argc, char **argv, int start)); int XPAMethod _PRx((char *method)); int XPAAccess _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, char **names, char **messages, int n)); int XPANSLookup _PRx((XPA xpa, char *tname, char *ttype, char ***xclasses, char ***names, char ***methods, char ***infs)); int XPANSClose _PRx((XPA xpa, NS ns)); int XPANSKeepAlive _PRx((XPA xpa, int type)); int XPANSAdd _PRx((XPA xpa, char *host, char *mode)); int XPANSDel _PRx((XPA xpa, char *host, char *mode)); int XPAVersionCheck _PRx((char *serv, char *nsv)); void XPAVersionWarn _PRx((char *myv, char *nsv)); char *XPANSMethod _PRx((char *host, int flag)); XPA XPANew _PRx((char *xclass, char *name, char *help, SendCb send_callback, void *send_data, char *send_mode, ReceiveCb rec_callback, void *rec_data, char *rec_mode)); int XPAFree _PRx((XPA xpa)); XPA XPAInfoNew _PRx((char *xclass, char *name, InfoCb info_callback, void *info_data, char *info_mode)); int XPAPoll _PRx((int msec, int maxreq)); int XPAMainLoop _PRx((void)); void XPASleep _PRx((int msec)); void XPAAtExit _PRx((void)); /* command.c */ void XPAInitReserved _PRx((void)); void XPAFreeReserved _PRx((void)); XPACmd XPACmdLookupReserved _PRx((XPA xpa, char *lbuf, int *lp)); XPACmd XPACmdLookup _PRx((XPA xpa, char *lbuf, int *lp)); int XPAReceiveCommands _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPASendCommands _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); XPA XPACmdNew _PRx((char *xclass, char *name)); XPACmd XPACmdAdd _PRx((XPA xpa, char *name, char *help, SendCb send_callback, void *send_data, char *send_mode, ReceiveCb rec_callback, void *rec_data, char *rec_mode)); int XPACmdDel _PRx((XPA xpa, XPACmd cmd)); int XPACmdInternalReceive _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPACmdInternalSend _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); XPA XPAGetReserved _PRx((void)); int XPAMtype _PRx((void)); /* client.c */ int XPAClientAddSelect _PRx((XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr)); int XPAClientProcessSelect _PRx((XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr, int maxreq)); XPA XPAOpen _PRx((char *mode)); void XPAClose _PRx((XPA xpa)); int XPAGet _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, char **bufs, int *lens, char **names, char **errs, int n)); int XPAGetFd _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, int *fds, char **names, char **errs, int n)); int XPASet _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, char *buf, int len, char **names, char **errs, int n)); int XPASetFd _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, int fd, char **names, char **errs, int n)); int XPAInfo _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, char **names, char **errs, int n)); int XPAClientValid _PRx((XPA xpa)); void XPASaveJmp _PRx((void *env)); /* acl.c */ int XPAReceiveAcl _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPASendAcl _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); int XPAAclEdit _PRx((char *lbuf)); int XPAAclAdd _PRx((char *lbuf)); int XPAAclDel _PRx((XACL acl)); void XPAAclFree _PRx((void)); int XPAAclNew _PRx((char *aname, int flag)); int XPAAclCheck _PRx((XPA xpa, unsigned int ip, char *acl)); /* port.c */ int XPAPortEdit _PRx((char *lbuf)); int XPAPortAdd _PRx((char *lbuf)); int XPAPortDel _PRx((PORT port)); void XPAPortFree _PRx((void)); int XPAPortNew _PRx((char *aname, int flag)); int XPAPort _PRx((XPA xpa)); /* remote.c */ int XPAReceiveRemote _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPASendRemote _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); int XPARemote _PRx((XPA xpa, char *host, char *acl, char *mode)); /* clipboard.c */ int XPAReceiveClipboard _PRx((void *client_data, void *call_data, char *paramlist, char *buf, int len)); int XPASendClipboard _PRx((void *client_data, void *call_data, char *paramlist, char **buf, int *len)); int ClipBoardFree _PRx((XPA xpa, XPAClip clip)); /* xt.c */ int XPAXtAddInput _PRx((void *app, XPA xpa)); /* tcl.c */ int XPATclAddInput _PRx((XPA xpa)); int Tclxpa_Init _PRx((void *vinterp)); /* gtkloop.c */ int XPAGtkAddInput _PRx((XPA xpa)); /* xpaio.c */ int XPAGets _PRx((XPA xpa, int fd, char *buf, int len, int timeout)); int XPAPuts _PRx((XPA xpa, int fd, char *buf, int timeout)); int XPAGetBuf _PRx((XPA xpa, int fd, char **buf, int *len, int timeout)); int XPAPutBuf _PRx((XPA xpa, int fd, char *buf, int len, int timeout)); int XPAIOCallsXPA _PRx((int flag)); char *XPALevelSpaces _PRx((void)); void XPALevelSet _PRx((int lev)); int XPALevelGet _PRx((void)); _PRend #endif /* __xpa.h */ xpa-2.1.15/port.c0000644000054000000360000001516010010224036012104 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * port.c -- xpa port management * */ #include /* *---------------------------------------------------------------------------- * * * Private Routines * * *---------------------------------------------------------------------------- */ /* this is the head of the global list -- too lazy to do anything more */ static PORT porthead=NULL; #ifdef ANSI_FUNC static PORT XPAPortLookup (char *xclass, char *name) #else static PORT XPAPortLookup(xclass, name) char *xclass; char *name; #endif { PORT cur; /* look for exact match */ for(cur=porthead; cur!=NULL; cur=cur->next){ if( !strcmp(xclass, cur->xclass) && !strcmp(name, cur->name) ){ return(cur); } } /* otherwise look for a template match */ for(cur=porthead; cur!=NULL; cur=cur->next){ if( tmatch(xclass, cur->xclass) && tmatch(name, cur->name) ){ return(cur); } } return(NULL); } /* *---------------------------------------------------------------------------- * * Routine: XPAPortParse * * Purpose: parse port list into components * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAPortParse (char *lbuf, char *xclass, char *name, int *port, int len) #else static int XPAPortParse(lbuf, xclass, name, port, len) char *lbuf; char *xclass; char *name; int *port; int len; #endif { char tbuf[SZ_LINE]; int lp=0; /* init port values */ *port = 0; /* class:name is required */ if( word(lbuf, tbuf, &lp) ){ XPAParseName(tbuf, xclass, name, len); } else{ return(-1); } /* port is required but can be "*" for default port */ if( word(lbuf, tbuf, &lp) ){ if( !strcmp(tbuf, "*") ) *port = XPA_DEFPORT; else *port = atoi(tbuf); } else{ return(-1); } /* made it */ return(0); } /*---------------------------------------------------------------------------- * * * Public Routines * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPAPortAdd * * Purpose: add one port entry to the xpa port list * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAPortAdd (char *lbuf) #else int XPAPortAdd(lbuf) char *lbuf; #endif { PORT xnew; PORT cur; char xclass[SZ_LINE]; char name[SZ_LINE]; int port; /* allocate port struct */ if( (xnew = (PORT)xcalloc(1, sizeof(struct portrec))) == NULL ) goto error; /* parse info from line buffer */ if( XPAPortParse(lbuf, xclass, name, &port, SZ_LINE) < 0 ) goto error; /* fill in the blanks */ xnew->xclass = xstrdup(xclass); xnew->name = xstrdup(name); xnew->port = port; /* add this port to end of list of port's */ if( porthead == NULL ){ porthead = xnew; } else{ for(cur=porthead; cur->next!=NULL; cur=cur->next) ; cur->next = xnew; } return(0); error: if( xnew ) xfree(xnew); return(-1); } /* *--------------------------------------------------------------------------- * * Routine: XPAPortDel * * Purpose: free up alloc'ed memory in the port record structure * * Results: 0 on success, -1 for failure * *--------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAPortDel (PORT port) #else int XPAPortDel(port) PORT port; #endif { PORT cur; if( port == NULL ) return(-1); /* remove from list of port's */ if( porthead ){ if( porthead == port ){ porthead = porthead->next; } else{ for(cur=porthead; cur!=NULL; cur=cur->next){ if( cur->next == port ){ cur->next = (cur->next)->next; break; } } } } /* free up string space */ if( port->xclass ) xfree(port->xclass); if( port->name ) xfree(port->name); /* free up record struct */ xfree((char *)port); return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPAPortFree * * Purpose: * * Results: 1 on success, 0 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC void XPAPortFree (void) #else void XPAPortFree() #endif { PORT cur; PORT saveport; for(cur=porthead; cur!=NULL; ){ saveport = cur->next; XPAPortDel(cur); cur = saveport; } } /* *---------------------------------------------------------------------------- * * Routine: XPAPortNew * * Purpose: read or re-read the port list * * Results: number of lines in list (including default) * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAPortNew (char *aname, int flag) #else int XPAPortNew(aname, flag) char *aname; int flag; #endif { int got=0; char lbuf[SZ_LINE]; char *s; char *portname=NULL; char *portpath=NULL; char *portstr=NULL; char *portcopy=NULL; FILE *fp; /* if there is an old list, free it */ if( flag == 0 ) XPAPortFree(); /* get port file name */ if( aname && *aname ) portname = aname; else if( (portname=(char *)getenv("XPA_PORTFILE")) == NULL ) portname = XPA_PORTFILE; /* get the default port */ portstr=(char *)getenv("XPA_PORT"); /* add the port assignments from environment first */ if( portstr && *portstr ){ portcopy=(char *)xstrdup(portstr); for(s=(char *)strtok(portcopy,";"); s!=NULL; s=(char *)strtok(NULL,";")){ if( XPAPortAdd(s) == 0 ) got++; } if( portcopy) xfree(portcopy); } /* add the port assignments from file next */ if( (portpath=(char *)Access(portname, "r")) != NULL ){ if( (fp=fopen(portpath, "r")) != NULL ){ while( fgets(lbuf, SZ_LINE, fp) ){ if( *lbuf == '#' ){ continue; } if( XPAPortAdd(lbuf) == 0 ) got++; } fclose(fp); } xfree(portpath); } /* return the news */ return(got); } /* *---------------------------------------------------------------------------- * * Routine: XPAPort * * Purpose: check for pre-defined port for a given class, name and * 1 for com port, 2 for data port * * Results: assigned port or 0 * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAPort (XPA xpa) #else int XPAPort(xpa) XPA xpa; #endif { int p=0; PORT cur; if( xpa == NULL ) return 0; if( (cur = XPAPortLookup(xpa->xclass, xpa->name)) ){ p = cur->port; } return p; } xpa-2.1.15/prsetup.h0000644000054000000360000000162010010224037012624 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* prsetup.h -- define variables for ANSI prototyping */ #ifndef _prsetup #define _prsetup #ifdef NO_ANSI_FUNC #define _PRbeg #define _PRend #define _PRx(s) () #ifdef ANSI_FUNC #undef ANSI_FUNC #endif #else #if defined(__cplusplus) || defined(c_plusplus) #define _PRbeg extern "C" { /* do not leave open across includes */ #define _PRend } #define _PRx(s) s #define ANSI_FUNC 1 #else #if defined(__STDC__) #define _PRbeg #define _PRend #define _PRx(s) s #define ANSI_FUNC 1 #else #define _PRbeg #define _PRend #define _PRx(s) () #ifdef ANSI_FUNC #undef ANSI_FUNC #endif #endif #endif #endif /* the ever-present */ #ifndef SZ_LINE #define SZ_LINE 4096 #endif #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif #ifndef ABS #define ABS(x) ((x)<0?(-x):(x)) #endif #endif xpa-2.1.15/remote.c0000644000054000000360000001362112052464634012435 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * remote.c -- xpa access control list management * */ #include /* *---------------------------------------------------------------------------- * * * Private Routines * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * * Semi-Public Routines (used by command.c) * * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * Routine: XPAReceiveRemote * * Purpose: establish remote connection with specified acls * * Returns: xpa callback error codes * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPAReceiveRemote (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int XPAReceiveRemote(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; XPA cxpa; char *mode=NULL; char host[SZ_LINE]; char acl[SZ_LINE]; char which[SZ_LINE]; char tbuf[SZ_LINE]; int lp=0; /* make sure we are using inet sockets */ if( XPAMtype() != XPA_INET ){ snprintf(tbuf, SZ_LINE, "remote requires that XPA_METHOD be 'inet'\n"); XPAError(xpa, tbuf); return(-1); } /* see if we are connecting to a particular host */ if( paramlist && *paramlist ){ cxpa = xpa; /* arg1: host */ if( !word(paramlist, host, &lp) ){ goto error; } /* arg2: acl (optional) or -proxy */ if( !word(paramlist, acl, &lp) ){ strcpy(acl, "+"); } /* arg3: -proxy to set up proxy processing or acl (if other word was -proxy) */ else{ if( !strcmp(acl, "-proxy") ){ mode="proxy=true"; if( !word(paramlist, acl, &lp) ){ strcpy(acl, "+"); } } else if( word(paramlist, which, &lp) ){ if( !strcmp(which, "-proxy") ){ mode="proxy=true"; } else{ goto error; } } } /* make the call */ if( XPARemote(cxpa, host, acl, mode) >= 0 ){ return(0); } else{ snprintf(tbuf, SZ_LINE, "remote xpans %s failed to process %s\n", host, xpa->name); XPAError(xpa, tbuf); return(-1); } } else{ goto error; } error: XPAError(xpa, "syntax error: -remote hostname:port [acl] [-proxy]\n"); return(-1); } /* *---------------------------------------------------------------------------- * * Routine: XPASendRemote * * Purpose: return the list of remotes for this access point * * Returns: 0 for success, -1 for failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPASendRemote (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int XPASendRemote(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; NS ns; int got = 0; char tbuf[SZ_LINE]; /* list out the remotes */ for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ /* skip default ns */ if( ns->host == NULL ) continue; snprintf(tbuf, SZ_LINE, "%s %x:%d\n", ns->host, ns->ip, ns->port); send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); got++; } if( got == 0 ){ send(xpa_datafd(xpa), "\n", 1, 0); } return(0); } /* *---------------------------------------------------------------------------- * * Routine: XPARemote * * Purpose: register the specified XPA (or all XPAs) with the named remote * name server using the specified acl * * Returns: none * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC int XPARemote (XPA xpa, char *host, char *acl, char *mode) #else int XPARemote(xpa, host, acl, mode) XPA xpa; char *host; char *acl; char *mode; #endif { int got=0; char remote[SZ_LINE]; char mach[SZ_LINE]; char lbuf[SZ_LINE]; char *ind; XPA cur; /* might have to add the "port" to the host to get remote */ strncpy(remote, host, SZ_LINE-1); remote[SZ_LINE-1] = '\0'; if( (ind=strchr(remote, ':')) == NULL ){ strcat(remote, ":$port"); } /* if no acl is specified, make it '+' */ if( (acl == NULL) || (*acl == '\0') ){ acl = "+"; } /* get machine name by removing port suffix */ strcpy(mach, remote); if( (ind=strchr(mach, ':')) != NULL ){ *ind = '\0'; } else{ return(-1); } /* either process the specified xpa, or do all of them */ if( xpa ){ cur = xpa; /* acl="-" => delete, else add */ if( strcmp(acl, "-") ){ got=XPANSAdd(cur, remote, mode); } else{ got=XPANSDel(cur, remote, mode); } switch(got){ /* error condition */ case -1: return(-1); /* OK */ case 0: snprintf(lbuf, SZ_LINE, "%s:%s %s %s", cur->xclass, cur->name, mach, acl); XPAAclEdit(lbuf); break; /* entry already exists (OK) */ case 1: break; } } else{ for(cur=XPAListHead(); cur!=NULL; cur=cur->next){ /* acl="-" => delete, else add */ if( strcmp(acl, "-") ){ got=XPANSAdd(cur, remote, mode); } else{ got=XPANSDel(cur, remote, mode); } switch(got){ /* error condition */ case -1: return(-1); /* OK */ case 0: snprintf(lbuf, SZ_LINE, "%s:%s %s %s", cur->xclass, cur->name, mach, acl); XPAAclEdit(lbuf); break; /* entry already exists (OK) */ case 1: break; } } } /* return OK */ return(0); } /* *---------------------------------------------------------------------------- * * * Public Routines * * *---------------------------------------------------------------------------- */ xpa-2.1.15/rtest.c0000644000054000000360000001112312052466576012305 0ustar erichead/* * Copyright (c) 2004 Smithsonian Astrophysical Observatory */ /* * * rtest -- server test for xpa * */ #include #define MAX_XPAS 10 extern char *optarg; extern int optind; #define BUFSIZE 1000000 char xbuf[BUFSIZE+1]; size_t xlen; int quiet=0; #ifdef ANSI_FUNC int send_cb (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int send_cb(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; if( !xpa ) return(-1); *len = xlen; *buf = (char *)xmalloc(*len); memcpy(*buf, xbuf, *len); if( !quiet ) fprintf(stderr, "sent (%s): %lu\n", paramlist, (unsigned long)xlen); return(0); } #ifdef ANSI_FUNC int receive_cb (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int receive_cb(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; if( !xpa ) return(-1); if( !quiet ) fprintf(stderr, "recd (%s): %s\n", paramlist, buf); return(0); } #ifdef ANSI_FUNC int main (int argc, char **argv) #else main(argc, argv) int argc; char **argv; #endif { int c; int i, j; int got; int delay=-1; int total=0; int dobig=0; int dofd=0; int doexit=0; int poll=1; int msec=100; int verbose=0; size_t lens[MAX_XPAS]; char *bufs[MAX_XPAS]; char *names[MAX_XPAS]; char *errs[MAX_XPAS]; char *xmode=""; char xname[SZ_LINE]; char xclass[SZ_LINE]; char paramlist[SZ_LINE]; int xfds[1]; XPA xpa; /* we use the xpa timestamp routine */ putenv("XPA_TIMESTAMP_ERRORS=true"); /* process switch arguments */ while ((c = getopt(argc, argv, "bd:fm:pqv")) != -1){ switch(c){ case 'b': dobig = 1; break; case 'd': delay = atoi(optarg); break; case 'f': dofd = 1; break; case 'm': msec = atoi(optarg); break; case 'p': poll = 0; break; case 'q': quiet = 1; break; case 'v': verbose = 1; break; default: break; } } /* make sure we have the xpa argument */ if( optind >= argc ){ fprintf(stderr, "usage: %s [xpa] [target1 target2 ...]\n", argv[0]); exit(1); } strcpy(xname, argv[optind++]); strcpy(xclass, xname); cluc(xclass); if( (xpa = XPANew(xclass, xname, "help is on the way", send_cb, (void *)xname, xmode, receive_cb, (void *)xname, xmode)) ){ fprintf(stdout, "%s using method: %s\n", xpa_name(xpa), xpa_method(xpa)); } else{ fprintf(stderr, "ERROR: could not init xpa\n"); exit(1); } if( dobig ){ for(i=0; i 0 ) XPASleep(delay); } } done: XPAFree(xpa); exit(0); } xpa-2.1.15/stest.c0000644000054000000360000004075312151731365012310 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ /* * * stest -- server test for xpa * */ #include #ifndef BUILD_WITH_XT #if HAVE_XT #undef HAVE_XT #endif #endif #if HAVE_XT #include #include #endif #define MAX_FPS 10 extern char *optarg; extern int optind; XPA xpa1, xpa1a, xpa2, xpa3; int quiet=0; int dowait=0; int dofill=0; int dosave=1; int doone=0; int domyfree=0; int doatexit=0; int n=0; int please_exit=0; size_t save_bytes=-1; char *save_buf=NULL; char *mode=""; char name[SZ_LINE]; char xclass[SZ_LINE]; #ifdef ANSI_FUNC void myfree(void *buf) #else void myfree(buf) void *buf; #endif { fprintf(stderr, "myfree calling xfree(%p)\n", buf); xfree(buf); } #ifdef ANSI_FUNC int send_cb (void *client_data, void *call_data, char *paramlist, char **buf, size_t *len) #else int send_cb(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char **buf; size_t *len; #endif { char *s = (char *)client_data; XPA xpa = (XPA)call_data; char tbuf[SZ_LINE]; char xtemplate[SZ_LINE]; char *names[MAX_FPS]; char *bufs[MAX_FPS]; char *errs[MAX_FPS]; size_t lens[MAX_FPS]; int sendbuf=0; int got; int i; int ip; /* set the free routine */ if( domyfree ) XPASetFree(xpa, myfree, NULL); /* introduce ourselves */ if( !quiet ){ fprintf(stdout, "SEND_CB #%d: %s:%s %s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), s); } /* process special paramlist tokens */ if( paramlist && *paramlist ){ ip = 0; word(paramlist, xtemplate, &ip); if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); if( !strncmp(paramlist, "buf", 3) ){ sendbuf=1; } else if( !strcmp(paramlist, "free") ){ if( !quiet ) fprintf(stdout, "Freeing xpa struct\n"); XPAFree(xpa); return(0); } else if( !strcmp(paramlist, "exit") ){ if( !quiet ) fprintf(stdout, "Exiting\n"); if( doatexit){ please_exit = 1; } else { XPAFree(xpa1); if( !doone ){ XPAFree(xpa1a); XPAFree(xpa2); XPAFree(xpa3); } } } else if( !strcmp(paramlist, "Exit") ){ if( !quiet ) fprintf(stdout, "Exiting immediately\n"); exit(0); } else if( !strncmp(paramlist, "error", 5) ){ if( !quiet ) fprintf(stdout, "\treturning error: %s\n", ¶mlist[6]); *len = 0; *buf = NULL; if( strlen(paramlist) > 6 ) XPAError(xpa, ¶mlist[6]); else XPAError(xpa, "intentional error from client"); return(-1); } else if( !strcmp(paramlist, "wait") || !strcmp(paramlist, "version") ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } else if( !strcmp(paramlist, "poll") ){ repoll: fprintf(stdout, "Press 'q' to quit ..."); got = XPAPoll (10000, 1); fprintf(stdout, " XPAPoll returns %d ...", got); fgets(tbuf, SZ_LINE, stdin); if( *tbuf != 'q' ) goto repoll; } else if( !strncmp(paramlist, "fork ", 5) ){ #if HAVE_MINGW32==0 if( strlen(paramlist) > 5 ){ fprintf(stdout, "fork command: %s\n", ¶mlist[5]); /* child forks a command and exits */ if(!(fork())){ system(¶mlist[5]); /* should call _exit but this tests avoidance of atexit routine */ exit(0); } } #else fprintf(stderr, "ERROR: fork() not available in mingw\n"); exit(1); #endif } else if( !strcmp(xtemplate, "xpaget") ){ word(paramlist, xtemplate, &ip); got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, bufs, lens, names, errs, MAX_FPS); if( !quiet ) fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); for(i=0; i 0) ){ fprintf(stdout, "contents (%lu bytes):\n", (unsigned long)lens[i]); fwrite(bufs[i], sizeof(char), lens[i], stdout); } if( !quiet ) fprintf(stdout, "\n"); } else{ write(fileno(stdout), errs[i], strlen(errs[i])); } if( bufs[i] ) xfree(bufs[i]); if( names[i] ) xfree(names[i]); if( errs[i] ) xfree(errs[i]); } } } else if( dowait ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } /* return information about this xpa */ if( !sendbuf ){ snprintf(tbuf, SZ_LINE, "class: %s\nname: %s\nmethod: %s\nsendian: %s\ncendian: %s\n", xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), xpa_sendian(xpa), xpa_cendian(xpa)); if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); *len = 0; *buf = NULL; if( !quiet) fprintf(stdout, "\tcallback writes %d bytes to client\n", (int)strlen(tbuf)); } /* return the buffer and let xpa transmit it */ else{ *len = strlen(tbuf); *buf = (char *)xmalloc(*len); memcpy(*buf, tbuf, *len); if( !quiet) fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", (int)strlen(tbuf)); } } /* return the last buffer we were sent */ else{ if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ send(xpa_datafd(xpa), save_buf, save_bytes, 0); *len = 0; *buf = NULL; if( !quiet) fprintf(stdout, "\tcallback writes %lu bytes to client\n", (unsigned long)save_bytes); } /* return the buffer and let xpa transmit it */ else{ *len = save_bytes; *buf = (char *)xmalloc(*len); memcpy(*buf, save_buf, *len); if( !quiet) fprintf(stdout, "\tcallback returns %lu bytes to xpa handler\n", (unsigned long)save_bytes); } } if( !quiet ){ fprintf(stdout, "SEND_CB complete\n"); } else{ fprintf(stdout, "."); } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int receive_cb (void *client_data, void *call_data, char *paramlist, char *buf, size_t len) #else int receive_cb(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 *s = (char *)client_data; char tbuf[SZ_LINE]; char cbuf[SZ_LINE]; char *errs[1]; int i; int ip; int got; int xwait; /* set the free routine */ if( domyfree ) XPASetFree(xpa, myfree, NULL); if( !quiet ){ fprintf(stdout, "RECEIVE_CB #%d: %s:%s %s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), s); } /* process param list */ if( paramlist && *paramlist ){ if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); if( !strcmp(paramlist, "free") ){ if( !quiet ) fprintf(stdout, "Freeing xpa struct\n"); XPAFree(xpa); return(0); } else if( !strcmp(paramlist, "exit") ){ if( !quiet ) fprintf(stdout, "Exiting\n"); if( doatexit){ please_exit = 1; } else { XPAFree(xpa1); if( !doone ){ XPAFree(xpa1a); XPAFree(xpa2); XPAFree(xpa3); } } } else if( !strcmp(paramlist, "Exit") ){ if( !quiet ) fprintf(stdout, "Exiting immediately\n"); exit(0); } else if( !strncmp(paramlist, "error", 5) ){ if( !quiet ) fprintf(stdout, "Processing error: %s\n", ¶mlist[6]); if( strlen(paramlist) > 6 ) XPAError(xpa, ¶mlist[6]); else XPAError(xpa, "intentional error from client"); return(-1); } else if( !strcmp(paramlist, "wait") ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } else if( !strcmp(paramlist, "poll") ){ repoll: fprintf(stdout, "Press 'q' to quit ..."); got = XPAPoll (10000, 1); fprintf(stdout, " ... XPAPoll returns %d ...", got); fgets(tbuf, SZ_LINE, stdin); if( *tbuf != 'q' ) goto repoll; } else if( !strncmp(paramlist, "fork ", 5) ){ #if HAVE_MINGW32==0 if( strlen(paramlist) > 5 ){ fprintf(stdout, "fork command: %s\n", ¶mlist[5]); /* child forks a command and exits */ if(!(fork())){ system(¶mlist[5]); /* should call _exit but this tests avoidance of atexit routine */ exit(0); } } #else fprintf(stderr, "ERROR: fork() not available in mingw\n"); exit(1); #endif } else if( !strncmp(paramlist, "xpaset", 6) ){ ip = 0; word(paramlist, tbuf, &ip); if( word(paramlist, tbuf, &ip) ){ if( !quiet ) fprintf(stdout, "calling XPASet(%s, \"%s\")\n", tbuf, &(paramlist[ip])); got = XPASet(NULL, tbuf, &(paramlist[ip]), mode, paramlist, strlen(paramlist), NULL, errs, 1); if( got == 0 ){ if( !quiet ) fprintf(stdout, "no XPA access points matched template %s\n", tbuf); } else if( errs[0] != NULL ){ if( !quiet ) fprintf(stdout, "Error on xpaset to %s: %s\n", tbuf, errs[0]); xfree(errs[0]); } else{ if( !quiet ) fprintf(stdout, "XPASet to %s successful\n", tbuf); } } return(0); } } else if( dowait ){ fprintf(stdout, "Press to continue ..."); fgets(tbuf, SZ_LINE, stdin); } /* reset save buffer */ if( save_buf != NULL ){ xfree(save_buf); save_buf = NULL; } save_bytes = 0; xwait = dowait; if( !(xpa->receive_mode & XPA_MODE_FILLBUF) && dofill ){ while( (got=recv(xpa_datafd(xpa), tbuf, SZ_LINE, 0)) >0 ){ if( xwait >0 ){ fprintf(stdout, "got %d bytes ... press to continue ...", got); fgets(cbuf, SZ_LINE, stdin); xwait--; } i = save_bytes; save_bytes += got; if( dosave ){ if( save_buf == NULL ) save_buf = (char *)xmalloc(save_bytes); else save_buf = (char *)xrealloc(save_buf, save_bytes); memcpy(&save_buf[i], tbuf, got); } } if( !quiet ) fprintf(stdout, "\tcallback read %lu bytes\n", (unsigned long)save_bytes); } else{ if( !quiet ){ fprintf(stdout, "\tenter callback with buf: %lu bytes\n", (unsigned long)len); } save_bytes = len; save_buf = (char *)xmalloc(len); memcpy(save_buf, buf, len); } if( !quiet ){ fprintf(stdout, "RECEIVE_CB complete\n"); } else{ fprintf(stdout, "."); } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int info_cb (void *client_data, void *call_data, char *paramlist) #else int info_cb(client_data, call_data, paramlist) void *client_data; void *call_data; char *paramlist; #endif { XPA xpa = (XPA)call_data; char *s = (char *)client_data; char xtemplate[SZ_LINE]; char *names[MAX_FPS]; char *bufs[MAX_FPS]; char *errs[MAX_FPS]; size_t lens[MAX_FPS]; int i; int ip; int got; if( !quiet ){ fprintf(stdout, "INFO_CB #%d: %s:%s (%s)\n", n++, xpa_class(xpa), xpa_name(xpa), s); } if( paramlist && *paramlist ){ if( !quiet ) fprintf(stdout, "\tparamlist: %s\n", paramlist); ip = 0; word(paramlist, xtemplate, &ip); if( !strcmp(xtemplate, "xpaget") ){ word(paramlist, xtemplate, &ip); got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, bufs, lens, names, errs, MAX_FPS); if( !quiet ) fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); for(i=0; i 0) ){ fprintf(stdout, "contents (%lu bytes):\n", (unsigned long)lens[i]); fwrite(bufs[i], sizeof(char), lens[i], stdout); } if( !quiet ) fprintf(stdout, "\n"); } else{ write(fileno(stdout), errs[i], strlen(errs[i])); } if( bufs[i] ) xfree(bufs[i]); if( names[i] ) xfree(names[i]); if( errs[i] ) xfree(errs[i]); } } } if( !quiet ){ fprintf(stdout, "INFO_CB complete\n"); } else{ fprintf(stdout, "."); } fflush(stdout); fflush(stderr); return(0); } #ifdef ANSI_FUNC int main (int argc, char **argv) #else main(argc, argv) int argc; char **argv; #endif { #if HAVE_XT Widget top; XtAppContext appcontext; #endif char *proxy=NULL; char tbuf[SZ_LINE]; char tbuf2[SZ_LINE]; char cmd[SZ_LINE]; int c; int got=0; int x=0; int delay=0; #if HAVE_MINGW32==0 setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #endif *cmd = '\0'; /* process switch arguments */ while ((c = getopt(argc, argv, "1ad:f:mqrRp:suwxX")) != -1){ switch(c){ case '1': doone = 1; break; case 'a': mode = "ack=false"; break; case 'd': delay = atoi(optarg); break; case 'f': snprintf(cmd, SZ_LINE, "%s %s &\n", argv[0], optarg); break; case 'm': domyfree = 1; break; case 'q': quiet = 1; break; case 'p': proxy = optarg; break; case 'r': mode = "fillbuf=false"; break; case 'R': mode = "fillbuf=false"; dofill = 1; dosave = 0; break; case 's': x = 0; break; case 'u': mode = "buf=false"; break; case 'w': dowait++; break; case 'x': doatexit=1; break; case 'X': x = 1; break; } } if( optind >= argc ){ strcpy(name, "xpa"); } else{ strcpy(name, argv[optind]); } strcpy(xclass, name); cluc(xclass); if( doatexit ){ #if HAVE_ATEXIT XPAAtExit(); #else fprintf(stderr, "ERROR: atexit not available\n"); exit(1); #endif } if( x ){ #if HAVE_XT top = XtAppInitialize(&appcontext, "Server", NULL, 0, &argc, argv, NULL, NULL, 0); XtVaSetValues(top, XtNwidth, (XtArgVal)10, XtNheight, (XtArgVal)10, XtNmappedWhenManaged, (XtArgVal)False, NULL); #else fprintf(stderr, "Xt is not available ...\n"); got = 1; goto done; #endif } strcpy(tbuf, name); snprintf(tbuf2, SZ_LINE, "help for %s", tbuf); xpa1 = XPANew(xclass, tbuf, tbuf2, send_cb, (void *)"send1", mode, receive_cb, (void *)"receive1", mode); if( xpa1 == NULL ){ fprintf(stderr, "ERROR: could not init xpa1\n"); } else{ fprintf(stdout, "%s using method: %s\n", xpa_name(xpa1), xpa_method(xpa1)); } if( !doone ){ snprintf(tbuf, SZ_LINE, "%s1", name); snprintf(tbuf2, SZ_LINE, "help for %s", tbuf); xpa1a = XPANew(xclass, tbuf, tbuf2, send_cb, (void *)"send1a", mode, receive_cb, (void *)"receive1a", mode); if( xpa1a == NULL ){ fprintf(stderr, "ERROR: could not init xpa1a\n"); } else{ fprintf(stdout, "%s using method: %s\n", xpa_name(xpa1a), xpa_method(xpa1a)); } snprintf(tbuf, SZ_LINE, "c_%s", name); xpa2 = XPACmdNew(xclass, tbuf); if( xpa2 == NULL ){ fprintf(stderr, "ERROR: could not init xpa2\n"); } else{ XPACmdAdd(xpa2, "cmd2", "and help for cmd2", send_cb, (void *)"cmd2", mode, receive_cb, (void *)"cmd2", mode); XPACmdAdd(xpa2, "cmd1 xx yy", "help for cmd1 xx yy", send_cb, (void *)"cmd1 xx yy", mode, receive_cb, (void *)"cmd1 xx yy", mode); XPACmdAdd(xpa2, "cmd1 xx", "help for cmd1 xx", send_cb, (void *)"cmd1 xx", mode, receive_cb, (void *)"cmd1 xx", mode); XPACmdAdd(xpa2, "cmd1", NULL, send_cb, (void *)"cmd1", mode, receive_cb, (void *)"cmd1", mode); fprintf(stdout, "%s using method: %s\n", xpa_name(xpa2), xpa_method(xpa2)); } snprintf(tbuf, SZ_LINE, "i_%s", name); xpa3 = XPAInfoNew(xclass, tbuf, info_cb, (void *)"info1", mode); if( xpa3 == NULL ){ fprintf(stderr, "ERROR: could not init xpa3\n"); } else{ fprintf(stdout, "%s using method: %s\n", xpa_name(xpa3), xpa_method(xpa3)); } } if( *cmd != '\0' ){ fprintf(stdout, "starting bkgd process: %s", cmd); system(cmd); } /* delay if necessary */ if( delay ){ fprintf(stdout, "starting delay of %d seconds ...", delay); XPASleep(delay*1000); fprintf(stdout, " done\n"); } fflush(stdout); fflush(stderr); /* connect to proxy, if necessary */ if( proxy ){ if( XPARemote(xpa1, proxy, "+", "proxy=true") < 0 ){ fprintf(stderr, "ERROR: could not connect to proxy: %s\n", proxy); } } if( x ){ #if HAVE_XT fprintf(stdout, "\nEntering Xt loop ...\n"); XPAXtAddInput(appcontext, NULL); XtRealizeWidget(top); XtAppMainLoop(appcontext); #else fprintf(stderr, "Xt is not available ...\n"); got = 1; goto done; #endif } else{ fprintf(stdout, "\nEntering select loop ...\n"); if( !doatexit ){ XPAMainLoop(); } else { while( !please_exit ) if( !XPAPoll(-1, 100) ) please_exit=1; } goto done; } done: if( !doatexit ){ XPAFree(xpa1); if( !doone ){ XPAFree(xpa1a); XPAFree(xpa2); XPAFree(xpa3); } } /* make valgrind happy */ XPACleanup(); if( save_buf ) xfree(save_buf); exit(got); } xpa-2.1.15/tcl.c0000644000054000000360000021522212052500020011701 0ustar erichead/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ #include #if HAVE_TCL #include /* *---------------------------------------------------------------------------- * * * Private Routines and Data * * *---------------------------------------------------------------------------- */ /* with Tcl 8.4, some function prototypes have added CONST qualifiers, which we try to deal with in a backward-compatible way */ #define XCONST84 #if TCL_MAJOR_VERSION >= 8 #if TCL_MINOR_VERSION >= 4 #undef XCONST84 #define XCONST84 CONST #endif #endif #ifdef NULLSTRING #undef NULLSTRING #endif #define NULLSTRING "" #define TCL_NULLSTR(s) (!s || !*s || !strcmp(s, "{}")) #define TY_CLIENT 1 #define TY_SERVER 2 #ifndef MAX_XPAS #define MAX_XPAS 10000 #endif /* * * record struct for client_data for XPATcl[Send,Receive,Info] routines * */ typedef struct xpatclclientdatarec{ Tcl_Interp *interp; char *callback; char *client_data; } *XPATclClientData, XPATclClientDataRec; /* *---------------------------------------------------------------------------- * * Routine: Tcl_GetXPAFromObj * * Purpose: convert string to XPA handle * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int Tcl_GetXPAFromObj(Tcl_Interp *interp, Tcl_Obj *obj, int flag, XPA *xpa) #else static int Tcl_GetXPAFromObj(interp, obj, flag, xpa) Tcl_Interp *interp; Tcl_Obj *obj; int flag; XPA *xpa; #endif { char *s; void *lval; Tcl_Obj *resultPtr; /* get result pointer */ resultPtr = Tcl_GetObjResult(interp); if( (s = Tcl_GetStringFromObj(obj, NULL)) == NULL ){ return(TCL_ERROR); } if( strncmp(s, "xpa_", 4) || (sscanf(&(s[4]), "%p", &lval) != 1) ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa handle", -1); return(TCL_ERROR); } *xpa = (XPA)lval; /* make sure its a valid xpa */ switch(flag){ case TY_CLIENT: if( !XPAClientValid(*xpa) ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); return(TCL_ERROR); } break; case TY_SERVER: if( !XPAValid(*xpa) ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa server handle", -1); return(TCL_ERROR); } break; } return(TCL_OK); } /* *---------------------------------------------------------------------------- * * Routine: XPATclHandler * * Purpose: common handler for access points written in tcl * execute the tcl receive command with xpa arguments * used instead of Tcl_Eval so we can avoid interpreting either * paramlist or buf * * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPATclHandler (void *client_data, void *call_data, char *paramlist, char *buf, int len, int nargs) #else static int XPATclHandler(client_data, call_data, paramlist, buf, len, nargs) void *client_data; void *call_data; char *paramlist; char *buf; int len; int nargs; #endif { XPA xpa = (XPA)call_data; XPATclClientData xptr = (XPATclClientData)client_data; Tcl_CmdInfo info; /* Info about command procedures */ Tcl_Obj *objv[10]; /* Object vector for arguments */ Tcl_Obj *resultPtr; /* The result object */ int result; /* TCL_OK or TCL_ERROR */ int object; char tbuf[SZ_LINE]; XCONST84 char *argv[10]; char *s=NULL; char *t=NULL; char *cmd; /* make sure we have a callback */ if( !xptr || !xptr->callback ){ XPAError(xpa, "Invalid tcl command for xpa callback"); return(-1); } /* set command name */ cmd = xptr->callback; /* Map from the command name to a C procedure */ if( !Tcl_GetCommandInfo(xptr->interp, cmd, &info) ){ XPAError(xpa, "Unknown tcl command for xpa callback"); return(-1); } /* string-ize some values */ snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); s = xstrdup(tbuf); if( nargs > 4 ){ snprintf(tbuf, SZ_LINE, "%d", len); t = xstrdup(tbuf); } /* package up argument values */ object = info.isNativeObjectProc; if (object) { /* The object interface is preferred for this command */ objv[0] = Tcl_NewStringObj(cmd, strlen(cmd)); objv[1] = Tcl_NewStringObj(s, strlen(s)); if( (xptr->client_data == NULL) || (*xptr->client_data == '\0') ) objv[2] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); else objv[2] = Tcl_NewStringObj(xptr->client_data, strlen(xptr->client_data)); if( (paramlist == NULL) || (*paramlist == '\0') ) objv[3] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); else objv[3] = Tcl_NewStringObj(paramlist, strlen(paramlist)); if( nargs > 4 ){ if( (buf == NULL) || (*buf == '\0') || (len == 0) ) objv[4] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); else objv[4] = Tcl_NewStringObj(buf, len); objv[5] = Tcl_NewStringObj(t, strlen(t)); } } else { argv[0] = cmd; argv[1] = s; argv[2] = xptr->client_data; argv[3] = paramlist; if( nargs > 4 ){ argv[4] = buf; argv[5] = t; } } /* reset before we make C call */ Tcl_ResetResult(xptr->interp); /* * Invoke the C procedure. */ if (object) { result = (*info.objProc)(info.objClientData, xptr->interp, nargs, objv); /* Get the string value from the result object */ resultPtr = Tcl_GetObjResult(xptr->interp); Tcl_SetResult(xptr->interp, Tcl_GetStringFromObj(resultPtr, NULL), TCL_VOLATILE); } else { result = (*info.proc)(info.clientData, xptr->interp, nargs, argv); } /* clean up */ if( s ) xfree(s); if( t ) xfree(t); /* translate Tcl status into XPA status */ if( result == TCL_OK ){ return(0); } else{ s = (char *)Tcl_GetStringResult(xptr->interp); if( !strncmp(s, "XPA$ERROR: ", 11) ) s += 11; XPAError(xpa, s); return(-1); } } /* *---------------------------------------------------------------------------- * * Routine: XPATclReceive * * Purpose: receive handler for access points written in tcl * execute the tcl receive command with xpa arguments * used instead of Tcl_Eval so we can avoid interpreting either * paramlist or buf * * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPATclReceive (void *client_data, void *call_data, char *paramlist, char *buf, int len) #else static int XPATclReceive(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char *buf; int len; #endif { return(XPATclHandler(client_data, call_data, paramlist, buf, len, 6)); } /* *---------------------------------------------------------------------------- * * Routine: XPATclSend * * Purpose: send handler for access points written in tcl * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPATclSend (void *client_data, void *call_data, char *paramlist, char **buf, int *len) #else static int XPATclSend(client_data, call_data, paramlist, buf, len) void *client_data; void *call_data; char *paramlist; char **buf; int *len; #endif { return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); } /* *---------------------------------------------------------------------------- * * Routine: XPATclInfo * * Purpose: info handler for access points written in tcl * * Returns: 0 on success, -1 on failure * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPATclInfo (void *client_data, void *call_data, char *paramlist) #else static int XPATclInfo(client_data, call_data, paramlist) void *client_data; void *call_data; char *paramlist; #endif { return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); } /* *---------------------------------------------------------------------------- * * Routine: XPANew_Tcl * * Purpose: Tcl binding to XPANew procedure * * Tcl call: * * xpanew class name help sproc sdata smode rproc rdata rmode * * use the empty string to specify NULL arguments * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPANew_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPANew_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { char *xclass; char *name; char *help; char *send_cb; char *sdata; char *smode; char *rec_cb; char *rdata; char *rmode; char tbuf[SZ_LINE]; XPA xpa; SendCb sproc; ReceiveCb rproc; XPATclClientData sptr; XPATclClientData rptr; Tcl_Obj *resultPtr; /* make sure argument count is correct */ if( objc != 10 ){ Tcl_WrongNumArgs(interp, 1, objv, "class name help sproc sdata smode rproc rdata rmode"); return(TCL_ERROR); } /* get arguments as strings */ xclass = Tcl_GetStringFromObj(objv[1], NULL); name = Tcl_GetStringFromObj(objv[2], NULL); help = Tcl_GetStringFromObj(objv[3], NULL); send_cb = Tcl_GetStringFromObj(objv[4], NULL); sdata = Tcl_GetStringFromObj(objv[5], NULL); smode = Tcl_GetStringFromObj(objv[6], NULL); rec_cb = Tcl_GetStringFromObj(objv[7], NULL); rdata = Tcl_GetStringFromObj(objv[8], NULL); rmode = Tcl_GetStringFromObj(objv[9], NULL); /* this will hold the result */ resultPtr = Tcl_GetObjResult(interp); /* set up callback procedures */ if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ sproc = NULL; sptr = NULL; } else{ sproc = XPATclSend; sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); sptr->interp = interp; sptr->callback = xstrdup(send_cb); sptr->client_data = xstrdup(sdata); } if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ rproc = NULL; rptr = NULL; } else{ rproc = XPATclReceive; rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); rptr->interp = interp; rptr->callback = xstrdup(rec_cb); rptr->client_data = xstrdup(rdata); } /* make sure we have either a send or receive callback */ if( !sproc && !rproc ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: xpanew requires send_cb or rec_cb (or both)", -1); return(TCL_ERROR); } /* set up the tcl handler for the xpa access point */ xpa = XPANew(xclass, name, help, sproc, sptr, smode, rproc, rptr, rmode); if( xpa == NULL ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA access point", -1); return(TCL_ERROR); } else{ /* add this xpa to the Tcl event loop */ XPATclAddInput(xpa); /* return xpa address to tcl in a string */ snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); Tcl_SetStringObj(resultPtr, tbuf, -1); return(TCL_OK); } } /* *---------------------------------------------------------------------------- * * Routine: XPAFree_Tcl * * Purpose: Tcl binding to XPAFree procedure * * Tcl call: * * xpafree xpa * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAFree_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPAFree_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { XPA xpa; XPATclClientData ptr; /* make sure argument count is correct */ if( objc != 2 ){ Tcl_WrongNumArgs(interp, 1, objv, "xpa"); return(TCL_ERROR); } /* get xpa, which is always arg 1 */ if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ return(TCL_ERROR); } /* reset error/result condition */ Tcl_ResetResult(interp); /* free the associated tcl record, stored in the client data */ if( xpa->send_data ){ ptr = (XPATclClientData)xpa->send_data; if( ptr->callback ) xfree( ptr->callback); if( ptr->client_data ) xfree( ptr->client_data); xfree(xpa->send_data); } if( xpa->receive_data ){ ptr = (XPATclClientData)xpa->receive_data; if( ptr->callback ) xfree( ptr->callback); if( ptr->client_data ) xfree( ptr->client_data); xfree(xpa->receive_data); } if( xpa->info_data ){ ptr = (XPATclClientData)xpa->info_data; if( ptr->callback ) xfree( ptr->callback); if( ptr->client_data ) xfree( ptr->client_data); xfree(xpa->info_data); } /* call the XPAFree routine */ XPAFree(xpa); return(TCL_OK); } /* *---------------------------------------------------------------------------- * * Routine: XPAInfoNew_Tcl * * Purpose: Tcl binding to XPAInfoNew procedure * * Tcl call: * * xpanew class name help iproc idata imode * * use the empty string to specify NULL arguments * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPAInfoNew_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPAInfoNew_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { char *xclass; char *name; char *info_cb; char *idata; char *imode; char tbuf[SZ_LINE]; XPA xpa; InfoCb iproc; XPATclClientData iptr; Tcl_Obj *resultPtr; /* make sure argument count is correct */ if( objc != 6 ){ Tcl_WrongNumArgs(interp, 1, objv, "class name iproc idata imode"); return(TCL_ERROR); } /* get arguments as strings */ xclass = Tcl_GetStringFromObj(objv[1], NULL); name = Tcl_GetStringFromObj(objv[2], NULL); info_cb = Tcl_GetStringFromObj(objv[3], NULL); idata = Tcl_GetStringFromObj(objv[4], NULL); imode = Tcl_GetStringFromObj(objv[5], NULL); /* this will hold the result */ resultPtr = Tcl_GetObjResult(interp); /* set up callback procedures */ if( info_cb == NULL ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: xpainfonew requires info_cb", -1); return(TCL_ERROR); } else{ iproc = XPATclInfo; iptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); iptr->interp = interp; iptr->callback = xstrdup(info_cb); iptr->client_data = xstrdup(idata); } /* set up the tcl handler for the xpa access point */ xpa = XPAInfoNew(xclass, name, iproc, iptr, imode); if( xpa == NULL ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA info access point", -1); return(TCL_ERROR); } else{ /* add this xpa to the Tcl event loop */ XPATclAddInput(xpa); /* return xpa address to tcl in a string */ snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); Tcl_SetStringObj(resultPtr, tbuf, -1); return(TCL_OK); } } /* *---------------------------------------------------------------------------- * * Routine: XPACmdNew_Tcl * * Purpose: Tcl binding to XPACmdNew procedure * * Tcl call: * * xpacmdnew class name * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPACmdNew_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPACmdNew_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { char *xclass; char *name; char tbuf[SZ_LINE]; XPA xpa; Tcl_Obj *resultPtr; /* make sure argument count is correct */ if( objc != 3 ){ Tcl_WrongNumArgs(interp, 1, objv, "class name"); return(TCL_ERROR); } /* get arguments as strings */ xclass = Tcl_GetStringFromObj(objv[1], NULL); name = Tcl_GetStringFromObj(objv[2], NULL); /* this will hold the result */ resultPtr = Tcl_GetObjResult(interp); /* set up the tcl handler for the xpa access point */ if( (xpa = XPACmdNew(xclass, name)) == NULL ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA command access point", -1); return(TCL_ERROR); } else{ /* add this xpa to the Tcl event loop */ XPATclAddInput(xpa); /* return xpa address to tcl in a string */ snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); Tcl_SetStringObj(resultPtr, tbuf, -1); return(TCL_OK); } } /* *---------------------------------------------------------------------------- * * Routine: XPACmdAdd_Tcl * * Purpose: Tcl binding to XPACmdAdd procedure * * Tcl call: * * xpacmdadd xpa name help sproc sdata smode rproc rdata rmode * * use the empty string to specify NULL arguments * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPACmdAdd_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPACmdAdd_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { char *name; char *help; char *send_cb; char *sdata; char *smode; char *rec_cb; char *rdata; char *rmode; char tbuf[SZ_LINE]; XPA xpa; XPACmd xpacmd; SendCb sproc; ReceiveCb rproc; XPATclClientData sptr; XPATclClientData rptr; Tcl_Obj *resultPtr; /* make sure argument count is correct */ if( objc != 10 ){ Tcl_WrongNumArgs(interp, 1, objv, "class name help sproc sdata smode rproc rdata rmode"); return(TCL_ERROR); } /* get xpa, which is always arg 1 */ if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ return(TCL_ERROR); } name = Tcl_GetStringFromObj(objv[2], NULL); help = Tcl_GetStringFromObj(objv[3], NULL); send_cb = Tcl_GetStringFromObj(objv[4], NULL); sdata = Tcl_GetStringFromObj(objv[5], NULL); smode = Tcl_GetStringFromObj(objv[6], NULL); rec_cb = Tcl_GetStringFromObj(objv[7], NULL); rdata = Tcl_GetStringFromObj(objv[8], NULL); rmode = Tcl_GetStringFromObj(objv[9], NULL); /* this will hold the result */ resultPtr = Tcl_GetObjResult(interp); /* set up callback procedures */ if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ sproc = NULL; sptr = NULL; } else{ sproc = XPATclSend; sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); sptr->interp = interp; sptr->callback = xstrdup(send_cb); sptr->client_data = xstrdup(sdata); } if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ rproc = NULL; rptr = NULL; } else{ rproc = XPATclReceive; rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); rptr->interp = interp; rptr->callback = xstrdup(rec_cb); rptr->client_data = xstrdup(rdata); } /* make sure we have either a send or receive callback */ if( !sproc && !rproc ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: xpacmdadd requires send_cb or rec_cb (or both)", -1); return(TCL_ERROR); } /* set up the tcl handler for the xpa access point */ xpacmd = XPACmdAdd(xpa, name, help, sproc, sptr, smode, rproc, rptr, rmode); if( xpacmd == NULL ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA command", -1); return(TCL_ERROR); } else{ /* return xpa address to tcl in a string */ snprintf(tbuf, SZ_LINE, "xpacmd_%p", xpacmd); Tcl_SetStringObj(resultPtr, tbuf, -1); return(TCL_OK); } } /* *---------------------------------------------------------------------------- * * Routine: XPACmdDel_Tcl * * Purpose: Tcl binding to XPACmdDel procedure * * Tcl call: * * xpacmddel xpa cmd * * Returns: Tcl error code * *---------------------------------------------------------------------------- */ #ifdef ANSI_FUNC static int XPACmdDel_Tcl(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) #else static int XPACmdDel_Tcl(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; #endif { void *lval; char *s; XPA xpa; XPACmd cmd; Tcl_Obj *resultPtr; /* make sure argument count is correct */ if( objc != 3 ){ Tcl_WrongNumArgs(interp, 1, objv, "xpa cmd"); return(TCL_ERROR); } /* get result pointer */ resultPtr = Tcl_GetObjResult(interp); /* get xpa, which is always arg 1 */ if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ return(TCL_ERROR); } /* get xpacmd, which is always arg 2 */ if( (s = Tcl_GetStringFromObj(objv[2], NULL)) == NULL ){ return(TCL_ERROR); } if( strncmp(s, "xpacmd_", 7) || (sscanf(&(s[7]), "%p", &lval) != 1) ){ Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpacmd handle", -1); return(TCL_ERROR); } cmd = (XPACmd)lval; /* reset error/result condition */ Tcl_ResetResult(interp); /* call the XPACmdDel routine */ if( XPACmdDel(xpa, cmd) == 0 ){ /* free the associated tcl record, stored in the client data */ if( cmd->send_data ) xfree(cmd->send_data); if( cmd->receive_data ) xfree(cmd->receive_data); return(TCL_OK); } else{ resultPtr = Tcl_GetObjResult(interp); Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not delete xpa cmd", -1); return(TCL_ERROR); } } /* *---------------------------------------------------------------------------- * * Routine: XPARec_Tcl * * Purpose: Tcl binding to retrieve info from the xpa struct * * Tcl call: * * set val [xparec xpa