1 /* $XConsortium: Xtransam.c,v 1.4 94/04/17 20:23:01 mor Exp $ */
2 /* $XFree86: xc/lib/xtrans/Xtransam.c,v 3.1 1996/05/10 06:55:45 dawes Exp $ */
5 Copyright (c) 1994 X Consortium
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 OTHER DEALINGS IN THE SOFTWARE.
26 Except as contained in this notice, the name of the X Consortium shall
27 not be used in advertising or otherwise to promote the sale, use or
28 other dealings in this Software without prior written authorization
29 from the X Consortium.
33 /* Copyright (c) 1994 Vrije Universiteit Amsterdam, Netherlands
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted, provided
39 * that the above copyright notice appear in all copies and that both that
40 * copyright notice and this permission notice appear in supporting
41 * documentation, and that the name Vrije Universiteit not be used
42 * in advertising or publicity pertaining to distribution of the software
43 * without specific, written prior permission. The Vrije Universiteit
44 * makes no representations about the suitability of this software for
45 * any purpose. It is provided "as is" without express or implied warranty.
47 * THE VRIJE UNIVERSITEIT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
48 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
49 * NO EVENT SHALL THE VRIJE UNIVERSITEIT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
50 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
51 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
52 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
53 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 * This is the Amoeba implementation of the X Transport service layer
60 #define event am_event_t
61 #define interval am_interval_t
62 #define port am_port_t
64 #include <semaphore.h>
70 #include <exception.h>
71 #include <module/signals.h>
75 #include <exception.h>
79 #include <module/name.h>
80 #include <server/x11/Xamoeba.h>
81 #include <server/ip/hton.h>
82 #include <server/ip/types.h>
83 #include <server/ip/gen/in.h>
84 #include <server/ip/gen/tcp.h>
85 #include <server/ip/tcpip.h>
86 #include <server/ip/tcp_io.h>
87 #include <server/ip/gen/tcp_io.h>
88 #include <server/ip/gen/netdb.h>
89 #include <server/ip/gen/inet.h>
94 extern char *strdup();
96 /* a new family for Amoeba RPC connections */
98 #define FamilyAmoeba 33
100 #define MAX_TCPIP_RETRY 4
101 #define CIRCBUFSIZE 4096 /* was 1024 */
104 * Amoeba channel description:
106 typedef struct _XAmChanDesc {
107 int state; /* current state of connection */
108 int type; /* type of connection */
109 int status; /* status used by server */
110 signum signal; /* signal to kill TCP/IP reader */
111 semaphore *sema; /* select semaphore */
112 struct vc *virtcirc; /* virtual circuit for Amoeba RPC */
113 struct circbuf *circbuf; /* circular buffer for TCP/IP */
114 capability chancap; /* TCP/IP channel capability */
115 XtransConnInfo conninfo; /* back pointer to the connect info */
118 /* Amoeba channel descriptor states */
119 #define ACDS_FREE 0 /* unused */
120 #define ACDS_USED 1 /* intermediate state */
121 #define ACDS_CLOSED 2 /* just closed */
123 /* Amoeba channel types */
124 #define ACDT_TCPIP 1 /* TCP/IP connection */
125 #define ACDT_VIRTCIRC 2 /* Amoeba virtual circuit connection */
129 #include "dix.h" /* clients[] needed by AmFindReadyClients */
130 #define Error(list) ErrorF list
131 #define Fatal(list) FatalError list
133 #define Error(list) printf list
134 #define Fatal(list) { printf list; exit(1); }
137 #define dbprintf(list) /* printf list */
138 #define doprintf(list) printf list /**/
141 * First: utility functions.
144 #if defined(XSERV_t) || defined(FS_t)
146 static semaphore main_sema;
148 /* The X-server consists of one main thread, running the non re-entrant
149 * X code, and a number of auxilary threads that take care of reading
150 * the input streams, and input devices. The following set of routines
151 * wake up the main thread when it has something to do.
156 sema_init(&main_sema, 0);
166 SleepMainThread(timeout)
167 am_interval_t timeout;
169 dbprintf(("Sleeping main thread timeout %d\n", timeout));
170 return (sema_trydown(&main_sema, timeout) == 0) ? 0 : -1;
174 static int init_waiters;
175 static semaphore init_sema;
181 sema_init(&init_sema, 0);
185 * Force caller thread to wait until main has finished the initialization.
188 WaitForInitialization()
191 dbprintf(("Waiting for initialization (%d)\n", init_waiters));
192 sema_down(&init_sema);
198 /* wakeup threads in initial sleep */
199 if (init_waiters > 0) {
200 dbprintf(("%d waiters wait for something ...\n", init_waiters));
201 while (init_waiters-- > 0) {
207 #endif /* XSERV_t || FS_t */
210 #define THREAD_STACK_SIZE (8*1024)
213 * Amoeba connection information is stored in, so called,
214 * channel descriptors. Channel descriptors are identified
215 * by their index in the table below.
217 static XAmChanDesc XAmChanDescriptors[OPEN_MAX];
218 static void XAmCleanUpChanDesc(); /* forward */
221 * Cleanup connection descriptors on a signal
224 XAmSignalCleanUpChanDesc(sig)
227 XAmCleanUpChanDesc();
232 * Cleanup connection descriptors
239 for (i = 0; i < OPEN_MAX; i++) {
240 switch (XAmChanDescriptors[i].type) {
242 /* The Amoeba TCP/IP server is capability based, i.e.
243 * it uses capabilities to identify connections. Since a
244 * capability is only destroyed when it has aged too much
245 * or is explicitly deleted, the connection it identifies
246 * will tend to exist for some while even if the client is
247 * already gone. To force connections to close this loop
248 * destroys all open TCP/IP connection. This loop us auto-
249 * matically executed when exit() is called.
251 std_destroy(&XAmChanDescriptors[i].chancap);
254 /* Close the virtual circuit asynchronously, or otherwise
255 * we may hang for a minute under some (?) conditions.
257 vc_close(XAmChanDescriptors[i].virtcirc, VC_BOTH | VC_ASYNC);
260 XAmChanDescriptors[i].state = ACDS_FREE;
265 * Allocate a channel descriptor
274 static int initialized = 0;
277 * Since the TCP/IP server is capability based its connections exists
278 * even if the owner process is long gone. To overcome this nuisance,
279 * a sweep is made over the connection descriptors when exit() is
280 * called or when an un-catched (by application program) signal is
285 atexit(XAmCleanUpChanDesc);
286 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
287 signal(SIGHUP, XAmSignalCleanUpChanDesc);
288 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
289 signal(SIGQUIT, XAmSignalCleanUpChanDesc);
290 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
291 signal(SIGINT, XAmSignalCleanUpChanDesc);
292 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
293 signal(SIGTERM, XAmSignalCleanUpChanDesc);
297 for (i = 0; i < OPEN_MAX; i++) {
298 if (XAmChanDescriptors[i].state == ACDS_FREE) {
299 XAmChanDescriptors[i].state = ACDS_USED;
300 XAmChanDescriptors[i].conninfo = NULL;
301 return &XAmChanDescriptors[i];
308 * Convert ``file descriptor'' to channel descriptor
314 if (fd >= 0 && fd < OPEN_MAX) {
315 return &XAmChanDescriptors[fd];
322 * Convert channel descriptor to ``file descriptor''
325 XAmChanDescToFd(chandesc)
326 XAmChanDesc *chandesc;
328 return chandesc - XAmChanDescriptors;
332 * Free channel descriptor
335 XAmFreeChanDesc(chandesc)
336 XAmChanDesc *chandesc;
338 if (chandesc->sema) {
339 xfree(chandesc->sema);
340 chandesc->sema = NULL;
342 chandesc->state = ACDS_FREE;
345 static void XAmReaderThread();
348 MakeAmConnection(phostname, idisplay, familyp, saddrlenp, saddrp)
351 int *familyp; /* RETURN */
352 int *saddrlenp; /* RETURN */
353 char **saddrp; /* RETURN */
355 capability xservercap;
356 char xserverpath[256];
357 XAmChanDesc *chandesc;
360 /* Amoeba requires a server hostname */
361 if (phostname == NULL || *phostname == '\0') {
362 fprintf(stderr, "MakeAmConnection: Display name expected\n");
366 /* allocate channel descriptor */
367 chandesc = XAmAllocChanDesc();
368 if (chandesc == NULL) {
369 fprintf(stderr, "MakeAmConnection: Out of channel capabilities\n");
374 * There are two possible way to make a connection on Amoeba. Either
375 * through an Amoeba RPC or a TCP/IP connection. Depending on whether
376 * the X server resides on Amoeba, Amoeba RPC's are used. Otherwise
377 * it uses a TCP/IP connection.
379 (void)sprintf(xserverpath, "%s/%s:%d", DEF_XSVRDIR, phostname, idisplay);
380 if ((err = name_lookup(xserverpath, &xservercap)) == STD_OK) {
386 /* Amoeba virtual circuit connection */
387 chandesc->type = ACDT_VIRTCIRC;
389 /* get the two connection ports from the X-server */
390 hdr.h_command = AX_CONNECT;
391 hdr.h_port = xservercap.cap_port;
392 hdr.h_priv = xservercap.cap_priv;
393 size = trans(&hdr, NILBUF, 0, &hdr, (char *)vccaps, sizeof(vccaps));
394 if (ERR_STATUS(size)) {
395 err = ERR_CONVERT(size);
397 err = ERR_CONVERT(hdr.h_status);
399 if (err != STD_OK || size != sizeof(vccaps)) {
400 fprintf(stderr, "Xlib: connect to Amoeba X-server failed (%s)\n",
402 XAmFreeChanDesc(chandesc);
406 /* setup an Amoeba virtual circuit */
408 vc_create(&vccaps[1], &vccaps[0], MAXBUFSIZE, MAXBUFSIZE);
409 if (chandesc->virtcirc == (struct vc *)NULL) {
410 fprintf(stderr, "Xlib: Amoeba virtual circuit create failed\n");
411 XAmFreeChanDesc(chandesc);
415 /* Special Amoeba family type. For Amoeba no additional access control
416 * mechanism exists; when you have the server capability, you have
417 * the access. Just use a fake address.
419 *familyp = AF_AMOEBA;
420 *saddrp = strdup("Amoeba");
421 *saddrlenp = strlen(*saddrp);
428 nwio_tcpconf_t tcpconf;
432 /* Amoeba TCP/IP connection */
433 chandesc->type = ACDT_TCPIP;
435 /* lookup up TCP/IP server */
436 if ((tcpsvr = getenv("TCP_SERVER")) == NULL) {
437 tcpsvr = TCP_SVR_NAME;
439 if ((err = name_lookup(tcpsvr, &tcpcap)) != STD_OK) {
440 fprintf(stderr, "Xlib: Cannot lookup %s (%s)\n",
441 tcpsvr, err_why(err));
442 std_destroy(&chandesc->chancap);
443 XAmFreeChanDesc(chandesc);
447 /* establish TCP/IP connection */
448 if ((err = tcpip_open(&tcpcap, &chandesc->chancap)) != STD_OK) {
449 fprintf(stderr, "Xlib: Cannot open TCP/IP server on %s (%s)\n",
450 tcpsvr, tcpip_why(err));
451 std_destroy(&chandesc->chancap);
452 XAmFreeChanDesc(chandesc);
456 /* lookup TCP/IP hostname */
457 if (isdigit(phostname[0])) {
458 ipaddr = inet_addr(phostname);
460 struct hostent *hp = gethostbyname(phostname);
462 fprintf(stderr, "Xlib: %s unknown host\n", phostname);
465 memcpy(&ipaddr, hp->h_addr, hp->h_length);
468 /* set remote address/port on the TCP/IP connection */
469 tcpconf.nwtc_flags = NWTC_SET_RA|NWTC_SET_RP|NWTC_LP_SEL;
470 tcpconf.nwtc_remaddr = ipaddr;
471 tcpconf.nwtc_remport = htons(6000+idisplay);
472 if ((err = tcp_ioc_setconf(&chandesc->chancap, &tcpconf)) != STD_OK) {
473 fprintf(stderr, "Xlib: Cannot configure TCP/IP server (%s)\n",
475 std_destroy(&chandesc->chancap);
476 XAmFreeChanDesc(chandesc);
480 /* make the actual TCP/IP connection */
481 tcpcl.nwtcl_flags = 0;
482 if ((err = tcp_ioc_connect(&chandesc->chancap, &tcpcl)) != STD_OK) {
483 fprintf(stderr, "Xlib: Cannot make TCP/IP connection (%s)\n",
485 std_destroy(&chandesc->chancap);
486 XAmFreeChanDesc(chandesc);
490 /* start TCP/IP reader thread */
491 chandesc->signal = sig_uniq();
492 chandesc->circbuf = cb_alloc(CIRCBUFSIZE);
493 param = (XAmChanDesc **) xalloc(sizeof(XAmChanDesc *)); /* error checking? */
495 result = thread_newthread(XAmReaderThread, THREAD_STACK_SIZE,
496 (char *)param, sizeof(XAmChanDesc *));
498 fprintf(stderr, "Xlib: Cannot start reader thread\n");
499 std_destroy(&chandesc->chancap);
500 XAmFreeChanDesc(chandesc);
503 threadswitch(); /* give reader a try */
506 * Family type is set to Internet so that the .Xauthority
507 * files from Unix will work under Amoeba (for Unix displays).
510 *saddrlenp = sizeof(ipaddr_t);
511 *saddrp = xalloc(sizeof(ipaddr_t));
512 memcpy(*saddrp, (char *)&ipaddr, sizeof(ipaddr_t)); /* error checking? */
515 return XAmChanDescToFd(chandesc);
519 * The TCP/IP server silently assumes a maximum buffer size of 30000 bytes.
521 #define TCPIP_BUFSIZE 16384
524 XAMCloseChannel(chandesc)
525 XAmChanDesc *chandesc;
527 if (chandesc->state == ACDS_USED && chandesc->type == ACDT_TCPIP) {
528 cb_close(chandesc->circbuf);
529 chandesc->state = ACDS_CLOSED;
535 * Shutdown TCP/IP reader thread
538 XAmReaderSignalCatcher(sig, us, extra)
543 register XAmChanDesc *chandesc = (XAmChanDesc *)extra;
545 XAMCloseChannel(chandesc);
550 * TCP/IP reader thread
553 XAmReaderThread(argptr, argsize)
557 register XAmChanDesc *chandesc;
559 chandesc = *((XAmChanDesc **)argptr);
560 (void) sig_catch(chandesc->signal, XAmReaderSignalCatcher,
561 (_VOIDSTAR) chandesc);
563 while (chandesc->state == ACDS_USED) {
564 char buffer[CIRCBUFSIZE];
567 size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer));
568 if (ERR_STATUS(size) || size == 0) {
570 static char msg[] = "Xlib: TCP/IP channel closed\n";
572 write(2, msg, sizeof(msg));
574 fprintf(stderr, "Xlib: TCP/IP read failed (%s)\n",
575 err_why(ERR_CONVERT(size)));
577 XAMCloseChannel(chandesc);
581 if (cb_puts(chandesc->circbuf, buffer, size) != 0) {
582 fprintf(stderr, "Xlib: short write to circular buffer\n");
583 XAMCloseChannel(chandesc);
591 * Wait until input is available or until the timer expires.
594 TRANS(AmSelect)(ifd, timout)
598 XAmChanDesc *chandesc;
603 chandesc = XAmFdToChanDesc(ifd);
604 if (chandesc == NULL || chandesc->state != ACDS_USED) {
609 if (chandesc->sema == NULL) {
610 /* Allocate semaphore to sleep on when no data is
611 * available. The underlying circular buffer and
612 * virtual circuit packages manage this semaphore.
614 chandesc->sema = (semaphore *) xalloc(sizeof(semaphore));
615 if (chandesc->sema == NULL) {
620 sema_init(chandesc->sema, 0);
621 switch (chandesc->type) {
623 cb_setsema(chandesc->circbuf, chandesc->sema);
626 vc_setsema(chandesc->virtcirc, chandesc->sema);
631 switch (chandesc->type) {
633 if ((n = cb_full(chandesc->circbuf)) != 0) {
634 if (n < 0) errno = EPIPE;
635 return n; /* includes error as well */
637 if (sema_trydown(chandesc->sema, timout) < 0) {
641 /* we down for all the bytes in AMRead, so undo the down */
642 sema_up(chandesc->sema);
644 if ((n = cb_full(chandesc->circbuf)) < 0) {
651 if ((n = vc_avail(chandesc->virtcirc, VC_IN)) != 0) {
652 if (n < 0) errno = EPIPE;
653 return n; /* includes error as well */
655 if (sema_trydown(chandesc->sema, timout) < 0) {
659 /* we down for all the bytes in AMRead, so undo the down */
660 sema_up(chandesc->sema);
662 if ((n = vc_avail(chandesc->virtcirc, VC_IN)) < 0) {
674 * This function gets the local address of the transport and stores it in the
675 * XtransConnInfo structure for the connection.
679 TRANS(AMGetAddr)(ciptr)
680 XtransConnInfo ciptr;
682 PRMSG(1,"AMGetAddr(%x)\n", ciptr, 0,0 );
683 PRMSG(1,"AMGetAddr: TODO\n", 0, 0, 0);
690 * This function gets the remote address of the socket and stores it in the
691 * XtransConnInfo structure for the connection.
695 TRANS(AMGetPeerAddr)(ciptr)
696 XtransConnInfo ciptr;
698 struct nwio_tcpconf tcpconf;
700 XAmChanDesc *chandesc;
702 PRMSG(2,"AMGetPeerAddr(%x)\n", ciptr, 0,0 );
704 chandesc = XAmFdToChanDesc(ciptr->fd);
705 if (chandesc == NULL || chandesc->state != ACDS_USED) {
710 switch (chandesc->type) {
712 /* get the remote adress from the TCP/IP server */
713 if ((err = tcp_ioc_getconf(&chandesc->chancap, &tcpconf)) != STD_OK) {
714 PRMSG (1, "AMGetPeerAddr: Cannot get remote address (%d)\n",
721 struct hostent *remote;
724 remote = gethostbyaddr((char *) &tcpconf.nwtc_remaddr,
725 sizeof(tcpconf.nwtc_remaddr), AF_INET);
726 if ((remote == NULL) || (remote->h_name == NULL)) {
727 hostname = inet_ntoa(tcpconf.nwtc_remaddr);
729 hostname = remote->h_name;
731 PRMSG (1, "AMGetPeerAddr: remote addr `%s'\n",
736 ciptr->peeraddrlen = sizeof(tcpconf.nwtc_remaddr);
737 ciptr->peeraddr = (char *) xalloc (ciptr->peeraddrlen);
738 if (ciptr->peeraddr == NULL) {
739 PRMSG (1, "AMGetPeerAddr: Can't allocate peeraddr\n",
744 memcpy (ciptr->peeraddr, &tcpconf.nwtc_remaddr, ciptr->peeraddrlen);
748 /* for Amoeba virtual circuits just copy the client address */
749 if ((ciptr->peeraddr = (char *) xalloc (ciptr->addrlen)) == NULL) {
750 PRMSG (1, "AMGetPeerAddr: Can't allocate peeraddr\n",
755 ciptr->peeraddrlen = ciptr->addrlen;
756 memcpy (ciptr->peeraddr, ciptr->addr, ciptr->peeraddrlen);
764 static XtransConnInfo
765 TRANS(AMOpen)(device)
768 PRMSG(1,"AMOpen(%s)\n", device, 0,0 );
769 PRMSG(1,"AMOpen: TODO\n", 0, 0, 0);
776 TRANS(AMAddrToNetbuf)(tlifamily, host, port, netbufp)
780 struct netbuf *netbufp;
782 PRMSG(1,"AMAddrToNetbuf(%d,%s,%s)\n", tlifamily, host, port );
783 PRMSG(1,"AMAddrToNetbuf: TODO\n", 0, 0, 0);
789 * These functions are the interface supplied in the Xtransport structure
794 static XtransConnInfo
795 TRANS(AMOpenCOTSClient)(thistrans, protocol, host, port)
796 Xtransport *thistrans;
801 XtransConnInfo ciptr;
802 XAmChanDesc *chandesc;
804 PRMSG(2,"AMOpenCOTSClient(%s,%s,%s)\n", protocol, host, port );
806 ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
808 PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0);
812 ciptr->fd = MakeAmConnection (host, 0 /* TODO */, &ciptr->family,
813 &ciptr->addrlen, &ciptr->addr);
815 PRMSG(1,"AMOpenCOTSClient: Unable to make connection to %s\n",
821 /* set the back pointer */
822 chandesc = XAmFdToChanDesc(ciptr->fd);
823 chandesc->conninfo = ciptr;
825 TRANS(AMGetPeerAddr)(ciptr);
827 PRMSG(2,"AMOpenCOTSClient: made connection to %s; fd = %d, family = %d\n",
828 host, ciptr->fd, ciptr->family);
833 #endif /* TRANS_CLIENT */
835 #if defined(XSERV_t) || defined(FS_t)
837 /* The following defines come from osdep.h;
838 * they should removed from there eventually.
842 * Some fundamental constants
844 #define CONNECTOR_STACK 4000 /* stack for connector task */
845 #define DEVREADER_STACK 4000 /* stack for device reader */
846 #define CREATOR_STACK 4000 /* stack for connection creator */
847 #define MAXTASKS 100 /* Maximum # clients */
852 #define CONN_KILLED 0x1 /* Connection being closed */
853 #define REQ_PUSHBACK 0x2 /* Request pushed back */
854 #define IGNORE 0x4 /* True if client ignored */
855 #define CONN_INIT 0x8 /* True if still initializing */
856 #define CONN_ALIVE 0x10 /* True if living */
859 #define REPLY_BUFSIZE 30000
861 capability X; /* X capability */
862 char *XServerHostName; /* X server host name */
863 char *XTcpServerName; /* TCP/IP server name */
865 static XtransConnInfo NewConns[MAXTASKS]; /* new client connections */
866 int nNewConns; /* # of new clients */
868 int maxClient; /* Highest allocated client fd + 1*/
869 static int minClient = 1; /* Lowest allocated client fd */
875 static char buf[100];
879 sprintf(buf, "NONE");
880 if (status & CONN_INIT)
881 sprintf(buf, "%s INIT", buf);
882 if (status & CONN_ALIVE)
883 sprintf(buf, "%s ALIVE", buf);
884 if (status & CONN_KILLED)
885 sprintf(buf, "%s KILLED", buf);
886 if (status & REQ_PUSHBACK)
887 sprintf(buf, "%s PUSHBACK", buf);
889 sprintf(buf, "%s IGNORE", buf);
897 if (family == FamilyAmoeba) {
906 * Return status information about the open connections
909 ConnectionStatus(hdr, buf, size)
917 XAmChanDesc *chandesc;
923 /* all active clients */
924 begin = bprintf(begin, end, "Active clients:\n");
925 for (fd = minClient; fd < maxClient; fd++) {
926 static XAmChanDesc *chandesc;
928 chandesc = XAmFdToChanDesc(fd);
929 if (chandesc != NULL && chandesc->conninfo != NULL) {
930 begin = bprintf(begin, end, "%d: Family %s, State %d, Status %s\n",
931 fd, OsCommFamily(chandesc->conninfo->family),
932 chandesc->state, OsCommStatus(chandesc->status));
940 hdr->h_size = begin - buf;
946 * Wakeup main thread if necessary
952 XAmChanDesc *chandesc;
954 chandesc = XAmFdToChanDesc(fd);
955 if (chandesc != NULL) {
956 if ((chandesc->status & IGNORE) == 0) {
960 Error(("UnblockMain: invalid fd %d\n", fd));
965 TcpIpReaderSignalCatcher(sig, us, extra)
970 XAmChanDesc *chandesc = (XAmChanDesc *) extra;
972 if (chandesc->conninfo != NULL) {
973 dbprintf(("TcpIpReaderSignalCatcher(%d), number %d\n",
974 sig, chandesc->conninfo->fd));
975 if (chandesc->signal != sig) {
976 Error(("TCP/IP Reader: Connection %s got unexpected signal %d\n",
977 chandesc->conninfo->fd, sig));
981 chandesc->signal = -1;
986 TcpIpReaderThread(argptr, argsize)
990 XAmChanDesc *chandesc;
992 if (argsize != sizeof(XAmChanDesc *)) {
993 Fatal(("Internal error: TcpIpReaderThread incorrectly called\n"));
996 chandesc = * ((XAmChanDesc **) argptr);
997 (void) sig_catch(chandesc->signal, TcpIpReaderSignalCatcher,
998 (_VOIDSTAR) chandesc);
1001 char buffer[MAXBUFSIZE];
1004 size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer));
1006 dbprintf(("TcpIpReaderThread() read %d bytes\n", size));
1007 if (ERR_STATUS(size)) {
1008 Error(("TCP/IP read failed (%s)\n", tcpip_why(ERR_CONVERT(size))));
1009 chandesc->status |= CONN_KILLED;
1010 chandesc->status &= ~CONN_ALIVE;
1011 chandesc->signal = -1;
1015 if (size == 0 || cb_puts(chandesc->circbuf, buffer, size)) {
1017 Error(("TCP/IP short write to circular buffer for %d\n",
1018 XAmChanDescToFd(chandesc)));
1020 Error(("TCP/IP read failed for client %d\n",
1021 XAmChanDescToFd(chandesc)));
1024 chandesc->status |= CONN_KILLED;
1025 chandesc->status &= ~CONN_ALIVE;
1026 chandesc->signal = -1;
1029 UnblockMain(XAmChanDescToFd(chandesc));
1033 static XAmChanDesc *
1034 AllocClientChannel()
1036 XAmChanDesc *chandesc;
1039 chandesc = XAmAllocChanDesc();
1040 if (chandesc == NULL) {
1044 fd = XAmChanDescToFd(chandesc);
1045 if (fd >= maxClient) {
1047 dbprintf(("new max Client: %d\n", fd));
1049 if (fd < minClient) {
1057 AmRegisterRPCconn(client_ports, server_ports)
1058 am_port_t client_ports[2];
1059 am_port_t server_ports[2];
1061 XAmChanDesc *chandesc;
1063 if ((chandesc = AllocClientChannel()) == NULL) {
1067 chandesc->type = ACDT_VIRTCIRC;
1068 chandesc->virtcirc = vc_create(&server_ports[0], &server_ports[1],
1069 MAXBUFSIZE, MAXBUFSIZE);
1070 if (chandesc->virtcirc == NULL) {
1071 Error(("Connection refused: No memory for virtual circuit\n"));
1072 XAmFreeChanDesc(chandesc);
1076 dbprintf(("Amoeba connection registered\n"));
1078 vc_warn(chandesc->virtcirc, VC_IN, UnblockMain, XAmChanDescToFd(chandesc));
1080 chandesc->status = CONN_INIT;
1082 /* cause WaitFor to call EstablishNewConnections: */
1089 static XAmChanDesc *
1090 XAmFetchConnectingClient()
1092 XAmChanDesc *chandesc;
1095 for (fd = minClient; fd < maxClient; fd++) {
1096 chandesc = XAmFdToChanDesc(fd);
1098 if (chandesc->status & CONN_INIT) {
1099 Error(("Client %d is connecting\n", fd));
1100 chandesc->status &= ~CONN_INIT;
1109 AmRegisterTCPconn(chancap)
1110 capability *chancap;
1112 XAmChanDesc *chandesc, **param;
1114 if ((chandesc = AllocClientChannel()) == NULL) {
1118 chandesc->type = ACDT_TCPIP;
1119 chandesc->chancap = *chancap;
1121 if ((chandesc->circbuf = cb_alloc(MAXBUFSIZE)) == NULL) {
1122 Error(("TCPconn refused: No memory for circular buffer\n"));
1123 XAmFreeChanDesc(chandesc);
1127 chandesc->signal = sig_uniq();
1128 param = (XAmChanDesc **) xalloc(sizeof(XAmChanDesc *)); /* error checking? */
1130 if (thread_newthread(TcpIpReaderThread, MAXBUFSIZE + CONNECTOR_STACK,
1131 (char *)param, sizeof(XAmChanDesc *)) == 0)
1133 Error(("TCPconn refused: Cannot start reader thread\n"));
1134 cb_close(chandesc->circbuf);
1135 cb_free(chandesc->circbuf);
1136 XAmFreeChanDesc(chandesc);
1140 dbprintf(("TCP connection registered\n"));
1142 chandesc->status = CONN_INIT;
1144 /* cause WaitFor to call EstablishNewConnections: */
1153 * Establishing a new connection is done in two phases. This thread does the
1154 * first part. It filters out bad connect requests. A new rendevous port is
1155 * sent to the client and the main loop is informed if there is a legal
1156 * request. The sleep synchronizes with the main loop so that the paperwork
1157 * is finished for the current connect request before the thread is ready to
1158 * accept another connect.
1164 am_port_t client_ports[2];
1165 am_port_t server_ports[2];
1168 extern CreateNewClient();
1170 WaitForInitialization();
1171 dbprintf(("AmConnectorThread() running ...\n"));
1172 if ((repb = (char *)xalloc(REPLY_BUFSIZE)) == NULL) {
1173 Fatal(("Amoeba connector thread: malloc failed"));
1177 req.h_port = X.cap_port;
1178 s = getreq(&req, NILBUF, 0);
1179 } while (ERR_CONVERT(s) == RPC_ABORTED);
1181 Fatal(("Amoeba connector thread: getreq failed"));
1183 /* TODO: check privilege fields here */
1185 dbprintf(("AmConnectorThread() accepting a request\n"));
1187 switch (req.h_command) {
1190 rep.h_status = STD_OK;
1191 sprintf(repb, "X11R6 server on %s", XServerHostName);
1192 rep.h_size = strlen(repb);
1193 putrep(&rep, repb, rep.h_size);
1197 rep.h_status = ConnectionStatus(&rep, repb, REPLY_BUFSIZE);
1198 putrep(&rep, repb, rep.h_size);
1203 rep.h_status = STD_OK;
1204 putrep(&rep, NILBUF, 0);
1209 rep.h_status = STD_OK;
1210 putrep(&rep, NILBUF, 0);
1211 AutoResetServer(SIGINT);
1216 uniqport(&client_ports[0]);
1217 uniqport(&server_ports[1]);
1218 priv2pub(&client_ports[0], &server_ports[0]);
1219 priv2pub(&server_ports[1], &client_ports[1]);
1221 rep.h_status = AmRegisterRPCconn(client_ports, server_ports);
1222 if (rep.h_status == STD_OK) {
1223 putrep(&rep, (bufptr)client_ports, 2*sizeof(am_port_t));
1225 putrep(&rep, NILBUF, 0);
1230 rep.h_status = STD_COMBAD;
1231 putrep(&rep, NILBUF, 0);
1240 * To prevent the X-server from generating lots of error messages,
1241 * in case the server is gone or when its full.
1244 #define LOOP_SETCONF 2
1245 #define LOOP_LISTEN 4
1247 extern char *display; /* The display number */
1250 * The TCP/IP connector thread listens to a well known port (6000 +
1251 * display number) for connection request. When such a request arrives
1252 * it allocates a communication structure and a reader thread. This
1253 * thread prevents the main loop from blocking when there's no data.
1256 AmTCPConnectorThread()
1258 capability svrcap, chancap;
1259 nwio_tcpconf_t tcpconf;
1260 nwio_tcpcl_t tcpconnopt;
1266 strncpy(name, XTcpServerName, BUFSIZ);
1267 if ((err = name_lookup(name, &svrcap)) != STD_OK) {
1268 sprintf(name, "%s/%s", TCP_SVR_NAME, XTcpServerName);
1269 if ((err = name_lookup(name, &svrcap)) != STD_OK)
1270 Fatal(("Lookup %s failed: %s\n", XTcpServerName, err_why(err)));
1273 WaitForInitialization();
1274 dbprintf(("AmTCPConnectorThread() running ...\n"));
1278 * Listen to TCP/IP port X_TCP_PORT + display for connections.
1279 * Some interesting actions have to be taken to keep this connection
1280 * alive and kicking :-)
1282 if ((err = tcpip_open(&svrcap, &chancap)) != STD_OK) {
1283 /* the server probably disappeared, just wait for it to return */
1284 if (looping & LOOP_OPEN) {
1285 Error(("TCP/IP open failed: %s\n", tcpip_why(err)));
1286 looping |= LOOP_OPEN;
1289 (void) name_lookup(name, &svrcap);
1292 looping &= ~LOOP_OPEN;
1294 tcpconf.nwtc_locport = htons(X_TCP_PORT + atoi(display));
1295 tcpconf.nwtc_flags = NWTC_EXCL | NWTC_LP_SET | NWTC_UNSET_RA |
1297 if ((err = tcp_ioc_setconf(&chancap, &tcpconf)) != STD_OK) {
1298 /* couldn't configure, probably server space problem */
1299 if (looping & LOOP_SETCONF) {
1300 Error(("TCP/IP setconf failed: %s\n", tcpip_why(err)));
1301 looping |= LOOP_SETCONF;
1303 std_destroy(&chancap);
1307 looping &= ~LOOP_SETCONF;
1309 tcpconnopt.nwtcl_flags = 0;
1310 if ((err = tcp_ioc_listen(&chancap, &tcpconnopt)) != STD_OK) {
1311 /* couldn't listen, definitely a server memory problem */
1312 if (looping & LOOP_LISTEN) {
1313 Error(("TCP/IP listen failed: %s\n", tcpip_why(err)));
1314 looping |= LOOP_LISTEN;
1316 std_destroy(&chancap);
1320 looping &= ~LOOP_LISTEN;
1322 if ((err = tcpip_keepalive_cap(&chancap)) != STD_OK) {
1323 Error(("TCP/IP keep alive failed: %s\n", tcpip_why(err)));
1324 std_destroy(&chancap);
1328 err = AmRegisterTCPconn(&chancap);
1329 if (err != STD_OK) {
1330 Error(("AmRegisterTCPconn failed (%s)\n", err_why(err)));
1331 std_destroy(&chancap);
1337 AmStartXserverThreads(chandesc)
1338 XAmChanDesc *chandesc;
1343 static int threadsStarted = 0;
1346 * Each time the server is reset this routine is called to
1347 * setup the new well known sockets. For Amoeba we'll just
1348 * keep using the old threads that are already running.
1350 if (!threadsStarted) {
1354 * Create a new capability for this X server
1356 if (XServerHostName == NULL)
1357 XServerHostName = getenv("XHOST");
1358 if (XServerHostName == NULL) {
1359 Fatal(("XHOST not set, or server host name not given\n"));
1361 sprintf(host, "%s/%s:%s", DEF_XSVRDIR, XServerHostName, display);
1363 uniqport(&X.cap_port);
1364 priv2pub(&X.cap_port, &pubX.cap_port);
1365 (void) name_delete(host);
1366 if ((err = name_append(host, &pubX)) != 0) {
1367 Error(("Cannot create capability %s: %s\n", host, err_why(err)));
1371 /* Allow WaitFor module to initialize */
1374 /* Also, initialize main thread locking */
1377 /* Initialize and start IOP reader thread */
1378 InitializeIOPServerReader();
1380 /* Start native Amoeba service threads */
1381 if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) {
1382 Fatal(("Cannot start Amoeba connector thread\n"));
1384 if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) {
1385 Fatal(("Cannot start Amoeba connector thread\n"));
1387 chandesc->type = ACDT_VIRTCIRC;
1388 chandesc->status = CONN_ALIVE;
1391 * Start TCP/IP service threads
1393 if (XTcpServerName) {
1394 if (thread_newthread(AmTCPConnectorThread,
1395 CONNECTOR_STACK, 0, 0) <= 0)
1396 Fatal(("Cannot start TCP connector thread\n"));
1397 if (thread_newthread(AmTCPConnectorThread,
1398 CONNECTOR_STACK, 0, 0) <= 0)
1399 Fatal(("Cannot start TCP connector thread\n"));
1405 AmFindReadyClients(pClientsReady, mask)
1409 /* Check for clients needing attention. They may have input,
1410 * or they might be dying. Ignore the clients not present in
1411 * the file descriptor bit vector `mask'. This is used for
1412 * implementing server grabs.
1413 * Returns the number of clients having data for us.
1415 extern int ConnectionTranslation[];
1416 XAmChanDesc *chandesc;
1420 /* Since we're scheduled non-preemptively by default, allow the
1421 * listener threads to run first, if needed:
1426 for (fd = minClient; fd < maxClient; fd++) {
1430 if (fd > 0 && (fd % 32) == 0) {
1431 /* switch to next fd mask */
1435 if ((*mask & (1L << fd)) == 0) {
1436 dbprintf(("skip %d\n", fd));
1440 chandesc = XAmFdToChanDesc(fd);
1441 if (chandesc->state != ACDS_USED) {
1442 dbprintf(("AmFindReady: fd %d not in use\n", fd));
1446 which = ConnectionTranslation[fd];
1447 dbprintf(("checking client %d (fd %d) of %d\n",
1448 fd, which, maxClient));
1450 if (chandesc->status & CONN_KILLED) {
1451 dbprintf(("conn killed; close client with fd %d\n", fd));
1452 CloseDownClient(clients[which]);
1453 chandesc->status &= ~(CONN_KILLED | CONN_ALIVE);
1457 if ((chandesc->status & CONN_ALIVE) == 0) {
1458 dbprintf(("conn with %d is not alive\n", fd));
1462 /* see if there is data available */
1463 switch (chandesc->type) {
1465 n = cb_full(chandesc->circbuf);
1468 n = vc_avail(chandesc->virtcirc, VC_IN);
1475 dbprintf(("avail %d; close client %d\n", n, which));
1476 CloseDownClient(clients[which]);
1480 *pClientsReady++ = which;
1482 dbprintf(("client %d has %d bytes available\n", which, n));
1484 dbprintf(("client %d has no data available\n", which, n));
1488 /* Clients that already have (possibly inserted) data are found
1489 * with help from io.c (the ClientsWithData bit array).
1496 #endif /* XSERV_t */
1498 #endif /* XSERV_t || FS_t */
1501 TRANS(AmSetAddr)(ciptr, chandesc)
1502 XtransConnInfo ciptr;
1503 XAmChanDesc *chandesc;
1505 switch (chandesc->type) {
1507 /* should really ask the TCP/IP server */
1508 ciptr->family = AF_INET;
1509 ciptr->addr = strdup("XXXXTODO");
1510 ciptr->addrlen = strlen("XXXXTODO");
1513 /* For Amoeba connections the adress is not really used,
1514 * so just fake something
1516 ciptr->family = AF_AMOEBA;
1517 ciptr->addr = strdup("Amoeba");
1518 ciptr->addrlen = strlen(ciptr->addr);
1525 static XtransConnInfo
1526 TRANS(AMOpenCOTSServer)(thistrans, protocol, given_host, port)
1527 Xtransport *thistrans;
1532 XAmChanDesc *chandesc;
1533 XtransConnInfo ciptr;
1535 PRMSG(2,"AMOpenCOTSServer(%s,%s,%s)\n", protocol, given_host, port);
1537 ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
1538 if (ciptr == NULL) {
1539 PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0);
1543 chandesc = XAmAllocChanDesc();
1544 if (chandesc == NULL) {
1549 AmStartXserverThreads(chandesc);
1552 chandesc->conninfo = ciptr;
1553 ciptr->fd = XAmChanDescToFd(chandesc);
1555 TRANS(AmSetAddr)(ciptr, chandesc);
1556 TRANS(AMGetPeerAddr)(ciptr);
1561 #endif /* TRANS_SERVER */
1566 static XtransConnInfo
1567 TRANS(AMOpenCLTSClient)(thistrans, protocol, host, port)
1568 Xtransport *thistrans;
1573 XtransConnInfo ciptr;
1576 PRMSG(1,"AMOpenCLTSClient(%d,%s,%s)\n", protocol, host, port );
1581 #endif /* TRANS_CLIENT */
1586 static XtransConnInfo
1587 TRANS(AMOpenCLTSServer)(thistrans, protocol, host, port)
1588 Xtransport *thistrans;
1593 XtransConnInfo ciptr;
1596 PRMSG(1,"AMOpenCLTSServer(%d,%s,%s)\n", protocol, host, port );
1602 TRANS(AMResetListener)(ciptr)
1603 XtransConnInfo ciptr;
1605 PRMSG(2,"AMResetListener()\n", 0, 0, 0 );
1607 /* nothing to do? */
1611 #endif /* TRANS_SERVER */
1614 TRANS(AMSetOption)(ciptr, option, arg)
1615 XtransConnInfo ciptr;
1619 PRMSG(1,"AMSetOption(%d,%d,%d)\n", ciptr->fd, option, arg );
1628 TRANS(AMCreateListener)(ciptr, req)
1629 XtransConnInfo ciptr;
1632 PRMSG(2,"AMCreateListener(%x->%d,%x)\n", ciptr, ciptr->fd, req );
1634 /* Listener threads are already created at this point */
1639 static XtransConnInfo
1640 TRANS(AMAccept)(ciptr)
1641 XtransConnInfo ciptr;
1643 XAmChanDesc *chandesc;
1644 XtransConnInfo newciptr;
1646 PRMSG(2,"AMAccept(%x->%d)\n", ciptr, ciptr->fd, 0 );
1648 #if defined(XSERV_t) || defined(FS_t)
1649 chandesc = XAmFetchConnectingClient();
1650 if (chandesc == NULL) {
1651 PRMSG (1, "AMAccept: no client waiting?\n", 0, 0, 0);
1656 newciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
1657 if (newciptr == NULL)
1659 PRMSG (1, "AMAccept: malloc failed\n", 0, 0, 0);
1663 newciptr->fd = XAmChanDescToFd(chandesc);
1664 chandesc->conninfo = newciptr;
1665 chandesc->status |= CONN_ALIVE;
1667 PRMSG(2,"AMAccept: OK: (%x->%d)\n", newciptr, newciptr->fd, 0 );
1669 TRANS(AmSetAddr)(newciptr, chandesc);
1670 TRANS(AMGetPeerAddr)(newciptr);
1678 #endif /* TRANS_SERVER */
1684 TRANS(AMConnect)(ciptr, host, port)
1685 XtransConnInfo ciptr;
1689 /* If this function is called, we are already connected */
1690 PRMSG(2, "AMConnect(%d,%s)\n", ciptr->fd, host, 0);
1694 #endif /* TRANS_CLIENT */
1698 TRANS(AmFdBytesReadable)(fd, count)
1700 BytesReadable_t *count;
1702 register XAmChanDesc *chandesc;
1704 PRMSG(2, "AmFdBytesReadable(%d,%x): ", fd, count, 0 );
1707 /* give reader threads a chance: */
1712 chandesc = XAmFdToChanDesc(fd);
1713 if (chandesc == NULL || chandesc->state != ACDS_USED) {
1719 switch (chandesc->type) {
1721 *count = cb_full(chandesc->circbuf);
1724 *count = vc_avail(chandesc->virtcirc, VC_IN);
1729 errno = (chandesc->state == ACDS_CLOSED) ? EINTR : EPIPE;
1734 PRMSG(2, "AMFdBytesReadable: %d\n", *count, 0, 0 );
1740 TRANS(AMBytesReadable)(ciptr, count)
1741 XtransConnInfo ciptr;
1742 BytesReadable_t *count;
1744 return TRANS(AmFdBytesReadable)(ciptr->fd, count);
1749 TRANS(AMRead)(ciptr, buf, count)
1750 XtransConnInfo ciptr;
1755 register XAmChanDesc *chandesc;
1757 BytesReadable_t avail;
1760 PRMSG(2, "AMRead(%d,%x,%d)\n", ciptr->fd, buf, count );
1763 chandesc = XAmFdToChanDesc(fdi);
1764 if (chandesc == NULL || chandesc->state != ACDS_USED) {
1769 /* do a non-blocking read (maybe only conditionally?) */
1770 if ((TRANS(AMBytesReadable)(ciptr, &avail)) == 0) {
1772 PRMSG(2, "AMRead: nothing available yet\n", 0, 0, 0);
1775 } else if (count > avail) {
1776 PRMSG(2, "AMRead(%d): only %d of %d available\n",
1777 ciptr->fd, avail, count);
1778 count = avail; /* just read amount available */
1781 PRMSG(1, "AMRead: ...BytesReadable failed\n", 0, 0, 0);
1785 switch (chandesc->type) {
1787 rv = cb_gets(chandesc->circbuf, buf, count, count);
1790 fprintf(stderr, "Xlib: Cannot read circbuf\n");
1794 fprintf(stderr, "Xlib: Cannot read circbuf (%d)\n", rv);
1800 rv = vc_readall(chandesc->virtcirc, buf, count);
1802 fprintf(stderr, "Xlib: Cannot read virtual circuit\n");
1809 /* The circular buffer writer will only UP the semaphore when
1810 * characters are available; we have to down it ourselfs.
1812 if (chandesc->sema && rv > 0)
1813 sema_mdown(chandesc->sema, rv);
1815 PRMSG(2, "AMRead: %d bytes\n", rv, 0, 0);
1822 TRANS(AMWrite)(ciptr, buf, count)
1823 XtransConnInfo ciptr;
1827 register XAmChanDesc *chandesc;
1828 register int written;
1830 PRMSG(2, "AMWrite(%d,%x,%d)\n", ciptr->fd, buf, count );
1835 chandesc = XAmFdToChanDesc(ciptr->fd);
1836 if (chandesc == NULL || chandesc->state != ACDS_USED) {
1841 switch (chandesc->type) {
1847 wrcnt = count > TCPIP_BUFSIZE ? TCPIP_BUFSIZE : count;
1848 bsize = tcpip_write(&chandesc->chancap, buf, wrcnt);
1849 if (ERR_STATUS(bsize)) {
1850 fprintf(stderr, "Xlib: TCP/IP write failed (%s)\n",
1851 tcpip_why(ERR_CONVERT(bsize)));
1855 if (bsize != wrcnt) {
1857 "Xlib: TCP/IP write failed (expected %d, wrote %d)\n",
1863 count -= (int) bsize;
1864 written += (int) bsize;
1869 if ((written = vc_write(chandesc->virtcirc, buf, count)) < 0) {
1870 fprintf(stderr, "Xlib: virtual circuit write failed\n");
1882 TRANS(AMReadv)(ciptr, iov, n)
1883 XtransConnInfo ciptr;
1888 int count = 0, thiscount;
1890 PRMSG(2, "AMReadv(%d,%x,%d)\n", ciptr->fd, ciptr, n );
1892 for (i = 0; i < n; i++, iov++) {
1894 thiscount = TRANS(AMRead)(ciptr, iov->iov_base, iov->iov_len);
1895 if (thiscount < 0) return thiscount;
1897 if (thiscount < iov->iov_len) break;
1906 TRANS(AMWritev)(ciptr, iov, n)
1907 XtransConnInfo ciptr;
1912 int count = 0, thiscount;
1914 PRMSG(2, "AMWritev(%d,%x,%d)\n", ciptr->fd, iov, n );
1916 for (i = 0; i < n; i++, iov++) {
1918 thiscount = TRANS(AMWrite)(ciptr, iov->iov_base, iov->iov_len);
1922 if (thiscount < iov->iov_len) break;
1931 TRANS(AMDisconnect)(ciptr)
1932 XtransConnInfo ciptr;
1934 register XAmChanDesc *chandesc;
1936 PRMSG(2, "AMDisconnect(%x->%d)\n", ciptr, ciptr->fd, 0 );
1938 chandesc = XAmFdToChanDesc(ciptr->fd);
1939 if (chandesc != NULL) {
1940 switch (chandesc->type) {
1942 if (chandesc->signal != -1) {
1943 sig_raise(chandesc->signal);
1944 chandesc->signal = -1;
1946 std_destroy(&chandesc->chancap);
1950 vc_close(chandesc->virtcirc, VC_BOTH | VC_ASYNC);
1954 if (ciptr->fd == maxClient - 1) {
1956 /* we could look if maxClient can be reduced even more */
1959 XAmFreeChanDesc(chandesc);
1967 TRANS(AMClose)(ciptr)
1968 XtransConnInfo ciptr;
1970 PRMSG(2, "AMClose(%x->%d)\n", ciptr, ciptr->fd, 0 );
1972 return TRANS(AMDisconnect)(ciptr);
1976 Xtransport TRANS(AmConnFuncs) = {
1977 /* Combined AMOEBA RPC/TCP Interface; maybe we should split this */
1981 TRANS(AMOpenCOTSClient),
1982 #endif /* TRANS_CLIENT */
1984 TRANS(AMOpenCOTSServer),
1985 #endif /* TRANS_SERVER */
1987 TRANS(AMOpenCLTSClient),
1988 #endif /* TRANS_CLIENT */
1990 TRANS(AMOpenCLTSServer),
1991 #endif /* TRANS_SERVER */
1994 TRANS(AMCreateListener),
1995 TRANS(AMResetListener),
1997 #endif /* TRANS_SERVER */
2000 #endif /* TRANS_CLIENT */
2001 TRANS(AMBytesReadable),
2006 TRANS(AMDisconnect),