/* $XConsortium: Xtransam.c,v 1.4 94/04/17 20:23:01 mor Exp $ */ /* $XFree86: xc/lib/xtrans/Xtransam.c,v 3.1 1996/05/10 06:55:45 dawes Exp $ */ /* Copyright (c) 1994 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* Copyright (c) 1994 Vrije Universiteit Amsterdam, Netherlands * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name Vrije Universiteit not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The Vrije Universiteit * makes no representations about the suitability of this software for * any purpose. It is provided "as is" without express or implied warranty. * * THE VRIJE UNIVERSITEIT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL THE VRIJE UNIVERSITEIT BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This is the Amoeba implementation of the X Transport service layer */ #define event am_event_t #define interval am_interval_t #define port am_port_t #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef event #undef interval #undef port extern char *strdup(); /* a new family for Amoeba RPC connections */ #define AF_AMOEBA 33 #define FamilyAmoeba 33 #define MAX_TCPIP_RETRY 4 #define CIRCBUFSIZE 4096 /* was 1024 */ /* * Amoeba channel description: */ typedef struct _XAmChanDesc { int state; /* current state of connection */ int type; /* type of connection */ int status; /* status used by server */ signum signal; /* signal to kill TCP/IP reader */ semaphore *sema; /* select semaphore */ struct vc *virtcirc; /* virtual circuit for Amoeba RPC */ struct circbuf *circbuf; /* circular buffer for TCP/IP */ capability chancap; /* TCP/IP channel capability */ XtransConnInfo conninfo; /* back pointer to the connect info */ } XAmChanDesc; /* Amoeba channel descriptor states */ #define ACDS_FREE 0 /* unused */ #define ACDS_USED 1 /* intermediate state */ #define ACDS_CLOSED 2 /* just closed */ /* Amoeba channel types */ #define ACDT_TCPIP 1 /* TCP/IP connection */ #define ACDT_VIRTCIRC 2 /* Amoeba virtual circuit connection */ #ifdef XSERV_t #include "dix.h" /* clients[] needed by AmFindReadyClients */ #define Error(list) ErrorF list #define Fatal(list) FatalError list #else #define Error(list) printf list #define Fatal(list) { printf list; exit(1); } #endif #define dbprintf(list) /* printf list */ #define doprintf(list) printf list /**/ /* * First: utility functions. */ #if defined(XSERV_t) || defined(FS_t) static semaphore main_sema; /* The X-server consists of one main thread, running the non re-entrant * X code, and a number of auxilary threads that take care of reading * the input streams, and input devices. The following set of routines * wake up the main thread when it has something to do. */ void InitMainThread() { sema_init(&main_sema, 0); } void WakeUpMainThread() { sema_up(&main_sema); } int SleepMainThread(timeout) am_interval_t timeout; { dbprintf(("Sleeping main thread timeout %d\n", timeout)); return (sema_trydown(&main_sema, timeout) == 0) ? 0 : -1; } static int init_waiters; static semaphore init_sema; void AmInitWaitFor() { init_waiters = 0; sema_init(&init_sema, 0); } /* * Force caller thread to wait until main has finished the initialization. */ void WaitForInitialization() { init_waiters++; dbprintf(("Waiting for initialization (%d)\n", init_waiters)); sema_down(&init_sema); } void WakeupInitWaiters() { /* wakeup threads in initial sleep */ if (init_waiters > 0) { dbprintf(("%d waiters wait for something ...\n", init_waiters)); while (init_waiters-- > 0) { sema_up(&init_sema); } } } #endif /* XSERV_t || FS_t */ #define THREAD_STACK_SIZE (8*1024) /* * Amoeba connection information is stored in, so called, * channel descriptors. Channel descriptors are identified * by their index in the table below. */ static XAmChanDesc XAmChanDescriptors[OPEN_MAX]; static void XAmCleanUpChanDesc(); /* forward */ /* * Cleanup connection descriptors on a signal */ static void XAmSignalCleanUpChanDesc(sig) int sig; { XAmCleanUpChanDesc(); _exit(sig | 0x80); } /* * Cleanup connection descriptors */ static void XAmCleanUpChanDesc() { register int i; for (i = 0; i < OPEN_MAX; i++) { switch (XAmChanDescriptors[i].type) { case ACDT_TCPIP: /* The Amoeba TCP/IP server is capability based, i.e. * it uses capabilities to identify connections. Since a * capability is only destroyed when it has aged too much * or is explicitly deleted, the connection it identifies * will tend to exist for some while even if the client is * already gone. To force connections to close this loop * destroys all open TCP/IP connection. This loop us auto- * matically executed when exit() is called. */ std_destroy(&XAmChanDescriptors[i].chancap); break; case ACDT_VIRTCIRC: /* Close the virtual circuit asynchronously, or otherwise * we may hang for a minute under some (?) conditions. */ vc_close(XAmChanDescriptors[i].virtcirc, VC_BOTH | VC_ASYNC); break; } XAmChanDescriptors[i].state = ACDS_FREE; } } /* * Allocate a channel descriptor */ static XAmChanDesc * XAmAllocChanDesc() { register int i; #ifndef XSERV_t static int initialized = 0; /* * Since the TCP/IP server is capability based its connections exists * even if the owner process is long gone. To overcome this nuisance, * a sweep is made over the connection descriptors when exit() is * called or when an un-catched (by application program) signal is * received. */ if (!initialized) { initialized = 1; atexit(XAmCleanUpChanDesc); if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, XAmSignalCleanUpChanDesc); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, XAmSignalCleanUpChanDesc); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, XAmSignalCleanUpChanDesc); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, XAmSignalCleanUpChanDesc); } #endif for (i = 0; i < OPEN_MAX; i++) { if (XAmChanDescriptors[i].state == ACDS_FREE) { XAmChanDescriptors[i].state = ACDS_USED; XAmChanDescriptors[i].conninfo = NULL; return &XAmChanDescriptors[i]; } } return NULL; } /* * Convert ``file descriptor'' to channel descriptor */ static XAmChanDesc * XAmFdToChanDesc(fd) int fd; { if (fd >= 0 && fd < OPEN_MAX) { return &XAmChanDescriptors[fd]; } else { return NULL; } } /* * Convert channel descriptor to ``file descriptor'' */ static int XAmChanDescToFd(chandesc) XAmChanDesc *chandesc; { return chandesc - XAmChanDescriptors; } /* * Free channel descriptor */ static void XAmFreeChanDesc(chandesc) XAmChanDesc *chandesc; { if (chandesc->sema) { xfree(chandesc->sema); chandesc->sema = NULL; } chandesc->state = ACDS_FREE; } static void XAmReaderThread(); static int MakeAmConnection(phostname, idisplay, familyp, saddrlenp, saddrp) char *phostname; int idisplay; int *familyp; /* RETURN */ int *saddrlenp; /* RETURN */ char **saddrp; /* RETURN */ { capability xservercap; char xserverpath[256]; XAmChanDesc *chandesc; errstat err; /* Amoeba requires a server hostname */ if (phostname == NULL || *phostname == '\0') { fprintf(stderr, "MakeAmConnection: Display name expected\n"); return -1; } /* allocate channel descriptor */ chandesc = XAmAllocChanDesc(); if (chandesc == NULL) { fprintf(stderr, "MakeAmConnection: Out of channel capabilities\n"); return -1; } /* * There are two possible way to make a connection on Amoeba. Either * through an Amoeba RPC or a TCP/IP connection. Depending on whether * the X server resides on Amoeba, Amoeba RPC's are used. Otherwise * it uses a TCP/IP connection. */ (void)sprintf(xserverpath, "%s/%s:%d", DEF_XSVRDIR, phostname, idisplay); if ((err = name_lookup(xserverpath, &xservercap)) == STD_OK) { am_port_t vccaps[2]; bufsize size; errstat err; header hdr; /* Amoeba virtual circuit connection */ chandesc->type = ACDT_VIRTCIRC; /* get the two connection ports from the X-server */ hdr.h_command = AX_CONNECT; hdr.h_port = xservercap.cap_port; hdr.h_priv = xservercap.cap_priv; size = trans(&hdr, NILBUF, 0, &hdr, (char *)vccaps, sizeof(vccaps)); if (ERR_STATUS(size)) { err = ERR_CONVERT(size); } else { err = ERR_CONVERT(hdr.h_status); } if (err != STD_OK || size != sizeof(vccaps)) { fprintf(stderr, "Xlib: connect to Amoeba X-server failed (%s)\n", err_why(err)); XAmFreeChanDesc(chandesc); return -1; } /* setup an Amoeba virtual circuit */ chandesc->virtcirc = vc_create(&vccaps[1], &vccaps[0], MAXBUFSIZE, MAXBUFSIZE); if (chandesc->virtcirc == (struct vc *)NULL) { fprintf(stderr, "Xlib: Amoeba virtual circuit create failed\n"); XAmFreeChanDesc(chandesc); return -1; } /* Special Amoeba family type. For Amoeba no additional access control * mechanism exists; when you have the server capability, you have * the access. Just use a fake address. */ *familyp = AF_AMOEBA; *saddrp = strdup("Amoeba"); *saddrlenp = strlen(*saddrp); } else { char tcpname[256]; capability tcpcap; ipaddr_t ipaddr; char *tcpsvr; nwio_tcpcl_t tcpcl; nwio_tcpconf_t tcpconf; XAmChanDesc **param; int result; /* Amoeba TCP/IP connection */ chandesc->type = ACDT_TCPIP; /* lookup up TCP/IP server */ if ((tcpsvr = getenv("TCP_SERVER")) == NULL) { tcpsvr = TCP_SVR_NAME; } if ((err = name_lookup(tcpsvr, &tcpcap)) != STD_OK) { fprintf(stderr, "Xlib: Cannot lookup %s (%s)\n", tcpsvr, err_why(err)); std_destroy(&chandesc->chancap); XAmFreeChanDesc(chandesc); return -1; } /* establish TCP/IP connection */ if ((err = tcpip_open(&tcpcap, &chandesc->chancap)) != STD_OK) { fprintf(stderr, "Xlib: Cannot open TCP/IP server on %s (%s)\n", tcpsvr, tcpip_why(err)); std_destroy(&chandesc->chancap); XAmFreeChanDesc(chandesc); return -1; } /* lookup TCP/IP hostname */ if (isdigit(phostname[0])) { ipaddr = inet_addr(phostname); } else { struct hostent *hp = gethostbyname(phostname); if (hp == NULL) { fprintf(stderr, "Xlib: %s unknown host\n", phostname); return -1; } memcpy(&ipaddr, hp->h_addr, hp->h_length); } /* set remote address/port on the TCP/IP connection */ tcpconf.nwtc_flags = NWTC_SET_RA|NWTC_SET_RP|NWTC_LP_SEL; tcpconf.nwtc_remaddr = ipaddr; tcpconf.nwtc_remport = htons(6000+idisplay); if ((err = tcp_ioc_setconf(&chandesc->chancap, &tcpconf)) != STD_OK) { fprintf(stderr, "Xlib: Cannot configure TCP/IP server (%s)\n", tcpip_why(err)); std_destroy(&chandesc->chancap); XAmFreeChanDesc(chandesc); return -1; } /* make the actual TCP/IP connection */ tcpcl.nwtcl_flags = 0; if ((err = tcp_ioc_connect(&chandesc->chancap, &tcpcl)) != STD_OK) { fprintf(stderr, "Xlib: Cannot make TCP/IP connection (%s)\n", tcpip_why(err)); std_destroy(&chandesc->chancap); XAmFreeChanDesc(chandesc); return -1; } /* start TCP/IP reader thread */ chandesc->signal = sig_uniq(); chandesc->circbuf = cb_alloc(CIRCBUFSIZE); param = (XAmChanDesc **) xalloc(sizeof(XAmChanDesc *)); /* error checking? */ *param = chandesc; result = thread_newthread(XAmReaderThread, THREAD_STACK_SIZE, (char *)param, sizeof(XAmChanDesc *)); if (result == 0) { fprintf(stderr, "Xlib: Cannot start reader thread\n"); std_destroy(&chandesc->chancap); XAmFreeChanDesc(chandesc); return -1; } threadswitch(); /* give reader a try */ /* * Family type is set to Internet so that the .Xauthority * files from Unix will work under Amoeba (for Unix displays). */ *familyp = AF_INET; *saddrlenp = sizeof(ipaddr_t); *saddrp = xalloc(sizeof(ipaddr_t)); memcpy(*saddrp, (char *)&ipaddr, sizeof(ipaddr_t)); /* error checking? */ } return XAmChanDescToFd(chandesc); } /* * The TCP/IP server silently assumes a maximum buffer size of 30000 bytes. */ #define TCPIP_BUFSIZE 16384 static void XAMCloseChannel(chandesc) XAmChanDesc *chandesc; { if (chandesc->state == ACDS_USED && chandesc->type == ACDT_TCPIP) { cb_close(chandesc->circbuf); chandesc->state = ACDS_CLOSED; } } /* * Shutdown TCP/IP reader thread */ static void XAmReaderSignalCatcher(sig, us, extra) signum sig; thread_ustate *us; _VOIDSTAR extra; { register XAmChanDesc *chandesc = (XAmChanDesc *)extra; XAMCloseChannel(chandesc); thread_exit(); } /* * TCP/IP reader thread */ static void XAmReaderThread(argptr, argsize) void *argptr; int argsize; { register XAmChanDesc *chandesc; chandesc = *((XAmChanDesc **)argptr); (void) sig_catch(chandesc->signal, XAmReaderSignalCatcher, (_VOIDSTAR) chandesc); while (chandesc->state == ACDS_USED) { char buffer[CIRCBUFSIZE]; bufsize size; size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer)); if (ERR_STATUS(size) || size == 0) { if (size == 0) { static char msg[] = "Xlib: TCP/IP channel closed\n"; write(2, msg, sizeof(msg)); } else { fprintf(stderr, "Xlib: TCP/IP read failed (%s)\n", err_why(ERR_CONVERT(size))); } XAMCloseChannel(chandesc); break; } if (cb_puts(chandesc->circbuf, buffer, size) != 0) { fprintf(stderr, "Xlib: short write to circular buffer\n"); XAMCloseChannel(chandesc); } } thread_exit(); } /* * Wait until input is available or until the timer expires. */ int TRANS(AmSelect)(ifd, timout) int ifd; int timout; { XAmChanDesc *chandesc; int n; errno = 0; chandesc = XAmFdToChanDesc(ifd); if (chandesc == NULL || chandesc->state != ACDS_USED) { errno = EBADF; return -1; } if (chandesc->sema == NULL) { /* Allocate semaphore to sleep on when no data is * available. The underlying circular buffer and * virtual circuit packages manage this semaphore. */ chandesc->sema = (semaphore *) xalloc(sizeof(semaphore)); if (chandesc->sema == NULL) { errno = ENOMEM; return -1; } sema_init(chandesc->sema, 0); switch (chandesc->type) { case ACDT_TCPIP: cb_setsema(chandesc->circbuf, chandesc->sema); break; case ACDT_VIRTCIRC: vc_setsema(chandesc->virtcirc, chandesc->sema); break; } } switch (chandesc->type) { case ACDT_TCPIP: if ((n = cb_full(chandesc->circbuf)) != 0) { if (n < 0) errno = EPIPE; return n; /* includes error as well */ } if (sema_trydown(chandesc->sema, timout) < 0) { errno = EINTR; return -1; } else { /* we down for all the bytes in AMRead, so undo the down */ sema_up(chandesc->sema); } if ((n = cb_full(chandesc->circbuf)) < 0) { errno = EPIPE; return -1; } return n; case ACDT_VIRTCIRC: if ((n = vc_avail(chandesc->virtcirc, VC_IN)) != 0) { if (n < 0) errno = EPIPE; return n; /* includes error as well */ } if (sema_trydown(chandesc->sema, timout) < 0) { errno = EINTR; return -1; } else { /* we down for all the bytes in AMRead, so undo the down */ sema_up(chandesc->sema); } if ((n = vc_avail(chandesc->virtcirc, VC_IN)) < 0) { errno = EPIPE; return -1; } return n; } errno = EINVAL; return -1; } /* * This function gets the local address of the transport and stores it in the * XtransConnInfo structure for the connection. */ static int TRANS(AMGetAddr)(ciptr) XtransConnInfo ciptr; { PRMSG(1,"AMGetAddr(%x)\n", ciptr, 0,0 ); PRMSG(1,"AMGetAddr: TODO\n", 0, 0, 0); return -1; } /* * This function gets the remote address of the socket and stores it in the * XtransConnInfo structure for the connection. */ static int TRANS(AMGetPeerAddr)(ciptr) XtransConnInfo ciptr; { struct nwio_tcpconf tcpconf; errstat err; XAmChanDesc *chandesc; PRMSG(2,"AMGetPeerAddr(%x)\n", ciptr, 0,0 ); chandesc = XAmFdToChanDesc(ciptr->fd); if (chandesc == NULL || chandesc->state != ACDS_USED) { errno = EBADF; return -1; } switch (chandesc->type) { case ACDT_TCPIP: /* get the remote adress from the TCP/IP server */ if ((err = tcp_ioc_getconf(&chandesc->chancap, &tcpconf)) != STD_OK) { PRMSG (1, "AMGetPeerAddr: Cannot get remote address (%d)\n", (int) err, 0, 0); return -1; } #if 0 /* debug */ { struct hostent *remote; char *hostname; remote = gethostbyaddr((char *) &tcpconf.nwtc_remaddr, sizeof(tcpconf.nwtc_remaddr), AF_INET); if ((remote == NULL) || (remote->h_name == NULL)) { hostname = inet_ntoa(tcpconf.nwtc_remaddr); } else { hostname = remote->h_name; } PRMSG (1, "AMGetPeerAddr: remote addr `%s'\n", hostname, 0, 0); } #endif ciptr->peeraddrlen = sizeof(tcpconf.nwtc_remaddr); ciptr->peeraddr = (char *) xalloc (ciptr->peeraddrlen); if (ciptr->peeraddr == NULL) { PRMSG (1, "AMGetPeerAddr: Can't allocate peeraddr\n", 0, 0, 0); return -1; } memcpy (ciptr->peeraddr, &tcpconf.nwtc_remaddr, ciptr->peeraddrlen); break; case ACDT_VIRTCIRC: /* for Amoeba virtual circuits just copy the client address */ if ((ciptr->peeraddr = (char *) xalloc (ciptr->addrlen)) == NULL) { PRMSG (1, "AMGetPeerAddr: Can't allocate peeraddr\n", 0, 0, 0); return -1; } ciptr->peeraddrlen = ciptr->addrlen; memcpy (ciptr->peeraddr, ciptr->addr, ciptr->peeraddrlen); break; } return 0; } static XtransConnInfo TRANS(AMOpen)(device) char *device; { PRMSG(1,"AMOpen(%s)\n", device, 0,0 ); PRMSG(1,"AMOpen: TODO\n", 0, 0, 0); return NULL; } static int TRANS(AMAddrToNetbuf)(tlifamily, host, port, netbufp) int tlifamily; char *host; char *port; struct netbuf *netbufp; { PRMSG(1,"AMAddrToNetbuf(%d,%s,%s)\n", tlifamily, host, port ); PRMSG(1,"AMAddrToNetbuf: TODO\n", 0, 0, 0); return -1; } /* * These functions are the interface supplied in the Xtransport structure */ #ifdef TRANS_CLIENT static XtransConnInfo TRANS(AMOpenCOTSClient)(thistrans, protocol, host, port) Xtransport *thistrans; char *protocol; char *host; char *port; { XtransConnInfo ciptr; XAmChanDesc *chandesc; PRMSG(2,"AMOpenCOTSClient(%s,%s,%s)\n", protocol, host, port ); ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo)); if (ciptr == NULL) { PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0); return NULL; } ciptr->fd = MakeAmConnection (host, 0 /* TODO */, &ciptr->family, &ciptr->addrlen, &ciptr->addr); if (ciptr->fd < 0) { PRMSG(1,"AMOpenCOTSClient: Unable to make connection to %s\n", host, 0,0 ); xfree(ciptr); return NULL; } /* set the back pointer */ chandesc = XAmFdToChanDesc(ciptr->fd); chandesc->conninfo = ciptr; TRANS(AMGetPeerAddr)(ciptr); PRMSG(2,"AMOpenCOTSClient: made connection to %s; fd = %d, family = %d\n", host, ciptr->fd, ciptr->family); return ciptr; } #endif /* TRANS_CLIENT */ #if defined(XSERV_t) || defined(FS_t) /* The following defines come from osdep.h; * they should removed from there eventually. */ /* * Some fundamental constants */ #define CONNECTOR_STACK 4000 /* stack for connector task */ #define DEVREADER_STACK 4000 /* stack for device reader */ #define CREATOR_STACK 4000 /* stack for connection creator */ #define MAXTASKS 100 /* Maximum # clients */ /* * OsComm status bits */ #define CONN_KILLED 0x1 /* Connection being closed */ #define REQ_PUSHBACK 0x2 /* Request pushed back */ #define IGNORE 0x4 /* True if client ignored */ #define CONN_INIT 0x8 /* True if still initializing */ #define CONN_ALIVE 0x10 /* True if living */ #define REPLY_BUFSIZE 30000 capability X; /* X capability */ char *XServerHostName; /* X server host name */ char *XTcpServerName; /* TCP/IP server name */ static XtransConnInfo NewConns[MAXTASKS]; /* new client connections */ int nNewConns; /* # of new clients */ int maxClient; /* Highest allocated client fd + 1*/ static int minClient = 1; /* Lowest allocated client fd */ static char * OsCommStatus(status) int status; { static char buf[100]; buf[0] = '\0'; if (status == 0) sprintf(buf, "NONE"); if (status & CONN_INIT) sprintf(buf, "%s INIT", buf); if (status & CONN_ALIVE) sprintf(buf, "%s ALIVE", buf); if (status & CONN_KILLED) sprintf(buf, "%s KILLED", buf); if (status & REQ_PUSHBACK) sprintf(buf, "%s PUSHBACK", buf); if (status & IGNORE) sprintf(buf, "%s IGNORE", buf); return buf; } static char * OsCommFamily(family) int family; { if (family == FamilyAmoeba) { return "AMOEBA"; } else { return "TCP/IP"; } } /* * Return status information about the open connections */ static errstat ConnectionStatus(hdr, buf, size) header *hdr; char *buf; int size; { char *begin, *end; char *bprintf(); int fd; XAmChanDesc *chandesc; begin = buf; end = buf + size; /* all active clients */ begin = bprintf(begin, end, "Active clients:\n"); for (fd = minClient; fd < maxClient; fd++) { static XAmChanDesc *chandesc; chandesc = XAmFdToChanDesc(fd); if (chandesc != NULL && chandesc->conninfo != NULL) { begin = bprintf(begin, end, "%d: Family %s, State %d, Status %s\n", fd, OsCommFamily(chandesc->conninfo->family), chandesc->state, OsCommStatus(chandesc->status)); } } if (begin == NULL) { hdr->h_size = 0; return STD_SYSERR; } else { hdr->h_size = begin - buf; return STD_OK; } } /* * Wakeup main thread if necessary */ static void UnblockMain(fd) int fd; { XAmChanDesc *chandesc; chandesc = XAmFdToChanDesc(fd); if (chandesc != NULL) { if ((chandesc->status & IGNORE) == 0) { WakeUpMainThread(); } } else { Error(("UnblockMain: invalid fd %d\n", fd)); } } static void TcpIpReaderSignalCatcher(sig, us, extra) signum sig; thread_ustate *us; _VOIDSTAR extra; { XAmChanDesc *chandesc = (XAmChanDesc *) extra; if (chandesc->conninfo != NULL) { dbprintf(("TcpIpReaderSignalCatcher(%d), number %d\n", sig, chandesc->conninfo->fd)); if (chandesc->signal != sig) { Error(("TCP/IP Reader: Connection %s got unexpected signal %d\n", chandesc->conninfo->fd, sig)); } } chandesc->signal = -1; thread_exit(); } void TcpIpReaderThread(argptr, argsize) void *argptr; int argsize; { XAmChanDesc *chandesc; if (argsize != sizeof(XAmChanDesc *)) { Fatal(("Internal error: TcpIpReaderThread incorrectly called\n")); } chandesc = * ((XAmChanDesc **) argptr); (void) sig_catch(chandesc->signal, TcpIpReaderSignalCatcher, (_VOIDSTAR) chandesc); for (;;) { char buffer[MAXBUFSIZE]; bufsize size; size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer)); dbprintf(("TcpIpReaderThread() read %d bytes\n", size)); if (ERR_STATUS(size)) { Error(("TCP/IP read failed (%s)\n", tcpip_why(ERR_CONVERT(size)))); chandesc->status |= CONN_KILLED; chandesc->status &= ~CONN_ALIVE; chandesc->signal = -1; thread_exit(); } if (size == 0 || cb_puts(chandesc->circbuf, buffer, size)) { if (size != 0) { Error(("TCP/IP short write to circular buffer for %d\n", XAmChanDescToFd(chandesc))); } else { Error(("TCP/IP read failed for client %d\n", XAmChanDescToFd(chandesc))); } chandesc->status |= CONN_KILLED; chandesc->status &= ~CONN_ALIVE; chandesc->signal = -1; thread_exit(); } UnblockMain(XAmChanDescToFd(chandesc)); } } static XAmChanDesc * AllocClientChannel() { XAmChanDesc *chandesc; int fd; chandesc = XAmAllocChanDesc(); if (chandesc == NULL) { return NULL; } fd = XAmChanDescToFd(chandesc); if (fd >= maxClient) { maxClient = fd + 1; dbprintf(("new max Client: %d\n", fd)); } if (fd < minClient) { minClient = fd; } return chandesc; } static errstat AmRegisterRPCconn(client_ports, server_ports) am_port_t client_ports[2]; am_port_t server_ports[2]; { XAmChanDesc *chandesc; if ((chandesc = AllocClientChannel()) == NULL) { return STD_NOSPACE; } chandesc->type = ACDT_VIRTCIRC; chandesc->virtcirc = vc_create(&server_ports[0], &server_ports[1], MAXBUFSIZE, MAXBUFSIZE); if (chandesc->virtcirc == NULL) { Error(("Connection refused: No memory for virtual circuit\n")); XAmFreeChanDesc(chandesc); return STD_NOSPACE; } dbprintf(("Amoeba connection registered\n")); vc_warn(chandesc->virtcirc, VC_IN, UnblockMain, XAmChanDescToFd(chandesc)); chandesc->status = CONN_INIT; /* cause WaitFor to call EstablishNewConnections: */ nNewConns++; WakeUpMainThread(); return STD_OK; } static XAmChanDesc * XAmFetchConnectingClient() { XAmChanDesc *chandesc; int fd; for (fd = minClient; fd < maxClient; fd++) { chandesc = XAmFdToChanDesc(fd); if (chandesc->status & CONN_INIT) { Error(("Client %d is connecting\n", fd)); chandesc->status &= ~CONN_INIT; return chandesc; } } return NULL; } static errstat AmRegisterTCPconn(chancap) capability *chancap; { XAmChanDesc *chandesc, **param; if ((chandesc = AllocClientChannel()) == NULL) { return STD_NOSPACE; } chandesc->type = ACDT_TCPIP; chandesc->chancap = *chancap; if ((chandesc->circbuf = cb_alloc(MAXBUFSIZE)) == NULL) { Error(("TCPconn refused: No memory for circular buffer\n")); XAmFreeChanDesc(chandesc); return STD_NOSPACE; } chandesc->signal = sig_uniq(); param = (XAmChanDesc **) xalloc(sizeof(XAmChanDesc *)); /* error checking? */ *param = chandesc; if (thread_newthread(TcpIpReaderThread, MAXBUFSIZE + CONNECTOR_STACK, (char *)param, sizeof(XAmChanDesc *)) == 0) { Error(("TCPconn refused: Cannot start reader thread\n")); cb_close(chandesc->circbuf); cb_free(chandesc->circbuf); XAmFreeChanDesc(chandesc); return STD_NOSPACE; } dbprintf(("TCP connection registered\n")); chandesc->status = CONN_INIT; /* cause WaitFor to call EstablishNewConnections: */ nNewConns++; WakeUpMainThread(); return STD_OK; } /* * Establishing a new connection is done in two phases. This thread does the * first part. It filters out bad connect requests. A new rendevous port is * sent to the client and the main loop is informed if there is a legal * request. The sleep synchronizes with the main loop so that the paperwork * is finished for the current connect request before the thread is ready to * accept another connect. */ static void AmConnectorThread() { header req, rep; am_port_t client_ports[2]; am_port_t server_ports[2]; short s; char *repb; extern CreateNewClient(); WaitForInitialization(); dbprintf(("AmConnectorThread() running ...\n")); if ((repb = (char *)xalloc(REPLY_BUFSIZE)) == NULL) { Fatal(("Amoeba connector thread: malloc failed")); } for (;;) { do { req.h_port = X.cap_port; s = getreq(&req, NILBUF, 0); } while (ERR_CONVERT(s) == RPC_ABORTED); if (ERR_STATUS(s)) Fatal(("Amoeba connector thread: getreq failed")); /* TODO: check privilege fields here */ dbprintf(("AmConnectorThread() accepting a request\n")); switch (req.h_command) { case STD_INFO: rep.h_status = STD_OK; sprintf(repb, "X11R6 server on %s", XServerHostName); rep.h_size = strlen(repb); putrep(&rep, repb, rep.h_size); break; case STD_STATUS: rep.h_status = ConnectionStatus(&rep, repb, REPLY_BUFSIZE); putrep(&rep, repb, rep.h_size); break; #ifdef XSERV_t case AX_SHUTDOWN: rep.h_status = STD_OK; putrep(&rep, NILBUF, 0); GiveUp(SIGTERM); break; case AX_REINIT: rep.h_status = STD_OK; putrep(&rep, NILBUF, 0); AutoResetServer(SIGINT); break; #endif case AX_CONNECT: uniqport(&client_ports[0]); uniqport(&server_ports[1]); priv2pub(&client_ports[0], &server_ports[0]); priv2pub(&server_ports[1], &client_ports[1]); rep.h_status = AmRegisterRPCconn(client_ports, server_ports); if (rep.h_status == STD_OK) { putrep(&rep, (bufptr)client_ports, 2*sizeof(am_port_t)); } else { putrep(&rep, NILBUF, 0); } break; default: rep.h_status = STD_COMBAD; putrep(&rep, NILBUF, 0); break; } } } #ifdef XSERV_t /* * To prevent the X-server from generating lots of error messages, * in case the server is gone or when its full. */ #define LOOP_OPEN 1 #define LOOP_SETCONF 2 #define LOOP_LISTEN 4 extern char *display; /* The display number */ /* * The TCP/IP connector thread listens to a well known port (6000 + * display number) for connection request. When such a request arrives * it allocates a communication structure and a reader thread. This * thread prevents the main loop from blocking when there's no data. */ static void AmTCPConnectorThread() { capability svrcap, chancap; nwio_tcpconf_t tcpconf; nwio_tcpcl_t tcpconnopt; char name[BUFSIZ]; errstat err; int result; int looping = 0; strncpy(name, XTcpServerName, BUFSIZ); if ((err = name_lookup(name, &svrcap)) != STD_OK) { sprintf(name, "%s/%s", TCP_SVR_NAME, XTcpServerName); if ((err = name_lookup(name, &svrcap)) != STD_OK) Fatal(("Lookup %s failed: %s\n", XTcpServerName, err_why(err))); } WaitForInitialization(); dbprintf(("AmTCPConnectorThread() running ...\n")); for (;;) { /* * Listen to TCP/IP port X_TCP_PORT + display for connections. * Some interesting actions have to be taken to keep this connection * alive and kicking :-) */ if ((err = tcpip_open(&svrcap, &chancap)) != STD_OK) { /* the server probably disappeared, just wait for it to return */ if (looping & LOOP_OPEN) { Error(("TCP/IP open failed: %s\n", tcpip_why(err))); looping |= LOOP_OPEN; } sleep(60); (void) name_lookup(name, &svrcap); continue; } looping &= ~LOOP_OPEN; tcpconf.nwtc_locport = htons(X_TCP_PORT + atoi(display)); tcpconf.nwtc_flags = NWTC_EXCL | NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; if ((err = tcp_ioc_setconf(&chancap, &tcpconf)) != STD_OK) { /* couldn't configure, probably server space problem */ if (looping & LOOP_SETCONF) { Error(("TCP/IP setconf failed: %s\n", tcpip_why(err))); looping |= LOOP_SETCONF; } std_destroy(&chancap); sleep(60); continue; } looping &= ~LOOP_SETCONF; tcpconnopt.nwtcl_flags = 0; if ((err = tcp_ioc_listen(&chancap, &tcpconnopt)) != STD_OK) { /* couldn't listen, definitely a server memory problem */ if (looping & LOOP_LISTEN) { Error(("TCP/IP listen failed: %s\n", tcpip_why(err))); looping |= LOOP_LISTEN; } std_destroy(&chancap); sleep(60); continue; } looping &= ~LOOP_LISTEN; if ((err = tcpip_keepalive_cap(&chancap)) != STD_OK) { Error(("TCP/IP keep alive failed: %s\n", tcpip_why(err))); std_destroy(&chancap); continue; } err = AmRegisterTCPconn(&chancap); if (err != STD_OK) { Error(("AmRegisterTCPconn failed (%s)\n", err_why(err))); std_destroy(&chancap); } } } static void AmStartXserverThreads(chandesc) XAmChanDesc *chandesc; { char host[100]; errstat err; capability pubX; static int threadsStarted = 0; /* * Each time the server is reset this routine is called to * setup the new well known sockets. For Amoeba we'll just * keep using the old threads that are already running. */ if (!threadsStarted) { threadsStarted = 1; /* * Create a new capability for this X server */ if (XServerHostName == NULL) XServerHostName = getenv("XHOST"); if (XServerHostName == NULL) { Fatal(("XHOST not set, or server host name not given\n")); } sprintf(host, "%s/%s:%s", DEF_XSVRDIR, XServerHostName, display); uniqport(&X.cap_port); priv2pub(&X.cap_port, &pubX.cap_port); (void) name_delete(host); if ((err = name_append(host, &pubX)) != 0) { Error(("Cannot create capability %s: %s\n", host, err_why(err))); exit(1); } /* Allow WaitFor module to initialize */ AmInitWaitFor(); /* Also, initialize main thread locking */ InitMainThread(); /* Initialize and start IOP reader thread */ InitializeIOPServerReader(); /* Start native Amoeba service threads */ if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) { Fatal(("Cannot start Amoeba connector thread\n")); } if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) { Fatal(("Cannot start Amoeba connector thread\n")); } chandesc->type = ACDT_VIRTCIRC; chandesc->status = CONN_ALIVE; /* * Start TCP/IP service threads */ if (XTcpServerName) { if (thread_newthread(AmTCPConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) Fatal(("Cannot start TCP connector thread\n")); if (thread_newthread(AmTCPConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) Fatal(("Cannot start TCP connector thread\n")); } } } int AmFindReadyClients(pClientsReady, mask) int *pClientsReady; long *mask; { /* Check for clients needing attention. They may have input, * or they might be dying. Ignore the clients not present in * the file descriptor bit vector `mask'. This is used for * implementing server grabs. * Returns the number of clients having data for us. */ extern int ConnectionTranslation[]; XAmChanDesc *chandesc; int fd; int nready; /* Since we're scheduled non-preemptively by default, allow the * listener threads to run first, if needed: */ threadswitch(); nready = 0; for (fd = minClient; fd < maxClient; fd++) { int which; int n; if (fd > 0 && (fd % 32) == 0) { /* switch to next fd mask */ mask++; } if ((*mask & (1L << fd)) == 0) { dbprintf(("skip %d\n", fd)); continue; } chandesc = XAmFdToChanDesc(fd); if (chandesc->state != ACDS_USED) { dbprintf(("AmFindReady: fd %d not in use\n", fd)); continue; } which = ConnectionTranslation[fd]; dbprintf(("checking client %d (fd %d) of %d\n", fd, which, maxClient)); if (chandesc->status & CONN_KILLED) { dbprintf(("conn killed; close client with fd %d\n", fd)); CloseDownClient(clients[which]); chandesc->status &= ~(CONN_KILLED | CONN_ALIVE); continue; } if ((chandesc->status & CONN_ALIVE) == 0) { dbprintf(("conn with %d is not alive\n", fd)); continue; } /* see if there is data available */ switch (chandesc->type) { case ACDT_TCPIP: n = cb_full(chandesc->circbuf); break; case ACDT_VIRTCIRC: n = vc_avail(chandesc->virtcirc, VC_IN); break; default: n = -1; } if (n < 0) { dbprintf(("avail %d; close client %d\n", n, which)); CloseDownClient(clients[which]); continue; } else { if (n > 0) { *pClientsReady++ = which; nready++; dbprintf(("client %d has %d bytes available\n", which, n)); } else { dbprintf(("client %d has no data available\n", which, n)); } } /* Clients that already have (possibly inserted) data are found * with help from io.c (the ClientsWithData bit array). */ } return nready; } #endif /* XSERV_t */ #endif /* XSERV_t || FS_t */ static TRANS(AmSetAddr)(ciptr, chandesc) XtransConnInfo ciptr; XAmChanDesc *chandesc; { switch (chandesc->type) { case ACDT_TCPIP: /* should really ask the TCP/IP server */ ciptr->family = AF_INET; ciptr->addr = strdup("XXXXTODO"); ciptr->addrlen = strlen("XXXXTODO"); break; case ACDT_VIRTCIRC: /* For Amoeba connections the adress is not really used, * so just fake something */ ciptr->family = AF_AMOEBA; ciptr->addr = strdup("Amoeba"); ciptr->addrlen = strlen(ciptr->addr); break; } } #ifdef TRANS_SERVER static XtransConnInfo TRANS(AMOpenCOTSServer)(thistrans, protocol, given_host, port) Xtransport *thistrans; char *protocol; char *given_host; char *port; { XAmChanDesc *chandesc; XtransConnInfo ciptr; PRMSG(2,"AMOpenCOTSServer(%s,%s,%s)\n", protocol, given_host, port); ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo)); if (ciptr == NULL) { PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0); return NULL; } chandesc = XAmAllocChanDesc(); if (chandesc == NULL) { return NULL; } #ifdef XSERV_t AmStartXserverThreads(chandesc); #endif chandesc->conninfo = ciptr; ciptr->fd = XAmChanDescToFd(chandesc); TRANS(AmSetAddr)(ciptr, chandesc); TRANS(AMGetPeerAddr)(ciptr); return ciptr; } #endif /* TRANS_SERVER */ #ifdef TRANS_CLIENT static XtransConnInfo TRANS(AMOpenCLTSClient)(thistrans, protocol, host, port) Xtransport *thistrans; char *protocol; char *host; char *port; { XtransConnInfo ciptr; int i; PRMSG(1,"AMOpenCLTSClient(%d,%s,%s)\n", protocol, host, port ); /* TODO */ return NULL; } #endif /* TRANS_CLIENT */ #ifdef TRANS_SERVER static XtransConnInfo TRANS(AMOpenCLTSServer)(thistrans, protocol, host, port) Xtransport *thistrans; char *protocol; char *host; char *port; { XtransConnInfo ciptr; int i; PRMSG(1,"AMOpenCLTSServer(%d,%s,%s)\n", protocol, host, port ); /* TODO */ return NULL; } static int TRANS(AMResetListener)(ciptr) XtransConnInfo ciptr; { PRMSG(2,"AMResetListener()\n", 0, 0, 0 ); /* nothing to do? */ return 0; } #endif /* TRANS_SERVER */ static TRANS(AMSetOption)(ciptr, option, arg) XtransConnInfo ciptr; int option; int arg; { PRMSG(1,"AMSetOption(%d,%d,%d)\n", ciptr->fd, option, arg ); /* TODO */ return -1; } #ifdef TRANS_SERVER static TRANS(AMCreateListener)(ciptr, req) XtransConnInfo ciptr; char *req; { PRMSG(2,"AMCreateListener(%x->%d,%x)\n", ciptr, ciptr->fd, req ); /* Listener threads are already created at this point */ return 0; } static XtransConnInfo TRANS(AMAccept)(ciptr) XtransConnInfo ciptr; { XAmChanDesc *chandesc; XtransConnInfo newciptr; PRMSG(2,"AMAccept(%x->%d)\n", ciptr, ciptr->fd, 0 ); #if defined(XSERV_t) || defined(FS_t) chandesc = XAmFetchConnectingClient(); if (chandesc == NULL) { PRMSG (1, "AMAccept: no client waiting?\n", 0, 0, 0); return NULL; } nNewConns--; newciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo)); if (newciptr == NULL) { PRMSG (1, "AMAccept: malloc failed\n", 0, 0, 0); return NULL; } newciptr->fd = XAmChanDescToFd(chandesc); chandesc->conninfo = newciptr; chandesc->status |= CONN_ALIVE; PRMSG(2,"AMAccept: OK: (%x->%d)\n", newciptr, newciptr->fd, 0 ); TRANS(AmSetAddr)(newciptr, chandesc); TRANS(AMGetPeerAddr)(newciptr); return newciptr; #else return NULL; #endif } #endif /* TRANS_SERVER */ #ifdef TRANS_CLIENT static TRANS(AMConnect)(ciptr, host, port) XtransConnInfo ciptr; char *host; char *port; { /* If this function is called, we are already connected */ PRMSG(2, "AMConnect(%d,%s)\n", ciptr->fd, host, 0); return 0; } #endif /* TRANS_CLIENT */ int TRANS(AmFdBytesReadable)(fd, count) int fd; BytesReadable_t *count; { register XAmChanDesc *chandesc; PRMSG(2, "AmFdBytesReadable(%d,%x): ", fd, count, 0 ); #ifndef XSERV_t /* give reader threads a chance: */ threadswitch(); #endif errno = 0; chandesc = XAmFdToChanDesc(fd); if (chandesc == NULL || chandesc->state != ACDS_USED) { errno = EBADF; *count = 0; return -1; } switch (chandesc->type) { case ACDT_TCPIP: *count = cb_full(chandesc->circbuf); break; case ACDT_VIRTCIRC: *count = vc_avail(chandesc->virtcirc, VC_IN); break; } if (*count < 0) { errno = (chandesc->state == ACDS_CLOSED) ? EINTR : EPIPE; *count = 0; return -1; } PRMSG(2, "AMFdBytesReadable: %d\n", *count, 0, 0 ); return 0; } static TRANS(AMBytesReadable)(ciptr, count) XtransConnInfo ciptr; BytesReadable_t *count; { return TRANS(AmFdBytesReadable)(ciptr->fd, count); } static TRANS(AMRead)(ciptr, buf, count) XtransConnInfo ciptr; char *buf; int count; { int fdi; register XAmChanDesc *chandesc; register int rv; BytesReadable_t avail; fdi = ciptr->fd; PRMSG(2, "AMRead(%d,%x,%d)\n", ciptr->fd, buf, count ); errno = 0; chandesc = XAmFdToChanDesc(fdi); if (chandesc == NULL || chandesc->state != ACDS_USED) { errno = EBADF; return -1; } /* do a non-blocking read (maybe only conditionally?) */ if ((TRANS(AMBytesReadable)(ciptr, &avail)) == 0) { if (avail <= 0) { PRMSG(2, "AMRead: nothing available yet\n", 0, 0, 0); errno = EAGAIN; return 0; } else if (count > avail) { PRMSG(2, "AMRead(%d): only %d of %d available\n", ciptr->fd, avail, count); count = avail; /* just read amount available */ } } else { PRMSG(1, "AMRead: ...BytesReadable failed\n", 0, 0, 0); return -1; } switch (chandesc->type) { case ACDT_TCPIP: rv = cb_gets(chandesc->circbuf, buf, count, count); if (rv != count) { if (rv == 0) { fprintf(stderr, "Xlib: Cannot read circbuf\n"); errno = EPIPE; rv = -1; } else { fprintf(stderr, "Xlib: Cannot read circbuf (%d)\n", rv); } } break; case ACDT_VIRTCIRC: rv = vc_readall(chandesc->virtcirc, buf, count); if (rv < 0) { fprintf(stderr, "Xlib: Cannot read virtual circuit\n"); errno = EPIPE; rv = -1; } break; } /* The circular buffer writer will only UP the semaphore when * characters are available; we have to down it ourselfs. */ if (chandesc->sema && rv > 0) sema_mdown(chandesc->sema, rv); PRMSG(2, "AMRead: %d bytes\n", rv, 0, 0); return rv; } static TRANS(AMWrite)(ciptr, buf, count) XtransConnInfo ciptr; char *buf; int count; { register XAmChanDesc *chandesc; register int written; PRMSG(2, "AMWrite(%d,%x,%d)\n", ciptr->fd, buf, count ); errno = 0; written = 0; chandesc = XAmFdToChanDesc(ciptr->fd); if (chandesc == NULL || chandesc->state != ACDS_USED) { errno = EBADF; return -1; } switch (chandesc->type) { case ACDT_TCPIP: while (count > 0) { bufsize bsize; int wrcnt; wrcnt = count > TCPIP_BUFSIZE ? TCPIP_BUFSIZE : count; bsize = tcpip_write(&chandesc->chancap, buf, wrcnt); if (ERR_STATUS(bsize)) { fprintf(stderr, "Xlib: TCP/IP write failed (%s)\n", tcpip_why(ERR_CONVERT(bsize))); errno = EPIPE; return -1; } if (bsize != wrcnt) { fprintf(stderr, "Xlib: TCP/IP write failed (expected %d, wrote %d)\n", (int)bsize, wrcnt); errno = EPIPE; return -1; } buf += bsize; count -= (int) bsize; written += (int) bsize; } break; case ACDT_VIRTCIRC: if ((written = vc_write(chandesc->virtcirc, buf, count)) < 0) { fprintf(stderr, "Xlib: virtual circuit write failed\n"); errno = EPIPE; return -1; } break; } return written; } static TRANS(AMReadv)(ciptr, iov, n) XtransConnInfo ciptr; struct iovec *iov; int n; { int i; int count = 0, thiscount; PRMSG(2, "AMReadv(%d,%x,%d)\n", ciptr->fd, ciptr, n ); for (i = 0; i < n; i++, iov++) { if (iov->iov_len) { thiscount = TRANS(AMRead)(ciptr, iov->iov_base, iov->iov_len); if (thiscount < 0) return thiscount; count += thiscount; if (thiscount < iov->iov_len) break; } } return count; } static TRANS(AMWritev)(ciptr, iov, n) XtransConnInfo ciptr; struct iovec *iov; int n; { int i; int count = 0, thiscount; PRMSG(2, "AMWritev(%d,%x,%d)\n", ciptr->fd, iov, n ); for (i = 0; i < n; i++, iov++) { if (iov->iov_len) { thiscount = TRANS(AMWrite)(ciptr, iov->iov_base, iov->iov_len); if (thiscount < 0) return thiscount; count += thiscount; if (thiscount < iov->iov_len) break; } } return count; } static TRANS(AMDisconnect)(ciptr) XtransConnInfo ciptr; { register XAmChanDesc *chandesc; PRMSG(2, "AMDisconnect(%x->%d)\n", ciptr, ciptr->fd, 0 ); chandesc = XAmFdToChanDesc(ciptr->fd); if (chandesc != NULL) { switch (chandesc->type) { case ACDT_TCPIP: if (chandesc->signal != -1) { sig_raise(chandesc->signal); chandesc->signal = -1; } std_destroy(&chandesc->chancap); break; case ACDT_VIRTCIRC: vc_close(chandesc->virtcirc, VC_BOTH | VC_ASYNC); break; } #ifdef XSERV_t if (ciptr->fd == maxClient - 1) { maxClient--; /* we could look if maxClient can be reduced even more */ } #endif XAmFreeChanDesc(chandesc); } return 0; } static TRANS(AMClose)(ciptr) XtransConnInfo ciptr; { PRMSG(2, "AMClose(%x->%d)\n", ciptr, ciptr->fd, 0 ); return TRANS(AMDisconnect)(ciptr); } Xtransport TRANS(AmConnFuncs) = { /* Combined AMOEBA RPC/TCP Interface; maybe we should split this */ "amcon", 0, #ifdef TRANS_CLIENT TRANS(AMOpenCOTSClient), #endif /* TRANS_CLIENT */ #ifdef TRANS_SERVER TRANS(AMOpenCOTSServer), #endif /* TRANS_SERVER */ #ifdef TRANS_CLIENT TRANS(AMOpenCLTSClient), #endif /* TRANS_CLIENT */ #ifdef TRANS_SERVER TRANS(AMOpenCLTSServer), #endif /* TRANS_SERVER */ TRANS(AMSetOption), #ifdef TRANS_SERVER TRANS(AMCreateListener), TRANS(AMResetListener), TRANS(AMAccept), #endif /* TRANS_SERVER */ #ifdef TRANS_CLIENT TRANS(AMConnect), #endif /* TRANS_CLIENT */ TRANS(AMBytesReadable), TRANS(AMRead), TRANS(AMWrite), TRANS(AMReadv), TRANS(AMWritev), TRANS(AMDisconnect), TRANS(AMClose), };