]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/xtrans/Xtransam.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / lib / xtrans / Xtransam.c
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 $ */
3 /*
4
5 Copyright (c) 1994  X Consortium
6
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:
14
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
17
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.
25
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.
30
31 */
32
33 /* Copyright (c) 1994 Vrije Universiteit Amsterdam, Netherlands
34  *
35  * All Rights Reserved
36  *
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.
46  *
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.
54  */
55
56 /*
57  * This is the Amoeba implementation of the X Transport service layer
58  */
59
60 #define event am_event_t
61 #define interval am_interval_t
62 #define port am_port_t
63 #include <amoeba.h>
64 #include <semaphore.h>
65 #include <cmdreg.h>
66 #include <stdcom.h>
67 #include <stderr.h>
68 #include <vc.h>
69 #include <circbuf.h>
70 #include <exception.h>
71 #include <module/signals.h>
72 #include <ampolicy.h>
73 #include <stdlib.h>
74 #include <stdio.h>
75 #include <exception.h>
76 #include <fault.h>
77 #include <signal.h>
78 #include <ctype.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>
90 #undef event
91 #undef interval
92 #undef port
93
94 extern char *strdup();
95
96 /* a new family for Amoeba RPC connections */
97 #define AF_AMOEBA       33
98 #define FamilyAmoeba    33
99
100 #define MAX_TCPIP_RETRY 4
101 #define CIRCBUFSIZE     4096 /* was 1024 */
102
103 /*
104  * Amoeba channel description:
105  */
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 */
116 } XAmChanDesc;
117
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 */
122
123 /* Amoeba channel types */
124 #define ACDT_TCPIP      1               /* TCP/IP connection */
125 #define ACDT_VIRTCIRC   2               /* Amoeba virtual circuit connection */
126
127
128 #ifdef XSERV_t
129 #include "dix.h" /* clients[] needed by AmFindReadyClients */
130 #define Error(list) ErrorF list
131 #define Fatal(list) FatalError list
132 #else
133 #define Error(list) printf list
134 #define Fatal(list) { printf list; exit(1); }
135 #endif
136
137 #define dbprintf(list) /* printf list */
138 #define doprintf(list) printf list /**/
139
140 /*
141  * First: utility functions.
142  */
143
144 #if defined(XSERV_t) || defined(FS_t)
145
146 static semaphore main_sema;
147
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.
152  */
153 void
154 InitMainThread()
155 {
156     sema_init(&main_sema, 0);
157 }
158
159 void
160 WakeUpMainThread()
161 {
162     sema_up(&main_sema);
163 }
164
165 int
166 SleepMainThread(timeout)
167 am_interval_t timeout;
168 {
169     dbprintf(("Sleeping main thread timeout %d\n", timeout));
170     return (sema_trydown(&main_sema, timeout) == 0) ? 0 : -1;
171 }
172
173
174 static int init_waiters;
175 static semaphore init_sema;
176
177 void
178 AmInitWaitFor()
179 {
180     init_waiters = 0;
181     sema_init(&init_sema, 0);
182 }
183
184 /*
185  * Force caller thread to wait until main has finished the initialization.
186  */
187 void
188 WaitForInitialization()
189 {
190     init_waiters++;
191     dbprintf(("Waiting for initialization (%d)\n", init_waiters));
192     sema_down(&init_sema);
193 }
194
195 void
196 WakeupInitWaiters()
197 {
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) {
202             sema_up(&init_sema);
203         }
204     }
205 }
206
207 #endif /* XSERV_t || FS_t */
208
209
210 #define THREAD_STACK_SIZE (8*1024)
211
212 /*
213  * Amoeba connection information is stored in, so called,
214  * channel descriptors. Channel descriptors are identified
215  * by their index in the table below.
216  */
217 static XAmChanDesc XAmChanDescriptors[OPEN_MAX];
218 static void XAmCleanUpChanDesc(); /* forward */
219
220 /*
221  * Cleanup connection descriptors on a signal
222  */
223 static void
224 XAmSignalCleanUpChanDesc(sig)
225     int sig;
226 {
227     XAmCleanUpChanDesc();
228     _exit(sig | 0x80);
229 }
230
231 /*
232  * Cleanup connection descriptors
233  */
234 static void
235 XAmCleanUpChanDesc()
236 {
237     register int i;
238
239     for (i = 0; i < OPEN_MAX; i++) {
240         switch (XAmChanDescriptors[i].type) {
241         case ACDT_TCPIP:
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.
250              */
251             std_destroy(&XAmChanDescriptors[i].chancap);
252             break;
253         case ACDT_VIRTCIRC:
254             /* Close the virtual circuit asynchronously, or otherwise
255              * we may hang for a minute under some (?) conditions.
256              */
257             vc_close(XAmChanDescriptors[i].virtcirc, VC_BOTH | VC_ASYNC);
258             break;
259         }
260         XAmChanDescriptors[i].state = ACDS_FREE;
261     }
262 }
263
264 /*
265  * Allocate a channel descriptor
266  */
267 static XAmChanDesc *
268 XAmAllocChanDesc()
269 {
270     register int i;
271
272 #ifndef XSERV_t
273
274     static int initialized = 0;
275
276     /*
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 
281      * received.
282      */
283     if (!initialized) {
284         initialized = 1;
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);
294     }
295 #endif
296
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];
302         }
303     }
304     return NULL;
305 }
306
307 /*
308  * Convert ``file descriptor'' to channel descriptor
309  */
310 static XAmChanDesc *
311 XAmFdToChanDesc(fd)
312     int fd;
313 {
314     if (fd >= 0 && fd < OPEN_MAX) {
315         return &XAmChanDescriptors[fd];
316     } else {
317         return NULL;
318     }
319 }
320
321 /*
322  * Convert channel descriptor to ``file descriptor''
323  */
324 static int
325 XAmChanDescToFd(chandesc)
326     XAmChanDesc *chandesc;
327 {
328     return chandesc - XAmChanDescriptors;
329 }
330
331 /*
332  * Free channel descriptor
333  */
334 static void
335 XAmFreeChanDesc(chandesc)
336     XAmChanDesc *chandesc;
337 {
338     if (chandesc->sema) {
339         xfree(chandesc->sema);
340         chandesc->sema = NULL;
341     }
342     chandesc->state = ACDS_FREE;
343 }
344
345 static void XAmReaderThread();
346
347 static int
348 MakeAmConnection(phostname, idisplay, familyp, saddrlenp, saddrp)
349     char *phostname;
350     int idisplay;
351     int *familyp;                       /* RETURN */
352     int *saddrlenp;                     /* RETURN */
353     char **saddrp;                      /* RETURN */
354 {
355     capability xservercap;
356     char xserverpath[256];
357     XAmChanDesc *chandesc;
358     errstat err;
359
360     /* Amoeba requires a server hostname */
361     if (phostname == NULL || *phostname == '\0') {
362         fprintf(stderr, "MakeAmConnection: Display name expected\n");
363         return -1;
364     }
365
366     /* allocate channel descriptor */
367     chandesc = XAmAllocChanDesc();
368     if (chandesc == NULL) {
369         fprintf(stderr, "MakeAmConnection: Out of channel capabilities\n");
370         return -1;
371     }
372
373     /*
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.
378      */
379     (void)sprintf(xserverpath, "%s/%s:%d", DEF_XSVRDIR, phostname, idisplay);
380     if ((err = name_lookup(xserverpath, &xservercap)) == STD_OK) {
381         am_port_t vccaps[2];
382         bufsize size;
383         errstat err;
384         header hdr;
385
386         /* Amoeba virtual circuit connection */
387         chandesc->type = ACDT_VIRTCIRC;
388
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);
396         } else {
397             err = ERR_CONVERT(hdr.h_status);
398         }
399         if (err != STD_OK || size != sizeof(vccaps)) {
400             fprintf(stderr, "Xlib: connect to Amoeba X-server failed (%s)\n",
401                     err_why(err));
402             XAmFreeChanDesc(chandesc);
403             return -1;
404         }
405
406         /* setup an Amoeba virtual circuit */
407         chandesc->virtcirc =
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);
412             return -1;
413         }
414
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.
418          */
419         *familyp = AF_AMOEBA;
420         *saddrp = strdup("Amoeba");
421         *saddrlenp = strlen(*saddrp);
422     } else {
423         char tcpname[256];
424         capability tcpcap;
425         ipaddr_t ipaddr;
426         char *tcpsvr;
427         nwio_tcpcl_t tcpcl;
428         nwio_tcpconf_t tcpconf;
429         XAmChanDesc **param;
430         int result;
431
432         /* Amoeba TCP/IP connection */
433         chandesc->type = ACDT_TCPIP;
434
435         /* lookup up TCP/IP server */
436         if ((tcpsvr = getenv("TCP_SERVER")) == NULL) {
437             tcpsvr = TCP_SVR_NAME;
438         }
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);
444             return -1;
445         }
446
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);
453             return -1;
454         }
455
456         /* lookup TCP/IP hostname */
457         if (isdigit(phostname[0])) {
458             ipaddr = inet_addr(phostname);
459         } else {
460             struct hostent *hp = gethostbyname(phostname);
461             if (hp == NULL) {
462                 fprintf(stderr, "Xlib: %s unknown host\n", phostname);
463                 return -1;
464             }
465             memcpy(&ipaddr, hp->h_addr, hp->h_length);
466         }
467
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",
474                     tcpip_why(err));
475             std_destroy(&chandesc->chancap);
476             XAmFreeChanDesc(chandesc);
477             return -1;
478         }
479
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",
484                     tcpip_why(err));
485             std_destroy(&chandesc->chancap);
486             XAmFreeChanDesc(chandesc);
487             return -1;
488         }
489
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? */
494         *param = chandesc;
495         result = thread_newthread(XAmReaderThread, THREAD_STACK_SIZE,
496                                   (char *)param, sizeof(XAmChanDesc *));
497         if (result == 0) {
498             fprintf(stderr, "Xlib: Cannot start reader thread\n");
499             std_destroy(&chandesc->chancap);
500             XAmFreeChanDesc(chandesc);
501             return -1;
502         }
503         threadswitch(); /* give reader a try */
504
505         /*
506          * Family type is set to Internet so that the .Xauthority
507          * files from Unix will work under Amoeba (for Unix displays).
508          */
509         *familyp = AF_INET;
510         *saddrlenp = sizeof(ipaddr_t);
511         *saddrp = xalloc(sizeof(ipaddr_t));
512         memcpy(*saddrp, (char *)&ipaddr, sizeof(ipaddr_t)); /* error checking? */
513     }
514
515     return XAmChanDescToFd(chandesc);
516 }
517
518 /*
519  * The TCP/IP server silently assumes a maximum buffer size of 30000 bytes.
520  */
521 #define TCPIP_BUFSIZE   16384
522
523 static void
524 XAMCloseChannel(chandesc)
525 XAmChanDesc *chandesc;
526 {
527     if (chandesc->state == ACDS_USED && chandesc->type == ACDT_TCPIP) {
528         cb_close(chandesc->circbuf);
529         chandesc->state = ACDS_CLOSED;
530     }
531 }
532
533
534 /*
535  * Shutdown TCP/IP reader thread
536  */
537 static void
538 XAmReaderSignalCatcher(sig, us, extra)
539     signum sig;
540     thread_ustate *us;
541     _VOIDSTAR extra;
542 {
543     register XAmChanDesc *chandesc = (XAmChanDesc *)extra;
544
545     XAMCloseChannel(chandesc);
546     thread_exit();
547 }
548
549 /*
550  * TCP/IP reader thread
551  */
552 static void
553 XAmReaderThread(argptr, argsize)
554     void *argptr;
555     int argsize;
556 {
557     register XAmChanDesc *chandesc;
558
559     chandesc = *((XAmChanDesc **)argptr);
560     (void) sig_catch(chandesc->signal, XAmReaderSignalCatcher,
561                      (_VOIDSTAR) chandesc);
562
563     while (chandesc->state == ACDS_USED) {
564         char buffer[CIRCBUFSIZE];
565         bufsize size;
566
567         size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer));
568         if (ERR_STATUS(size) || size == 0) {
569             if (size == 0) {
570                 static char msg[] = "Xlib: TCP/IP channel closed\n";
571
572                 write(2, msg, sizeof(msg));
573             } else {
574                 fprintf(stderr, "Xlib: TCP/IP read failed (%s)\n",
575                         err_why(ERR_CONVERT(size)));
576             }
577             XAMCloseChannel(chandesc);
578             break;
579         }
580
581         if (cb_puts(chandesc->circbuf, buffer, size) != 0) {
582             fprintf(stderr, "Xlib: short write to circular buffer\n");
583             XAMCloseChannel(chandesc);
584         }
585     }
586
587     thread_exit();
588 }
589
590 /*
591  * Wait until input is available or until the timer expires.
592  */
593 int
594 TRANS(AmSelect)(ifd, timout)
595     int ifd;
596     int timout;
597 {
598     XAmChanDesc *chandesc;
599     int n;
600
601     errno = 0;
602
603     chandesc = XAmFdToChanDesc(ifd);
604     if (chandesc == NULL || chandesc->state != ACDS_USED) {
605         errno = EBADF;
606         return -1;
607     }
608
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.
613          */
614         chandesc->sema = (semaphore *) xalloc(sizeof(semaphore));
615         if (chandesc->sema == NULL) {
616             errno = ENOMEM;
617             return -1;
618         }
619
620         sema_init(chandesc->sema, 0);
621         switch (chandesc->type) {
622         case ACDT_TCPIP:
623             cb_setsema(chandesc->circbuf, chandesc->sema);
624             break;
625         case ACDT_VIRTCIRC:
626             vc_setsema(chandesc->virtcirc, chandesc->sema);
627             break;
628         }
629     }
630
631     switch (chandesc->type) {
632     case ACDT_TCPIP:
633         if ((n = cb_full(chandesc->circbuf)) != 0) {
634             if (n < 0) errno = EPIPE;
635             return n; /* includes error as well */
636         }
637         if (sema_trydown(chandesc->sema, timout) < 0) {
638             errno = EINTR;
639             return -1;
640         } else {
641             /* we down for all the bytes in AMRead, so undo the down */
642             sema_up(chandesc->sema);
643         }
644         if ((n = cb_full(chandesc->circbuf)) < 0) {
645             errno = EPIPE;
646             return -1;
647         }
648         return n;
649
650     case ACDT_VIRTCIRC:
651         if ((n = vc_avail(chandesc->virtcirc, VC_IN)) != 0) {
652             if (n < 0) errno = EPIPE;
653             return n; /* includes error as well */
654         }
655         if (sema_trydown(chandesc->sema, timout) < 0) {
656             errno = EINTR;
657             return -1;
658         } else {
659             /* we down for all the bytes in AMRead, so undo the down */
660             sema_up(chandesc->sema);
661         }
662         if ((n = vc_avail(chandesc->virtcirc, VC_IN)) < 0) {
663             errno = EPIPE;
664             return -1;
665         }
666         return n;
667     }
668
669     errno = EINVAL;
670     return -1;
671 }
672
673 /*
674  * This function gets the local address of the transport and stores it in the
675  * XtransConnInfo structure for the connection.
676  */
677
678 static int
679 TRANS(AMGetAddr)(ciptr)
680 XtransConnInfo  ciptr;
681 {
682     PRMSG(1,"AMGetAddr(%x)\n", ciptr, 0,0 );
683     PRMSG(1,"AMGetAddr: TODO\n", 0, 0, 0);
684
685     return -1;
686 }
687
688
689 /*
690  * This function gets the remote address of the socket and stores it in the
691  * XtransConnInfo structure for the connection.
692  */
693
694 static int
695 TRANS(AMGetPeerAddr)(ciptr)
696 XtransConnInfo  ciptr;
697 {
698     struct nwio_tcpconf tcpconf;
699     errstat err;
700     XAmChanDesc *chandesc;
701
702     PRMSG(2,"AMGetPeerAddr(%x)\n", ciptr, 0,0 );
703
704     chandesc = XAmFdToChanDesc(ciptr->fd);
705     if (chandesc == NULL || chandesc->state != ACDS_USED) {
706         errno = EBADF;
707         return -1;
708     }
709
710     switch (chandesc->type) {
711     case ACDT_TCPIP:
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",
715                    (int) err, 0, 0);
716             return -1;
717         }
718
719 #if 0 /* debug */
720         {
721             struct hostent *remote;
722             char *hostname;
723
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);
728             } else {
729                 hostname = remote->h_name;
730             }
731             PRMSG (1, "AMGetPeerAddr: remote addr `%s'\n",
732                    hostname, 0, 0);
733         }
734 #endif
735
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",
740                    0, 0, 0);
741             return -1;
742         }
743
744         memcpy (ciptr->peeraddr, &tcpconf.nwtc_remaddr, ciptr->peeraddrlen);
745         break;
746
747     case ACDT_VIRTCIRC:
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",
751                    0, 0, 0);
752             return -1;
753         }
754
755         ciptr->peeraddrlen = ciptr->addrlen;
756         memcpy (ciptr->peeraddr, ciptr->addr, ciptr->peeraddrlen);
757         break;
758     }
759
760     return 0;
761 }
762
763
764 static XtransConnInfo
765 TRANS(AMOpen)(device)
766 char    *device;
767 {
768     PRMSG(1,"AMOpen(%s)\n", device, 0,0 );
769     PRMSG(1,"AMOpen: TODO\n", 0, 0, 0);
770
771     return NULL;
772 }
773
774
775 static  int
776 TRANS(AMAddrToNetbuf)(tlifamily, host, port, netbufp)
777 int             tlifamily;
778 char            *host;
779 char            *port;
780 struct netbuf   *netbufp;
781 {
782     PRMSG(1,"AMAddrToNetbuf(%d,%s,%s)\n", tlifamily, host, port );
783     PRMSG(1,"AMAddrToNetbuf: TODO\n", 0, 0, 0);
784
785     return -1;
786 }
787
788 /*
789  * These functions are the interface supplied in the Xtransport structure
790  */
791
792 #ifdef TRANS_CLIENT
793
794 static XtransConnInfo
795 TRANS(AMOpenCOTSClient)(thistrans, protocol, host, port)
796 Xtransport      *thistrans;
797 char            *protocol;
798 char            *host;
799 char            *port;
800 {
801     XtransConnInfo  ciptr;
802     XAmChanDesc    *chandesc;
803
804     PRMSG(2,"AMOpenCOTSClient(%s,%s,%s)\n", protocol, host, port );
805     
806     ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
807     if (ciptr == NULL) {
808         PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0);
809         return NULL;
810     }
811
812     ciptr->fd = MakeAmConnection (host, 0 /* TODO */, &ciptr->family,
813                                   &ciptr->addrlen, &ciptr->addr);
814     if (ciptr->fd < 0) {
815         PRMSG(1,"AMOpenCOTSClient: Unable to make connection to %s\n",
816               host, 0,0 );
817         xfree(ciptr);
818         return NULL;
819     }
820
821     /* set the back pointer */
822     chandesc = XAmFdToChanDesc(ciptr->fd);
823     chandesc->conninfo = ciptr;
824
825     TRANS(AMGetPeerAddr)(ciptr);
826
827     PRMSG(2,"AMOpenCOTSClient: made connection to %s; fd = %d, family = %d\n",
828           host, ciptr->fd, ciptr->family);
829
830     return ciptr;
831 }
832
833 #endif /* TRANS_CLIENT */
834
835 #if defined(XSERV_t) || defined(FS_t)
836
837 /* The following defines come from osdep.h;
838  * they should removed from there eventually.
839  */
840
841 /*
842  * Some fundamental constants
843  */
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 */
848
849 /*
850  * OsComm status bits
851  */
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 */
857
858
859 #define REPLY_BUFSIZE   30000
860
861 capability      X;                      /* X capability */
862 char            *XServerHostName;       /* X server host name */
863 char            *XTcpServerName;        /* TCP/IP server name */
864
865 static XtransConnInfo NewConns[MAXTASKS]; /* new client connections */
866 int                   nNewConns;          /* # of new clients */
867
868 int             maxClient;              /* Highest allocated client fd + 1*/
869 static int      minClient = 1;          /* Lowest allocated client fd */
870
871 static char *
872 OsCommStatus(status)
873     int status;
874 {
875     static char buf[100];
876
877     buf[0] = '\0';
878     if (status == 0)
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);
888     if (status & IGNORE)
889         sprintf(buf, "%s IGNORE", buf);
890     return buf;
891 }
892
893 static char *
894 OsCommFamily(family)
895     int family;
896 {
897     if (family == FamilyAmoeba) {
898         return "AMOEBA";
899     } else {
900         return "TCP/IP";
901     }
902 }
903
904
905 /*
906  * Return status information about the open connections
907  */
908 static errstat
909 ConnectionStatus(hdr, buf, size)
910     header *hdr;
911     char *buf;
912     int size;
913 {
914     char        *begin, *end;
915     char        *bprintf();
916     int fd;
917     XAmChanDesc *chandesc;
918
919     begin = buf;
920     end = buf + size;
921
922
923     /* all active clients */
924     begin = bprintf(begin, end, "Active clients:\n");
925     for (fd = minClient; fd < maxClient; fd++) {
926         static XAmChanDesc *chandesc;
927
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));
933         }
934     }
935
936     if (begin == NULL) {
937         hdr->h_size = 0;
938         return STD_SYSERR;
939     } else {
940         hdr->h_size = begin - buf;
941         return STD_OK;
942     }
943 }
944
945 /*
946  * Wakeup main thread if necessary
947  */
948 static void
949 UnblockMain(fd)
950 int fd;
951 {
952     XAmChanDesc *chandesc;
953
954     chandesc = XAmFdToChanDesc(fd);
955     if (chandesc != NULL) {
956         if ((chandesc->status & IGNORE) == 0) {
957             WakeUpMainThread();
958         }
959     } else {
960         Error(("UnblockMain: invalid fd %d\n", fd));
961     }
962 }
963
964 static void
965 TcpIpReaderSignalCatcher(sig, us, extra)
966     signum sig;
967     thread_ustate *us;
968     _VOIDSTAR extra;
969 {
970     XAmChanDesc *chandesc = (XAmChanDesc *) extra;
971
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));
978         }
979     }
980
981     chandesc->signal = -1;
982     thread_exit();
983 }
984
985 void
986 TcpIpReaderThread(argptr, argsize)
987     void *argptr;
988     int argsize;
989 {
990     XAmChanDesc *chandesc;
991
992     if (argsize != sizeof(XAmChanDesc *)) {
993         Fatal(("Internal error: TcpIpReaderThread incorrectly called\n"));
994     }
995
996     chandesc = * ((XAmChanDesc **) argptr);
997     (void) sig_catch(chandesc->signal, TcpIpReaderSignalCatcher,
998                      (_VOIDSTAR) chandesc);
999
1000     for (;;) {
1001         char buffer[MAXBUFSIZE];
1002         bufsize size;
1003
1004         size = tcpip_read(&chandesc->chancap, buffer, sizeof(buffer));
1005
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;
1012             thread_exit();
1013         }
1014
1015         if (size == 0 || cb_puts(chandesc->circbuf, buffer, size)) {
1016             if (size != 0) {
1017                 Error(("TCP/IP short write to circular buffer for %d\n",
1018                        XAmChanDescToFd(chandesc)));
1019             } else {
1020                 Error(("TCP/IP read failed for client %d\n",
1021                        XAmChanDescToFd(chandesc)));
1022             }
1023
1024             chandesc->status |= CONN_KILLED;
1025             chandesc->status &= ~CONN_ALIVE;
1026             chandesc->signal = -1;
1027             thread_exit();
1028         }
1029         UnblockMain(XAmChanDescToFd(chandesc));
1030     }
1031 }
1032
1033 static XAmChanDesc *
1034 AllocClientChannel()
1035 {
1036     XAmChanDesc *chandesc;
1037     int fd;
1038
1039     chandesc = XAmAllocChanDesc();
1040     if (chandesc == NULL) {
1041         return NULL;
1042     }
1043
1044     fd = XAmChanDescToFd(chandesc);
1045     if (fd >= maxClient) {
1046         maxClient = fd + 1;
1047         dbprintf(("new max Client: %d\n", fd));
1048     }
1049     if (fd < minClient) {
1050         minClient = fd;
1051     }
1052
1053     return chandesc;
1054 }
1055
1056 static errstat
1057 AmRegisterRPCconn(client_ports, server_ports)
1058 am_port_t client_ports[2];
1059 am_port_t server_ports[2];
1060 {
1061     XAmChanDesc *chandesc;
1062
1063     if ((chandesc = AllocClientChannel()) == NULL) {
1064         return STD_NOSPACE;
1065     }
1066
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);
1073         return STD_NOSPACE;
1074     }
1075
1076     dbprintf(("Amoeba connection registered\n"));
1077
1078     vc_warn(chandesc->virtcirc, VC_IN, UnblockMain, XAmChanDescToFd(chandesc));
1079     
1080     chandesc->status = CONN_INIT;
1081
1082     /* cause WaitFor to call EstablishNewConnections: */
1083     nNewConns++;
1084     WakeUpMainThread();
1085
1086     return STD_OK;
1087 }
1088
1089 static XAmChanDesc *
1090 XAmFetchConnectingClient()
1091 {
1092     XAmChanDesc *chandesc;
1093     int fd;
1094
1095     for (fd = minClient; fd < maxClient; fd++) {
1096         chandesc = XAmFdToChanDesc(fd);
1097
1098         if (chandesc->status & CONN_INIT) {
1099             Error(("Client %d is connecting\n", fd));
1100             chandesc->status &= ~CONN_INIT;
1101             return chandesc;
1102         }
1103     }
1104
1105     return NULL;
1106 }
1107
1108 static errstat
1109 AmRegisterTCPconn(chancap)
1110 capability *chancap;
1111 {
1112     XAmChanDesc *chandesc, **param;
1113
1114     if ((chandesc = AllocClientChannel()) == NULL) {
1115         return STD_NOSPACE;
1116     }
1117     
1118     chandesc->type = ACDT_TCPIP;
1119     chandesc->chancap = *chancap;
1120
1121     if ((chandesc->circbuf = cb_alloc(MAXBUFSIZE)) == NULL) {
1122         Error(("TCPconn refused: No memory for circular buffer\n"));
1123         XAmFreeChanDesc(chandesc);
1124         return STD_NOSPACE;
1125     }
1126
1127     chandesc->signal = sig_uniq();
1128     param = (XAmChanDesc **) xalloc(sizeof(XAmChanDesc *)); /* error checking? */
1129     *param = chandesc;
1130     if (thread_newthread(TcpIpReaderThread, MAXBUFSIZE + CONNECTOR_STACK,
1131                          (char *)param, sizeof(XAmChanDesc *)) == 0)
1132     {
1133         Error(("TCPconn refused: Cannot start reader thread\n"));
1134         cb_close(chandesc->circbuf);
1135         cb_free(chandesc->circbuf);
1136         XAmFreeChanDesc(chandesc);
1137         return STD_NOSPACE;
1138     }
1139
1140     dbprintf(("TCP connection registered\n"));
1141
1142     chandesc->status = CONN_INIT;
1143
1144     /* cause WaitFor to call EstablishNewConnections: */
1145     nNewConns++;
1146     WakeUpMainThread();
1147
1148     return STD_OK;
1149 }
1150
1151
1152 /*
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.
1159  */
1160 static void
1161 AmConnectorThread()
1162 {
1163     header      req, rep;
1164     am_port_t   client_ports[2];
1165     am_port_t   server_ports[2];
1166     short       s;
1167     char        *repb;
1168     extern      CreateNewClient();
1169
1170     WaitForInitialization();
1171     dbprintf(("AmConnectorThread() running ...\n"));
1172     if ((repb = (char *)xalloc(REPLY_BUFSIZE)) == NULL) {
1173         Fatal(("Amoeba connector thread: malloc failed"));
1174     }
1175     for (;;) {
1176         do {
1177             req.h_port = X.cap_port;
1178             s = getreq(&req, NILBUF, 0);
1179         } while (ERR_CONVERT(s) == RPC_ABORTED);
1180         if (ERR_STATUS(s))
1181             Fatal(("Amoeba connector thread: getreq failed"));
1182
1183         /* TODO: check privilege fields here */
1184
1185         dbprintf(("AmConnectorThread() accepting a request\n"));
1186
1187         switch (req.h_command) {
1188
1189         case STD_INFO:
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);
1194             break;
1195
1196         case STD_STATUS:
1197             rep.h_status = ConnectionStatus(&rep, repb, REPLY_BUFSIZE);
1198             putrep(&rep, repb, rep.h_size);
1199             break;
1200
1201 #ifdef XSERV_t
1202         case AX_SHUTDOWN:
1203             rep.h_status = STD_OK;
1204             putrep(&rep, NILBUF, 0);
1205             GiveUp(SIGTERM);
1206             break;
1207
1208         case AX_REINIT:
1209             rep.h_status = STD_OK;
1210             putrep(&rep, NILBUF, 0);
1211             AutoResetServer(SIGINT);
1212             break;
1213 #endif
1214
1215         case AX_CONNECT:
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]);
1220
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));
1224             } else {
1225                 putrep(&rep, NILBUF, 0);
1226             }
1227             break;
1228
1229         default:
1230             rep.h_status = STD_COMBAD;
1231             putrep(&rep, NILBUF, 0);
1232             break;
1233         }
1234     }
1235 }
1236
1237 #ifdef XSERV_t
1238
1239 /*
1240  * To prevent the X-server from generating lots of error messages,
1241  * in case the server is gone or when its full.
1242  */
1243 #define LOOP_OPEN       1
1244 #define LOOP_SETCONF    2
1245 #define LOOP_LISTEN     4
1246
1247 extern char *display;           /* The display number */
1248
1249 /*
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.
1254  */
1255 static void
1256 AmTCPConnectorThread()
1257 {
1258     capability          svrcap, chancap;
1259     nwio_tcpconf_t      tcpconf;
1260     nwio_tcpcl_t        tcpconnopt;
1261     char                name[BUFSIZ];
1262     errstat             err;
1263     int                 result;
1264     int                 looping = 0;
1265
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)));
1271     }
1272
1273     WaitForInitialization();
1274     dbprintf(("AmTCPConnectorThread() running ...\n"));
1275
1276     for (;;) {
1277         /*
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 :-)
1281          */
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;
1287             }
1288             sleep(60);
1289             (void) name_lookup(name, &svrcap);
1290             continue;
1291         }
1292         looping &= ~LOOP_OPEN;
1293
1294         tcpconf.nwtc_locport = htons(X_TCP_PORT + atoi(display));
1295         tcpconf.nwtc_flags = NWTC_EXCL | NWTC_LP_SET | NWTC_UNSET_RA | 
1296                                                                 NWTC_UNSET_RP;
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;
1302             }
1303             std_destroy(&chancap);
1304             sleep(60);
1305             continue;
1306         }
1307         looping &= ~LOOP_SETCONF;
1308
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;
1315             }
1316             std_destroy(&chancap);
1317             sleep(60);
1318             continue;
1319         }
1320         looping &= ~LOOP_LISTEN;
1321
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);
1325             continue;
1326         }
1327
1328         err = AmRegisterTCPconn(&chancap);
1329         if (err != STD_OK) {
1330             Error(("AmRegisterTCPconn failed (%s)\n", err_why(err)));
1331             std_destroy(&chancap);
1332         }
1333     }
1334 }
1335
1336 static void
1337 AmStartXserverThreads(chandesc)
1338 XAmChanDesc *chandesc;
1339 {
1340     char                host[100];
1341     errstat             err;
1342     capability          pubX;
1343     static int          threadsStarted = 0;
1344
1345     /*
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.
1349      */
1350     if (!threadsStarted) {
1351         threadsStarted = 1;
1352
1353         /*
1354          * Create a new capability for this X server
1355          */
1356         if (XServerHostName == NULL)
1357             XServerHostName = getenv("XHOST");
1358         if (XServerHostName == NULL) {
1359             Fatal(("XHOST not set, or server host name not given\n"));
1360         }
1361         sprintf(host, "%s/%s:%s", DEF_XSVRDIR, XServerHostName, display);
1362
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)));
1368             exit(1);
1369         }
1370
1371         /* Allow WaitFor module to initialize */
1372         AmInitWaitFor();
1373
1374         /* Also, initialize main thread locking */
1375         InitMainThread();
1376
1377         /* Initialize and start IOP reader thread */
1378         InitializeIOPServerReader();
1379
1380         /* Start native Amoeba service threads */
1381         if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) {
1382             Fatal(("Cannot start Amoeba connector thread\n"));
1383         }
1384         if (thread_newthread(AmConnectorThread, CONNECTOR_STACK, 0, 0) <= 0) {
1385             Fatal(("Cannot start Amoeba connector thread\n"));
1386         }
1387         chandesc->type = ACDT_VIRTCIRC;
1388         chandesc->status = CONN_ALIVE;
1389
1390         /*
1391          * Start TCP/IP service threads
1392          */
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"));
1400         }
1401     }
1402 }
1403
1404 int
1405 AmFindReadyClients(pClientsReady, mask)
1406 int *pClientsReady;
1407 long *mask;
1408 {
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.
1414      */
1415     extern int ConnectionTranslation[];
1416     XAmChanDesc *chandesc;
1417     int fd;
1418     int nready;
1419
1420     /* Since we're scheduled non-preemptively by default, allow the
1421      * listener threads to run first, if needed:
1422      */
1423     threadswitch();
1424
1425     nready = 0;
1426     for (fd = minClient; fd < maxClient; fd++) {
1427         int which;
1428         int n;
1429
1430         if (fd > 0 && (fd % 32) == 0) {
1431             /* switch to next fd mask */
1432             mask++;
1433         }
1434
1435         if ((*mask & (1L << fd)) == 0) {
1436             dbprintf(("skip %d\n", fd));
1437             continue;
1438         }
1439
1440         chandesc = XAmFdToChanDesc(fd);
1441         if (chandesc->state != ACDS_USED) {
1442             dbprintf(("AmFindReady: fd %d not in use\n", fd));
1443             continue;
1444         }
1445
1446         which = ConnectionTranslation[fd];
1447         dbprintf(("checking client %d (fd %d) of %d\n",
1448                   fd, which, maxClient));
1449
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);
1454             continue;
1455         }
1456
1457         if ((chandesc->status & CONN_ALIVE) == 0) {
1458             dbprintf(("conn with %d is not alive\n", fd));
1459             continue;
1460         }
1461
1462         /* see if there is data available */
1463         switch (chandesc->type) {
1464         case ACDT_TCPIP:
1465             n = cb_full(chandesc->circbuf);
1466             break;
1467         case ACDT_VIRTCIRC:
1468             n = vc_avail(chandesc->virtcirc, VC_IN);
1469             break;
1470         default:
1471             n = -1;
1472         }
1473
1474         if (n < 0) {
1475             dbprintf(("avail %d; close client %d\n", n, which));
1476             CloseDownClient(clients[which]);
1477             continue;
1478         } else {
1479             if (n > 0) {
1480                 *pClientsReady++ = which;
1481                 nready++;
1482                 dbprintf(("client %d has %d bytes available\n", which, n));
1483             } else {
1484                 dbprintf(("client %d has no data available\n", which, n));
1485             }
1486         }
1487
1488         /* Clients that already have (possibly inserted) data are found
1489          * with help from io.c (the ClientsWithData bit array).
1490          */
1491     }
1492
1493     return nready;
1494 }
1495
1496 #endif /* XSERV_t */
1497
1498 #endif /* XSERV_t || FS_t */
1499
1500 static
1501 TRANS(AmSetAddr)(ciptr, chandesc)
1502     XtransConnInfo  ciptr;
1503     XAmChanDesc    *chandesc;
1504 {
1505     switch (chandesc->type) {
1506     case ACDT_TCPIP:
1507         /* should really ask the TCP/IP server */
1508         ciptr->family = AF_INET;
1509         ciptr->addr = strdup("XXXXTODO");
1510         ciptr->addrlen = strlen("XXXXTODO");
1511         break;
1512     case ACDT_VIRTCIRC:
1513         /* For Amoeba connections the adress is not really used,
1514          * so just fake something
1515          */
1516         ciptr->family = AF_AMOEBA;
1517         ciptr->addr = strdup("Amoeba");
1518         ciptr->addrlen = strlen(ciptr->addr);
1519         break;
1520     }
1521 }
1522
1523 #ifdef TRANS_SERVER
1524
1525 static XtransConnInfo
1526 TRANS(AMOpenCOTSServer)(thistrans, protocol, given_host, port)
1527 Xtransport      *thistrans;
1528 char            *protocol;
1529 char            *given_host;
1530 char            *port;
1531 {
1532     XAmChanDesc    *chandesc;
1533     XtransConnInfo  ciptr;
1534
1535     PRMSG(2,"AMOpenCOTSServer(%s,%s,%s)\n", protocol, given_host, port);
1536
1537     ciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
1538     if (ciptr == NULL) {
1539         PRMSG (1, "AMOpenCotsClient: malloc failed\n", 0, 0, 0);
1540         return NULL;
1541     }
1542
1543     chandesc = XAmAllocChanDesc();
1544     if (chandesc == NULL) {
1545         return NULL;
1546     }
1547
1548 #ifdef XSERV_t
1549     AmStartXserverThreads(chandesc);
1550 #endif
1551
1552     chandesc->conninfo = ciptr;
1553     ciptr->fd = XAmChanDescToFd(chandesc);
1554
1555     TRANS(AmSetAddr)(ciptr, chandesc);
1556     TRANS(AMGetPeerAddr)(ciptr);
1557
1558     return ciptr;
1559 }
1560
1561 #endif /* TRANS_SERVER */
1562
1563
1564 #ifdef TRANS_CLIENT
1565
1566 static XtransConnInfo
1567 TRANS(AMOpenCLTSClient)(thistrans, protocol, host, port)
1568 Xtransport      *thistrans;
1569 char            *protocol;
1570 char            *host;
1571 char            *port;
1572 {
1573     XtransConnInfo      ciptr;
1574     int                 i;
1575     
1576     PRMSG(1,"AMOpenCLTSClient(%d,%s,%s)\n", protocol, host, port );
1577     /* TODO */
1578     return NULL;
1579 }                       
1580
1581 #endif /* TRANS_CLIENT */
1582
1583
1584 #ifdef TRANS_SERVER
1585
1586 static XtransConnInfo
1587 TRANS(AMOpenCLTSServer)(thistrans, protocol, host, port)
1588 Xtransport      *thistrans;
1589 char            *protocol;
1590 char            *host;
1591 char            *port;
1592 {
1593     XtransConnInfo      ciptr;
1594     int                 i;
1595     
1596     PRMSG(1,"AMOpenCLTSServer(%d,%s,%s)\n", protocol, host, port );
1597     /* TODO */
1598     return NULL;
1599 }                       
1600
1601 static int
1602 TRANS(AMResetListener)(ciptr)
1603 XtransConnInfo  ciptr;
1604 {
1605     PRMSG(2,"AMResetListener()\n", 0, 0, 0 );
1606
1607     /* nothing to do? */
1608     return 0;
1609 }
1610
1611 #endif /* TRANS_SERVER */
1612
1613 static
1614 TRANS(AMSetOption)(ciptr, option, arg)
1615 XtransConnInfo  ciptr;
1616 int             option;
1617 int             arg;
1618 {
1619     PRMSG(1,"AMSetOption(%d,%d,%d)\n", ciptr->fd, option, arg );
1620     /* TODO */
1621     return -1;
1622 }
1623
1624
1625 #ifdef TRANS_SERVER
1626
1627 static
1628 TRANS(AMCreateListener)(ciptr, req)
1629 XtransConnInfo  ciptr;
1630 char           *req;
1631 {
1632     PRMSG(2,"AMCreateListener(%x->%d,%x)\n", ciptr, ciptr->fd, req );
1633
1634     /* Listener threads are already created at this point */
1635     return 0;
1636 }
1637
1638
1639 static XtransConnInfo
1640 TRANS(AMAccept)(ciptr)
1641 XtransConnInfo  ciptr;
1642 {
1643     XAmChanDesc    *chandesc;
1644     XtransConnInfo  newciptr;
1645
1646     PRMSG(2,"AMAccept(%x->%d)\n", ciptr, ciptr->fd, 0 );
1647
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);
1652         return NULL;
1653     }
1654     nNewConns--;
1655
1656     newciptr = (XtransConnInfo) xcalloc (1, sizeof(struct _XtransConnInfo));
1657     if (newciptr == NULL)
1658     {
1659         PRMSG (1, "AMAccept: malloc failed\n", 0, 0, 0);
1660         return NULL;
1661     }
1662
1663     newciptr->fd = XAmChanDescToFd(chandesc);
1664     chandesc->conninfo = newciptr;
1665     chandesc->status |= CONN_ALIVE;
1666
1667     PRMSG(2,"AMAccept: OK: (%x->%d)\n", newciptr, newciptr->fd, 0 );
1668
1669     TRANS(AmSetAddr)(newciptr, chandesc);
1670     TRANS(AMGetPeerAddr)(newciptr);
1671     
1672     return newciptr;
1673 #else
1674     return NULL;
1675 #endif
1676 }
1677
1678 #endif /* TRANS_SERVER */
1679
1680
1681 #ifdef TRANS_CLIENT
1682
1683 static
1684 TRANS(AMConnect)(ciptr, host, port)
1685 XtransConnInfo  ciptr;
1686 char            *host;
1687 char            *port;
1688 {
1689     /* If this function is called, we are already connected */
1690     PRMSG(2, "AMConnect(%d,%s)\n", ciptr->fd, host, 0);
1691     return 0;
1692 }
1693
1694 #endif /* TRANS_CLIENT */
1695
1696
1697 int
1698 TRANS(AmFdBytesReadable)(fd, count)
1699 int fd;
1700 BytesReadable_t *count;
1701 {
1702     register XAmChanDesc *chandesc;
1703
1704     PRMSG(2, "AmFdBytesReadable(%d,%x): ", fd, count, 0 );
1705
1706 #ifndef XSERV_t
1707     /* give reader threads a chance: */
1708     threadswitch();
1709 #endif
1710
1711     errno = 0;
1712     chandesc = XAmFdToChanDesc(fd);
1713     if (chandesc == NULL || chandesc->state != ACDS_USED) {
1714         errno = EBADF;
1715         *count = 0;
1716         return -1;
1717     }
1718
1719     switch (chandesc->type) {
1720     case ACDT_TCPIP:
1721         *count = cb_full(chandesc->circbuf);
1722         break;
1723     case ACDT_VIRTCIRC:
1724         *count = vc_avail(chandesc->virtcirc, VC_IN);
1725         break;
1726     }
1727
1728     if (*count < 0) {
1729         errno = (chandesc->state == ACDS_CLOSED) ? EINTR : EPIPE;
1730         *count = 0;
1731         return -1;
1732     }
1733
1734     PRMSG(2, "AMFdBytesReadable: %d\n", *count, 0, 0 );
1735
1736     return 0;
1737 }
1738
1739 static
1740 TRANS(AMBytesReadable)(ciptr, count)
1741 XtransConnInfo  ciptr;
1742 BytesReadable_t *count;
1743 {
1744     return TRANS(AmFdBytesReadable)(ciptr->fd, count);
1745 }
1746
1747
1748 static
1749 TRANS(AMRead)(ciptr, buf, count)
1750 XtransConnInfo  ciptr;
1751 char            *buf;
1752 int             count;
1753 {
1754     int fdi;
1755     register XAmChanDesc *chandesc;
1756     register int rv;
1757     BytesReadable_t avail;
1758
1759     fdi = ciptr->fd;
1760     PRMSG(2, "AMRead(%d,%x,%d)\n", ciptr->fd, buf, count );
1761
1762     errno = 0;
1763     chandesc = XAmFdToChanDesc(fdi);
1764     if (chandesc == NULL || chandesc->state != ACDS_USED) {
1765         errno = EBADF;
1766         return -1;
1767     }
1768
1769     /* do a non-blocking read (maybe only conditionally?) */
1770     if ((TRANS(AMBytesReadable)(ciptr, &avail)) == 0) {
1771         if (avail <= 0) {
1772             PRMSG(2, "AMRead: nothing available yet\n", 0, 0, 0);
1773             errno = EAGAIN;
1774             return 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 */
1779         }
1780     } else {
1781         PRMSG(1, "AMRead: ...BytesReadable failed\n", 0, 0, 0);
1782         return -1;
1783     }
1784
1785     switch (chandesc->type) {
1786     case ACDT_TCPIP:
1787         rv = cb_gets(chandesc->circbuf, buf, count, count);
1788         if (rv != count) {
1789             if (rv == 0) {
1790                 fprintf(stderr, "Xlib: Cannot read circbuf\n");
1791                 errno = EPIPE;
1792                 rv = -1;
1793             } else {
1794                 fprintf(stderr, "Xlib: Cannot read circbuf (%d)\n", rv);
1795             }
1796         }
1797         break;
1798
1799     case ACDT_VIRTCIRC:
1800         rv = vc_readall(chandesc->virtcirc, buf, count);
1801         if (rv < 0) {
1802             fprintf(stderr, "Xlib: Cannot read virtual circuit\n");
1803             errno = EPIPE;
1804             rv = -1;
1805         }
1806         break;
1807     }
1808
1809     /* The circular buffer writer will only UP the semaphore when
1810      * characters are available; we have to down it ourselfs.
1811      */
1812     if (chandesc->sema && rv > 0)
1813         sema_mdown(chandesc->sema, rv);
1814
1815     PRMSG(2, "AMRead: %d bytes\n", rv, 0, 0);
1816
1817     return rv;
1818 }
1819
1820
1821 static
1822 TRANS(AMWrite)(ciptr, buf, count)
1823 XtransConnInfo  ciptr;
1824 char            *buf;
1825 int             count;
1826 {
1827     register XAmChanDesc *chandesc;
1828     register int written;
1829     
1830     PRMSG(2, "AMWrite(%d,%x,%d)\n", ciptr->fd, buf, count );
1831
1832     errno = 0;
1833     written = 0;
1834
1835     chandesc = XAmFdToChanDesc(ciptr->fd);
1836     if (chandesc == NULL || chandesc->state != ACDS_USED) {
1837         errno = EBADF;
1838         return -1;
1839     }
1840
1841     switch (chandesc->type) {
1842     case ACDT_TCPIP:
1843         while (count > 0) {
1844             bufsize bsize;
1845             int wrcnt;
1846
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)));
1852                 errno = EPIPE;
1853                 return -1;
1854             }
1855             if (bsize != wrcnt) {
1856                 fprintf(stderr,
1857                         "Xlib: TCP/IP write failed (expected %d, wrote %d)\n",
1858                         (int)bsize, wrcnt);
1859                 errno = EPIPE;
1860                 return -1;
1861             }
1862             buf += bsize;
1863             count -= (int) bsize;
1864             written += (int) bsize;
1865         }
1866         break;
1867
1868     case ACDT_VIRTCIRC:
1869         if ((written = vc_write(chandesc->virtcirc, buf, count)) < 0) {
1870             fprintf(stderr, "Xlib: virtual circuit write failed\n");
1871             errno = EPIPE;
1872             return -1;
1873         }
1874         break;
1875     }
1876
1877     return written;
1878 }
1879
1880
1881 static
1882 TRANS(AMReadv)(ciptr, iov, n)
1883 XtransConnInfo  ciptr;
1884 struct iovec   *iov;
1885 int             n;
1886 {
1887     int i;
1888     int count = 0, thiscount;
1889
1890     PRMSG(2, "AMReadv(%d,%x,%d)\n", ciptr->fd, ciptr, n );
1891
1892     for (i = 0; i < n; i++, iov++) {
1893         if (iov->iov_len) {
1894             thiscount = TRANS(AMRead)(ciptr, iov->iov_base, iov->iov_len);
1895             if (thiscount < 0) return thiscount;
1896             count += thiscount;
1897             if (thiscount < iov->iov_len) break;
1898         }
1899     }
1900
1901     return count;
1902 }
1903
1904
1905 static
1906 TRANS(AMWritev)(ciptr, iov, n)
1907 XtransConnInfo  ciptr;
1908 struct iovec    *iov;
1909 int             n;
1910 {
1911     int i;
1912     int count = 0, thiscount;
1913
1914     PRMSG(2, "AMWritev(%d,%x,%d)\n", ciptr->fd, iov, n );
1915
1916     for (i = 0; i < n; i++, iov++) {
1917         if (iov->iov_len) {
1918             thiscount = TRANS(AMWrite)(ciptr, iov->iov_base, iov->iov_len);
1919             if (thiscount < 0)
1920                 return thiscount;
1921             count += thiscount;
1922             if (thiscount < iov->iov_len) break;
1923         }
1924     }
1925
1926     return count;
1927 }
1928
1929
1930 static
1931 TRANS(AMDisconnect)(ciptr)
1932 XtransConnInfo  ciptr;
1933 {
1934     register XAmChanDesc *chandesc;
1935
1936     PRMSG(2, "AMDisconnect(%x->%d)\n", ciptr, ciptr->fd, 0 );
1937
1938     chandesc = XAmFdToChanDesc(ciptr->fd);
1939     if (chandesc != NULL) {
1940         switch (chandesc->type) {
1941         case ACDT_TCPIP:
1942             if (chandesc->signal != -1) {
1943                 sig_raise(chandesc->signal);
1944                 chandesc->signal = -1;
1945             }
1946             std_destroy(&chandesc->chancap);
1947             break;
1948
1949         case ACDT_VIRTCIRC:
1950             vc_close(chandesc->virtcirc, VC_BOTH | VC_ASYNC);
1951             break;
1952         }
1953 #ifdef XSERV_t
1954         if (ciptr->fd == maxClient - 1) {
1955             maxClient--;
1956             /* we could look if maxClient can be reduced even more */
1957         }
1958 #endif
1959         XAmFreeChanDesc(chandesc);
1960     }
1961
1962     return 0;
1963 }
1964
1965
1966 static
1967 TRANS(AMClose)(ciptr)
1968 XtransConnInfo  ciptr;
1969 {
1970     PRMSG(2, "AMClose(%x->%d)\n", ciptr, ciptr->fd, 0 );
1971
1972     return TRANS(AMDisconnect)(ciptr);
1973 }
1974
1975
1976 Xtransport      TRANS(AmConnFuncs) = {
1977         /* Combined AMOEBA RPC/TCP Interface; maybe we should split this  */
1978         "amcon",
1979         0,
1980 #ifdef TRANS_CLIENT
1981         TRANS(AMOpenCOTSClient),
1982 #endif /* TRANS_CLIENT */
1983 #ifdef TRANS_SERVER
1984         TRANS(AMOpenCOTSServer),
1985 #endif /* TRANS_SERVER */
1986 #ifdef TRANS_CLIENT
1987         TRANS(AMOpenCLTSClient),
1988 #endif /* TRANS_CLIENT */
1989 #ifdef TRANS_SERVER
1990         TRANS(AMOpenCLTSServer),
1991 #endif /* TRANS_SERVER */
1992         TRANS(AMSetOption),
1993 #ifdef TRANS_SERVER
1994         TRANS(AMCreateListener),
1995         TRANS(AMResetListener),
1996         TRANS(AMAccept),
1997 #endif /* TRANS_SERVER */
1998 #ifdef TRANS_CLIENT
1999         TRANS(AMConnect),
2000 #endif /* TRANS_CLIENT */
2001         TRANS(AMBytesReadable),
2002         TRANS(AMRead),
2003         TRANS(AMWrite),
2004         TRANS(AMReadv),
2005         TRANS(AMWritev),
2006         TRANS(AMDisconnect),
2007         TRANS(AMClose),
2008 };