BSD 4_3_Net_2 release
[unix-history] / usr / src / contrib / isode / others / X / server / connection.c
CommitLineData
de5b4dd4
C
1/***********************************************************
2Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Digital or MIT not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23******************************************************************/
24/* $XConsortium: connection.c,v 1.88 88/10/22 22:06:31 keith Exp $ */
25/*****************************************************************
26 * Stuff to create connections --- OS dependent
27 *
28 * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
29 * CloseDownConnection, CheckConnections, AddEnabledDevice,
30 * RemoveEnabledDevice, OnlyListToOneClient,
31 * ListenToAllClients,
32 *
33 * (WaitForSomething is in its own file)
34 *
35 * In this implementation, a client socket table is not kept.
36 * Instead, what would be the index into the table is just the
37 * file descriptor of the socket. This won't work for if the
38 * socket ids aren't small nums (0 - 2^8)
39 *
40 *****************************************************************/
41
42#ifdef ISOCONN
43#include <math.h>
44#endif /* ISOCONN */
45
46#include <dbm.h>
47#undef NULL
48#include "X.h"
49#include "Xproto.h"
50#include <sys/param.h>
51#include <errno.h>
52#include "Xos.h" /* for strings, file, time */
53#include <sys/socket.h>
54
55#include <signal.h>
56#include <fcntl.h>
57#include <setjmp.h>
58
59#ifdef hpux
60#include <sys/ioctl.h>
61#endif
62
63#ifdef TCPCONN
64#include <netinet/in.h>
65#ifndef hpux
66#include <netinet/tcp.h>
67#endif
68#endif
69
70#ifdef UNIXCONN
71/*
72 * sites should be careful to have separate /tmp directories for diskless nodes
73 */
74#include <sys/un.h>
75#include <sys/stat.h>
76static int unixDomainConnection = -1;
77#endif
78
79#include <stdio.h>
80#include <sys/uio.h>
81#include "osstruct.h"
82#include "osdep.h"
83#include "opaque.h"
84#include "dixstruct.h"
85
86#ifdef DNETCONN
87#include <netdnet/dn.h>
88#endif /* DNETCONN */
89
90#ifdef ISOCONN
91#include <isode/psap.h>
92#include <isode/tsap.h>
93#include <isode/isoservent.h>
94
95extern char *isodetcpath;
96
97#ifdef ISODEBUG
98/*
99 * Set to true for loads of TSAP messages...
100 */
101int isodexbug = FALSE;
102#endif /* ISODEBUG */
103
104/*
105 * array of fd 2 family map so we can lookup right function below...
106 * Its initialised at connection setup...
107 */
108int fd2family[MAXSOCKS];
109/*
110 * Globals for storing functions appropos each fd/socket type
111 * UNIX_IO (0) map to sys calls
112 * ISODE_IO (1) maps to my fns...
113 */
114
115extern int accept(), TAcceptFromClient();
116int (*acceptfn[])() =
117{
118 accept, TAcceptFromClient
119};
120extern getpeername(), getISOpeername();
121int (*getpeerfn[])() =
122{
123 getpeername, getISOpeername
124};
125/*
126 * Note yuckiness here XXX
127 * TReadFromClient takes one more param than read - must fix...
128 */
129extern int read(), TReadFromClient();
130int (*readfn[])() =
131{
132 read, TReadFromClient
133};
134extern int write(), TWriteToClient();
135int (*writefn[])() =
136{
137 write, TWriteToClient
138};
139extern writev(), TWritevToClient();
140int (*writevfn[])() =
141{
142 writev, TWritevToClient
143};
144extern int close(), TDiscFromClient();
145int (*closefn[])() =
146{
147 close, TDiscFromClient
148};
149
150#endif /* ISOCONN */
151
152typedef long CCID; /* mask of indices into client socket table */
153
154#ifndef X_UNIX_PATH
155#define X_UNIX_DIR "/tmp/.X11-unix"
156#define X_UNIX_PATH "/tmp/.X11-unix/X"
157#endif
158
159#ifdef ISOCONN
160char *display = NULLCP; /* The display number */
161#else /* ISOCONN */
162char *display; /* The display number */
163#endif /* ISOCONN */
164int lastfdesc; /* maximum file descriptor */
165
166long WellKnownConnections; /* Listener mask */
167long EnabledDevices; /* mask for input devices that are on */
168long AllSockets[mskcnt]; /* select on this */
169long AllClients[mskcnt]; /* available clients */
170long LastSelectMask[mskcnt]; /* mask returned from last select call */
171long ClientsWithInput[mskcnt]; /* clients with FULL requests in buffer */
172long ClientsWriteBlocked[mskcnt];/* clients who cannot receive output */
173long OutputPending[mskcnt]; /* clients with reply/event data ready to go */
174long MaxClients = MAXSOCKS ;
175long OutputBufferSize = BUFSIZ; /* output buffer size (must be > 0) */
176long NConnBitArrays = mskcnt;
177long FirstClient;
178Bool NewOutputPending; /* not yet attempted to write some new output */
179Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
180
181static Bool debug_conns = FALSE;
182
183static char whichByteIsFirst;
184
185static int SavedAllClients[mskcnt];
186static int SavedAllSockets[mskcnt];
187static int SavedClientsWithInput[mskcnt];
188static Bool GrabDone = FALSE;
189
190ClientPtr ConnectionTranslation[MAXSOCKS];
191extern ClientPtr NextAvailableClient();
192
193extern ConnectionInput inputBuffers[];
194
195int swappedClients[MAXSOCKS];
196
197extern int AutoResetServer();
198extern int GiveUp();
199
200#ifdef UNIXCONN
201
202static struct sockaddr_un unsock;
203
204static int open_unix_socket ()
205{
206 int oldUmask;
207 int request;
208
209 unsock.sun_family = AF_UNIX;
210 oldUmask = umask (0);
211#ifdef X_UNIX_DIR
212 mkdir (X_UNIX_DIR, 0777);
213#endif
214 strcpy (unsock.sun_path, X_UNIX_PATH);
215 strcat (unsock.sun_path, display);
216 unlink (unsock.sun_path);
217 if ((request = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
218 {
219 Notice ("Creating Unix socket");
220 }
221 else
222 {
223 if(bind(request,(struct sockaddr *)&unsock, strlen(unsock.sun_path)+2))
224 Error ("Binding Unix socket");
225 if (listen (request, 5)) Error ("Unix Listening");
226 }
227 (void)umask(oldUmask);
228 return request;
229}
230#endif /*UNIXCONN */
231
232/*****************
233 * CreateWellKnownSockets
234 * At initialization, create the sockets to listen on for new clients.
235 * There are potentially 4: DECnet, UNIX Domain, TCP-IP with MSB first,
236 * with TCP-IP with LSB first.
237 *****************/
238
239void
240CreateWellKnownSockets()
241{
242 int request, i;
243 int whichbyte; /* used to figure out whether this is
244 LSB or MSB */
245#ifdef TCPCONN
246 struct sockaddr_in insock;
247 int tcpportReg; /* port with same byte order as server */
248
249#ifdef SO_LINGER
250 static int linger[2] = { 0, 0 };
251#endif /* SO_LINGER */
252
253#endif /* TCPCONN */
254
255#ifdef DNETCONN
256 struct sockaddr_dn dnsock;
257#endif /* DNETCONN */
258
259#ifdef ISOCONN
260 struct TSAPdisconnect tds;
261 struct TSAPdisconnect *td = &tds;
262 struct TSAPaddr tas;
263 struct TSAPaddr *ta = &tas;
264 struct PSAPaddr *pa;
265 AEI aei;
266#endif /* ISOCONN */
267 int retry;
268
269#ifdef ISOCONN
270#ifdef ISODEBUG
271 isodetcpath = ISODEPATH;
272#endif
273#endif /* ISOCONN */
274
275 CLEARBITS(AllSockets);
276 CLEARBITS(AllClients);
277 CLEARBITS(LastSelectMask);
278 CLEARBITS(ClientsWithInput);
279
280 for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = (ClientPtr)NULL;
281
282#ifdef hpux
283 lastfdesc = _NFILE - 1;
284#else
285 lastfdesc = getdtablesize() - 1;
286#endif /* hpux */
287
288 if (lastfdesc > MAXSOCKS)
289 {
290 lastfdesc = MAXSOCKS;
291 if (debug_conns)
292 ErrorF( "GOT TO END OF SOCKETS %d\n", MAXSOCKS);
293 }
294
295 WellKnownConnections = 0;
296 whichbyte = 1;
297
298 if (*(char *) &whichbyte)
299 whichByteIsFirst = 'l';
300 else
301 whichByteIsFirst = 'B';
302
303
304#ifdef TCPCONN
305
306 tcpportReg = atoi (display);
307 tcpportReg += X_TCP_PORT;
308
309 if ((request = socket (AF_INET, SOCK_STREAM, 0)) < 0)
310 {
311 Notice ("Creating TCP socket");
312 }
313 else
314 {
315 bzero ((char *)&insock, sizeof (insock));
316 insock.sin_family = AF_INET;
317 insock.sin_port = htons (tcpportReg);
318 insock.sin_addr.s_addr = htonl(INADDR_ANY);
319 retry = 20;
320 while (i = bind(request, (struct sockaddr *) &insock, sizeof (insock)))
321 {
322#ifdef hpux
323 /* Necesary to restart the server without a reboot */
324 if (errno == EADDRINUSE)
325 set_socket_option (request, SO_REUSEADDR);
326 if (--retry == 0)
327 Error ("Binding TCP socket");
328 sleep (1);
329#else
330 if (--retry == 0)
331 Error ("Binding MSB TCP socket");
332 sleep (10);
333#endif /* hpux */
334 }
335#ifdef hpux
336 /* return the socket option to the original */
337 if (errno)
338 unset_socket_option (request, SO_REUSEADDR);
339#endif /* hpux */
340#ifdef SO_LINGER
341 if(setsockopt (request, SOL_SOCKET, SO_LINGER,
342 (char *)linger, sizeof(linger)))
343 Notice ("Setting TCP SO_LINGER\n");
344#endif /* SO_LINGER */
345 if (listen (request, 5))
346 Error ("Reg TCP Listening");
347 WellKnownConnections |= (1 << request);
348 DefineSelf (request);
349#ifdef ISOCONN
350 fd2family[request] = UNIX_IO;
351#endif /* ISOCONN */
352 }
353
354#endif /* TCPCONN */
355
356#ifdef UNIXCONN
357 if ((request = open_unix_socket ()) != -1) {
358 WellKnownConnections |= (1L << request);
359 unixDomainConnection = request;
360#ifdef ISOCONN
361 fd2family[request] = UNIX_IO;
362#endif /* ISOCONN */
363 }
364#endif /*UNIXCONN */
365
366#ifdef DNETCONN
367 if ((request = socket (AF_DECnet, SOCK_STREAM, 0)) < 0)
368 {
369 Notice ("Creating DECnet socket");
370 }
371 else
372 {
373 bzero ((char *)&dnsock, sizeof (dnsock));
374 dnsock.sdn_family = AF_DECnet;
375 sprintf(dnsock.sdn_objname, "X$X%d", atoi (display));
376 dnsock.sdn_objnamel = strlen(dnsock.sdn_objname);
377 if (bind (request, (struct sockaddr *) &dnsock, sizeof (dnsock)))
378 Error ("Binding DECnet socket");
379 if (listen (request, 5)) Error ("DECnet Listening");
380 WellKnownConnections |= (1 << request);
381 DefineSelf (request);
382#ifdef ISOCONN
383 fd2family[request] = UNIX_IO;
384#endif /* ISOCONN */
385 }
386#endif /* DNETCONN */
387#ifdef ISOCONN
388/*
389 * If display is set, its the string after the Colon:
390 * i.e. X0 or X1 or T0 or T1...
391 */
392 if ((display == NULLCP) || (atoi(display) == 0))
393 aei = str2aei(TLocalHostName(), DEFAULTTSERVICE);
394 else
395 aei = str2aei(TLocalHostName(), display);
396
397 if (aei == NULLAEI) {
398 ErrorF("No AEI for me:");
399 FatalError(TLocalHostName());
400 }
401
402/*
403 * This hack only works if the PSAPaddr and SSAP addrsd are null!!
404 */
405 if ((pa = aei2addr (aei)) == NULLPA)
406 FatalError("address translation failed");
407
408 ta = (struct TSAPaddr *)&(pa->pa_addr.sa_addr);
409
410/*
411 * Just put out a listen for now
412 */
413 if ((request = TNetListen(ta, td)) != OK) {
414 Error(TErrString(td->td_reason));
415 FatalError("TNetListen");
416 }
417
418 WellKnownConnections |= (1 << request);
419 DefineSelf (request);
420 fd2family[request] = ISODE_IO;
421#endif /* ISOCONN */
422 if (WellKnownConnections == 0)
423 Error ("No Listeners, nothing to do");
424 signal (SIGPIPE, SIG_IGN);
425 signal (SIGHUP, AutoResetServer);
426 signal (SIGINT, GiveUp);
427 signal (SIGTERM, GiveUp);
428 FirstClient = request + 1;
429 AllSockets[0] = WellKnownConnections;
430 ResetHosts(display);
431
432 for (i=0; i<MaxClients; i++)
433 {
434 inputBuffers[i].buffer = (char *) NULL;
435 inputBuffers[i].bufptr = (char *) NULL;
436 inputBuffers[i].bufcnt = 0;
437 inputBuffers[i].lenLastReq = 0;
438 inputBuffers[i].size = 0;
439 }
440}
441
442void
443ResetWellKnownSockets ()
444{
445#ifdef UNIXCONN
446 if (unixDomainConnection != -1)
447 {
448 /*
449 * see if the unix domain socket has disappeared
450 */
451 struct stat statb;
452
453 if (stat (unsock.sun_path, &statb) == -1 ||
454 (statb.st_mode & S_IFMT) != S_IFSOCK)
455 {
456 ErrorF ("Unix domain socket %s trashed, recreating\n",
457 unsock.sun_path);
458 (void) unlink (unsock.sun_path);
459 (void) close (unixDomainConnection);
460 WellKnownConnections &= ~(1L << unixDomainConnection);
461 unixDomainConnection = open_unix_socket ();
462 if (unixDomainConnection != -1)
463 WellKnownConnections |= (1L << unixDomainConnection);
464 }
465 }
466#endif /* UNIXCONN */
467}
468
469#ifdef ISOCONN
470/*
471 * Convenience routine...
472 * client = transport descriptor
473 * data, size = buffer
474 * nonblock = NOTOK, blocks, OK, non blocks
475 */
476TReadFromClient(client, data, size, nonblock)
477int client, size, nonblock;
478char *data;
479{
480 struct TSAPdisconnect tds;
481 struct TSAPdisconnect *td = &tds;
482 int ret;
483static struct TSAPdata txs;
484static struct TSAPdata *tx = &txs;
485 char *aptr;
486static struct qbuf *qb;
487static char *qptr;
488static int ingot, qcpy, result = 0;
489 int q2data;
490
491#ifdef ISODEBUG
492 if (isodexbug) {
493 fprintf(stderr, "TReadFromClient %d want %d (%d buffered)\n",
494 client, size, result);
495 }
496#endif /* ISODEBUG */
497 if (result == 0) {
498 if ((ret = TReadRequest(client, tx, nonblock, td)) == NOTOK) {
499#ifdef ISODEBUG
500 if(errno == EWOULDBLOCK ) {
501 fprintf(stderr, "Server TReadReq: would block %s\n",
502 TErrString(td->td_reason));
503 if (!DR_FATAL(td->td_reason))
504 errno = EWOULDBLOCK;
505 else
506 errno = EBADF;
507 return ret;
508 }
509 if (isodexbug)
510 fprintf(stderr, "Server TReadReq: %s\n",
511 TErrString(td->td_reason));
512#endif /* ISODEBUG */
513/*
514 * map problems here - eg TimeOut...
515 */
516 if (td->td_reason == DR_TIMER)
517 errno = EWOULDBLOCK;
518 return ret;
519 }
520 result = tx->tx_cc;
521 qb = &(tx->tx_qbuf);
522 qptr = qb->qb_data;
523#ifdef ISODEBUG
524 if (isodexbug)
525 fprintf(stderr, "TReadRequest want %d got %d\n",
526 size, result);
527#endif
528 }
529#ifdef ISODEBUG
530 else {
531 if (isodexbug)
532 fprintf(stderr, "TReadFromClient want %d buffered %d\n",
533 size, result);
534 }
535#endif
536/*
537 * Buffer it
538 */
539 ingot = 0;
540 aptr = data;
541 for(ingot = 0, aptr = data, q2data = min(size, result);
542 ingot<q2data;
543 aptr += qcpy, ingot+= qcpy) {
544 int aleft = q2data - ingot;
545 if (qb->qb_len > aleft) {
546 qcpy = aleft;
547 bcopy(qptr, aptr, qcpy);
548 qptr += aleft;
549 } else {
550 qcpy = qb->qb_len;
551 bcopy(qb->qb_data, aptr, qcpy);
552 if ((qb = qb->qb_forw) == NULL)
553 break;
554 qptr = qb->qb_data;
555 }
556 }
557 if ((result -= ingot) <= 0) {
558 result = 0;
559 TXFREE(tx);
560 }
561 return ingot;
562}
563
564#endif /* ISOCONN */
565
566/* We want to read the connection information. If the client doesn't
567 * send us enough data, however, we want to time out eventually.
568 * The scheme is to clear a flag, set an alarm, and keep doing non-blocking
569 * reads until we get all the data we want. If the alarm goes
570 * off, the handler will clear the flag. If we see that the flag is
571 * cleared, we know we've timed out and return with an error.
572 *
573 * there remains one problem with this code:
574 * there is a window of vulnerability in which we might get an alarm
575 * even though all the data has come in properly. This is because I
576 * can't atomically clear the alarm.
577 *
578 * Anyone who sees how to fix this problem should do so and
579 * submit a fix.
580 */
581
582jmp_buf env;
583void TimeOut()
584{
585 longjmp(env, 1);
586}
587static Bool
588ReadBuffer(conn, buffer, charsWanted)
589 long conn;
590 char *buffer;
591 int charsWanted;
592{
593 char *bptr = buffer;
594 int got, fTimeOut;
595 struct itimerval itv;
596
597 signal(SIGALRM, TimeOut);
598 fTimeOut = FALSE;
599 /* only 1 alarm, please, not 1 per minute */
600 timerclear(&itv.it_interval);
601 itv.it_value.tv_sec = TimeOutValue;
602 itv.it_value.tv_usec = 0;
603 setitimer(ITIMER_REAL, &itv, (struct itimerval *)NULL);
604 /* It better not take a full minute to get to the read call */
605
606 while (charsWanted && (fTimeOut = setjmp(env)) == FALSE)
607 {
608#ifdef ISOCONN
609 got = SRead(conn, bptr, charsWanted, NOTOK);
610#else /* ISOCONN */
611 got = read(conn, bptr, charsWanted);
612#endif /* ISOCONN */
613 if (got <= 0)
614 return FALSE;
615 if(got > 0)
616 {
617 charsWanted -= got;
618 bptr += got;
619 /* Ok, we got something, reset the timer */
620 itv.it_value.tv_sec = TimeOutValue;
621 itv.it_value.tv_usec = 0;
622 setitimer(ITIMER_REAL, &itv, (struct itimerval *)NULL);
623 }
624 }
625 /* disable the timer */
626 timerclear(&itv.it_value);
627 setitimer(ITIMER_REAL, &itv, (struct itimerval *)NULL);
628 /* If we got here and we didn't time out, then return TRUE, because
629 * we must have read what we wanted. If we timed out, return FALSE */
630 if(fTimeOut && debug_conns)
631 ErrorF("Timed out on connection %d\n", conn);
632 return (!fTimeOut);
633}
634
635#ifdef ISOCONN
636/*
637 * Who's calling us?
638 */
639getISOpeername (conn, from, alen)
640int conn;
641struct TSAPaddr *from;
642int *alen;
643{
644 struct TSAPdisconnect td;
645 if (TGetAddresses (conn, from, NULLTA, &td) == NOTOK) {
646 Error(TErrString(td.td_reason));
647 return TRUE;
648 };
649 *alen = sizeof(struct TSAPaddr);
650 return FALSE;
651}
652#endif /* ISOCONN */
653/*****************************************************************
654 * ClientAuthorized
655 *
656 * Sent by the client at connection setup:
657 * typedef struct _xConnClientPrefix {
658 * CARD8 byteOrder;
659 * BYTE pad;
660 * CARD16 majorVersion, minorVersion;
661 * CARD16 nbytesAuthProto;
662 * CARD16 nbytesAuthString;
663 * } xConnClientPrefix;
664 *
665 * It is hoped that eventually one protocol will be agreed upon. In the
666 * mean time, a server that implements a different protocol than the
667 * client expects, or a server that only implements the host-based
668 * mechanism, will simply ignore this information.
669 *
670 *****************************************************************/
671
672int
673ClientAuthorized(conn, pswapped, reason)
674 long conn;
675 int *pswapped;
676 char **reason; /* if authorization fails, put reason in here */
677{
678 short slen;
679 union {
680 struct sockaddr sa;
681#ifdef UNIXCONN
682 struct sockaddr_un un;
683#endif /* UNIXCONN */
684#ifdef TCPCONN
685 struct sockaddr_in in;
686#endif /* TCPCONN */
687#ifdef DNETCONN
688 struct sockaddr_dn dn;
689#endif /* DNETCONN */
690#ifdef ISOCONN
691 struct TSAPaddr ts;
692#endif /* ISOCONN */
693 } from;
694 int fromlen;
695 xConnClientPrefix xccp;
696 char auth_proto[100];
697 char auth_string[100];
698
699#ifdef ISOCONN
700/*
701 * For now we always auth an ISO client!!
702 * should use directory etc etc
703 */
704 *reason = 0;
705#endif /* ISOCONN */
706 if (!ReadBuffer(conn, (char *)&xccp, sizeof(xConnClientPrefix)))
707 {
708 /* If they can't even give us this much, just blow them off
709 * without an error message */
710 *reason = 0;
711 return 0;
712 }
713 if (xccp.byteOrder != whichByteIsFirst)
714 {
715 SwapConnClientPrefix(&xccp);
716 *pswapped = TRUE;
717 }
718 else
719 *pswapped = FALSE;
720 if ((xccp.majorVersion != X_PROTOCOL) ||
721 (xccp.minorVersion != X_PROTOCOL_REVISION))
722 {
723#define STR "Protocol version mismatch"
724 *reason = (char *)xalloc(sizeof(STR));
725 strcpy(*reason, STR);
726 if (debug_conns)
727 ErrorF("%s\n", STR);
728#undef STR
729 return 0;
730 }
731 fromlen = sizeof (from);
732#ifdef ISOCONN
733 if (SGetPeerName (conn, &(from.ts), &fromlen) ||
734 InvalidHost (&(from.ts), fromlen))
735#else /* ISOCONN */
736 if (getpeername (conn, &from.sa, &fromlen) ||
737 InvalidHost (&from.sa, fromlen))
738#endif /* ISOCONN */
739 {
740#define STR "Server is not authorized to connect to host"
741 *reason = (char *)xalloc(sizeof(STR));
742 strcpy(*reason, STR);
743#undef STR
744 return 0;
745 }
746
747 slen = (xccp.nbytesAuthProto + 3) & ~3;
748 if ( slen )
749 if (!ReadBuffer(conn, auth_proto, slen))
750 {
751#define STR "Length error in xConnClientPrefix for protocol authorization "
752 *reason = (char *)xalloc(sizeof(STR));
753 strcpy(*reason, STR);
754 return 0;
755#undef STR
756 }
757 auth_proto[slen] = '\0';
758
759 slen = (xccp.nbytesAuthString + 3) & ~3;
760 if ( slen)
761 if (!ReadBuffer(conn, auth_string, slen))
762 {
763#define STR "Length error in xConnClientPrefix for protocol string"
764 *reason = (char *)xalloc(sizeof(STR));
765 strcpy(*reason, STR);
766 return 0;
767#undef STR
768 }
769 auth_string[slen] = '\0';
770
771 /* At this point, if the client is authorized to change the access control
772 * list, we should getpeername() information, and add the client to
773 * the selfhosts list. It's not really the host machine, but the
774 * true purpose of the selfhosts list is to see who may change the
775 * access control list.
776 */
777 return(1);
778}
779
780static int padlength[4] = {0, 3, 2, 1};
781
782/*****************
783 * EstablishNewConnections
784 * If anyone is waiting on listened sockets, accept them.
785 * Returns a mask with indices of new clients. Updates AllClients
786 * and AllSockets.
787 *****************/
788
789void
790#ifdef ISOCONN
791EstablishNewConnections(newclients, nnew, vecp, vec)
792 ClientPtr *newclients;
793 int *nnew;
794 int vecp;
795 char **vec;
796#else /* ISOCONN */
797EstablishNewConnections(newclients, nnew)
798 ClientPtr *newclients;
799 int *nnew;
800#endif /* ISOCONN */
801{
802 long readyconnections; /* mask of listeners that are ready */
803 long curconn; /* fd of listener that's ready */
804 long newconn; /* fd of new client */
805 int swapped; /* set by ClientAuthorized if connection is
806 * swapped */
807 char *reason;
808 struct iovec iov[2];
809#ifdef ISOCONN
810 struct udvec uv[3];
811 struct TSAPdisconnect tds;
812 struct TSAPdisconnect *td = &tds;
813 struct TSAPstart tsts;
814 struct TSAPstart *tst = &tsts;
815#endif /* ISOCONN */
816 char p[3];
817
818#ifdef TCP_NODELAY
819 union {
820 struct sockaddr sa;
821#ifdef UNIXCONN
822 struct sockaddr_un un;
823#endif /* UNIXCONN */
824#ifdef TCPCONN
825 struct sockaddr_in in;
826#endif /* TCPCONN */
827#ifdef DNETCONN
828 struct sockaddr_dn dn;
829#endif /* DNETCONN */
830 } from;
831 int fromlen;
832#endif TCP_NODELAY
833
834 *nnew = 0;
835 if (readyconnections = (LastSelectMask[0] & WellKnownConnections))
836 {
837 while (readyconnections)
838 {
839 curconn = ffs (readyconnections) - 1;
840#ifdef ISOCONN
841/*
842 * At this point, a TAccept has finished with a vec > 0
843 * so we need to init them...
844 */
845 if ((newconn = SAccept(curconn, vecp, vec)) >= 0)
846 {
847 fd2family[newconn] = ISODE_IO;
848#else /* ISOCONN */
849 if ((newconn = accept (curconn,
850 (struct sockaddr *) NULL,
851 (int *)NULL)) >= 0)
852 {
853 fd2family[newconn] = UNIX_IO;
854#endif /* ISOCONN */
855 if (newconn >= lastfdesc)
856 {
857 if (debug_conns)
858ErrorF("Didn't make connection: Out of file descriptors for connections\n");
859#ifdef ISOCONN
860 SClose(newconn);
861#else /* ISOCONN */
862 close (newconn);
863#endif /* ISOCONN */
864 }
865 else
866 {
867 ClientPtr next = (ClientPtr)NULL;
868
869#ifdef TCP_NODELAY
870#ifdef ISOCONN
871 if (fd2family(newconn) == UNIX_IO)
872 {
873#endif /* ISOCONN */
874 fromlen = sizeof (from);
875 if (!getpeername (newconn, &from.sa, &fromlen))
876 {
877 if (fromlen && (from.sa.sa_family == AF_INET))
878 {
879 int mi = 1;
880 setsockopt (newconn, IPPROTO_TCP, TCP_NODELAY,
881 (char *)&mi, sizeof (int));
882 }
883 }
884#ifdef ISOCONN
885 }
886#endif /* ISOCONN */
887#endif /* TCP_NODELAY */
888 if (ClientAuthorized(newconn, &swapped, &reason))
889 {
890#ifdef hpux
891 /*
892 * HPUX does not have FNDELAY
893 */
894 {
895 int arg;
896 arg = 1;
897 ioctl(newconn, FIOSNBIO, &arg);
898 }
899#else
900 fcntl (newconn, F_SETFL, FNDELAY);
901#endif /* hpux */
902 inputBuffers[newconn].used = 1;
903 if (! inputBuffers[newconn].size)
904 {
905 inputBuffers[newconn].buffer =
906 (char *)xalloc(BUFSIZE);
907 inputBuffers[newconn].size = BUFSIZE;
908 inputBuffers[newconn].bufptr =
909 inputBuffers[newconn].buffer;
910 }
911 if (GrabDone)
912 {
913 BITSET(SavedAllClients, newconn);
914 BITSET(SavedAllSockets, newconn);
915 }
916 else
917 {
918 BITSET(AllClients, newconn);
919 BITSET(AllSockets, newconn);
920 }
921 next = NextAvailableClient();
922 if (next != (ClientPtr)NULL)
923 {
924 OsCommPtr priv;
925
926 newclients[(*nnew)++] = next;
927 next->swapped = swapped;
928 ConnectionTranslation[newconn] = next;
929 priv = (OsCommPtr)xalloc(sizeof(OsCommRec));
930 priv->fd = newconn;
931 priv->buf = (unsigned char *)
932 xalloc(OutputBufferSize);
933 priv->bufsize = OutputBufferSize;
934 priv->count = 0;
935 next->osPrivate = (pointer)priv;
936 }
937 else
938 {
939#define STR "Maximum number of clients exceeded"
940 reason = (char *)xalloc(sizeof(STR));
941 strcpy(reason, STR);
942#undef STR
943 }
944 }
945 if (next == (ClientPtr)NULL)
946 {
947 xConnSetupPrefix c;
948
949 if(reason)
950 {
951 c.success = xFalse;
952 c.lengthReason = strlen(reason);
953 c.length = (c.lengthReason + 3) >> 2;
954 c.majorVersion = X_PROTOCOL;
955 c.minorVersion = X_PROTOCOL_REVISION;
956 if(swapped)
957 {
958 int n;
959
960 swaps(&c.majorVersion, n);
961 swaps(&c.minorVersion, n);
962 swaps(&c.length, n);
963 }
964
965#ifdef ISOCONN
966 (void)SWrite(newconn, (char *)&c, sizeof(xConnSetupPrefix));
967#else /* ISOCONN */
968 write(newconn, (char *)&c, sizeof(xConnSetupPrefix));
969#endif /* ISOCONN */
970 iov[0].iov_len = c.lengthReason;
971 iov[0].iov_base = reason;
972 iov[1].iov_len = padlength[c.lengthReason & 3];
973 iov[1].iov_base = p;
974#ifdef ISOCONN
975 SWritev(newconn, iov, 2);
976#else /* ISOCONN */
977 writev(newconn, iov, 2);
978#endif /* ISOCONN */
979 if (debug_conns)
980 ErrorF("Didn't make connection:%s\n", reason);
981 }
982#ifdef ISOCONN
983 SClose(newconn);
984#else /* ISOCONN */
985 close(newconn);
986#endif /* ISOCONN */
987 xfree(reason);
988 }
989
990 }
991 }
992 readyconnections &= ~(1 << curconn);
993 }
994 }
995}
996
997/************
998 * CloseDownFileDescriptor:
999 * Remove this file descriptor and it's inputbuffers, etc.
1000 ************/
1001
1002void
1003CloseDownFileDescriptor(connection)
1004 int connection;
1005{
1006#ifdef ISOCONN
1007 struct TSAPdisconnect tds;
1008#ifdef ISODEBUG
1009 if (isodexbug)
1010 fprintf(stderr, "server: TDiscReq\n");
1011#endif /* ISODEBUG */
1012 SClose(connection);
1013#else /* ISOCONN */
1014 close(connection);
1015#endif /* ISOCONN */
1016
1017 if (inputBuffers[connection].size)
1018 {
1019 xfree(inputBuffers[connection].buffer);
1020 inputBuffers[connection].buffer = (char *) NULL;
1021 inputBuffers[connection].bufptr = (char *) NULL;
1022 inputBuffers[connection].size = 0;
1023 }
1024 inputBuffers[connection].bufcnt = 0;
1025 inputBuffers[connection].lenLastReq = 0;
1026 inputBuffers[connection].used = 0;
1027
1028 BITCLEAR(AllSockets, connection);
1029 BITCLEAR(AllClients, connection);
1030 BITCLEAR(ClientsWithInput, connection);
1031 BITCLEAR(ClientsWriteBlocked, connection);
1032 if (!ANYSET(ClientsWriteBlocked))
1033 AnyClientsWriteBlocked = FALSE;
1034}
1035
1036/*****************
1037 * CheckConections
1038 * Some connection has died, go find which one and shut it down
1039 * The file descriptor has been closed, but is still in AllClients.
1040 * If would truly be wonderful if select() would put the bogus
1041 * file descriptors in the exception mask, but nooooo. So we have
1042 * to check each and every socket individually.
1043 *****************/
1044
1045void
1046CheckConnections()
1047{
1048 long mask[mskcnt];
1049 long tmask[mskcnt];
1050 register int curclient;
1051 int i;
1052 struct timeval notime;
1053 ClientPtr bad;
1054 int r;
1055#ifdef ISOCONN
1056 struct TSAPdisconnect tds;
1057 struct TSAPdisconnect *td = &tds;
1058 char *vec[4];
1059 int vecp;
1060#endif /* ISOCONN */
1061
1062 notime.tv_sec = 0;
1063 notime.tv_usec = 0;
1064
1065 COPYBITS(AllClients, mask);
1066 for (i=0; i<mskcnt; i++)
1067 {
1068 while (mask[i])
1069 {
1070 curclient = ffs (mask[i]) - 1 + (i << 5);
1071 CLEARBITS(tmask);
1072 BITSET(tmask, curclient);
1073#ifdef ISOCONN
1074 r = TNetAccept (&vecp, vec,
1075 curclient + 1, tmask, (int *)NULL, (int *)NULL,
1076 OK, td);
1077 if (r == NOTOK)
1078 {
1079 Error(TErrString(td->td_reason));
1080 Error("TNetAccept");
1081#else /* ISOCONN */
1082 r = select (curclient + 1, tmask, (int *)NULL, (int *)NULL,
1083 &notime);
1084 if (r < 0)
1085 {
1086#endif /* ISOCONN */
1087 if (bad = ConnectionTranslation[curclient])
1088 CloseDownClient(bad);
1089 else
1090 CloseDownFileDescriptor(curclient);
1091 }
1092 BITCLEAR(mask, curclient);
1093 }
1094 }
1095}
1096
1097
1098/*****************
1099 * CloseDownConnection
1100 * Delete client from AllClients and free resources
1101 *****************/
1102
1103CloseDownConnection(client)
1104 ClientPtr client;
1105{
1106 OsCommPtr oc = (OsCommPtr)client->osPrivate;
1107
1108 ConnectionTranslation[oc->fd] = (ClientPtr)NULL;
1109 CloseDownFileDescriptor(oc->fd);
1110 if (oc->buf != NULL) /* an Xrealloc may have returned NULL */
1111 xfree(oc->buf);
1112 xfree(client->osPrivate);
1113}
1114
1115
1116AddEnabledDevice(fd)
1117 int fd;
1118{
1119 EnabledDevices |= (1<<fd);
1120 BITSET(AllSockets, fd);
1121}
1122
1123
1124RemoveEnabledDevice(fd)
1125 int fd;
1126{
1127 EnabledDevices &= ~(1<<fd);
1128 BITCLEAR(AllSockets, fd);
1129}
1130
1131/*****************
1132 * OnlyListenToOneClient:
1133 * Only accept requests from one client. Continue to handle new
1134 * connections, but don't take any protocol requests from the new
1135 * ones. Note that if GrabDone is set, EstablishNewConnections
1136 * needs to put new clients into SavedAllSockets and SavedAllClients.
1137 * Note also that there is no timeout for this in the protocol.
1138 * This routine is "undone" by ListenToAllClients()
1139 *****************/
1140
1141OnlyListenToOneClient(client)
1142 ClientPtr client;
1143{
1144 OsCommPtr oc = (OsCommPtr)client->osPrivate;
1145 int connection = oc->fd;
1146
1147 if (! GrabDone)
1148 {
1149 COPYBITS (ClientsWithInput, SavedClientsWithInput);
1150 BITCLEAR (SavedClientsWithInput, connection);
1151 if (GETBIT(ClientsWithInput, connection))
1152 {
1153 CLEARBITS(ClientsWithInput);
1154 BITSET(ClientsWithInput, connection);
1155 }
1156 else
1157 {
1158 CLEARBITS(ClientsWithInput);
1159 }
1160 COPYBITS(AllSockets, SavedAllSockets);
1161 COPYBITS(AllClients, SavedAllClients);
1162
1163 UNSETBITS(AllSockets, AllClients);
1164 BITSET(AllSockets, connection);
1165 CLEARBITS(AllClients);
1166 BITSET(AllClients, connection);
1167 GrabDone = TRUE;
1168 }
1169}
1170
1171/****************
1172 * ListenToAllClients:
1173 * Undoes OnlyListentToOneClient()
1174 ****************/
1175
1176ListenToAllClients()
1177{
1178 if (GrabDone)
1179 {
1180 ORBITS(AllSockets, AllSockets, SavedAllSockets);
1181 ORBITS(AllClients, AllClients, SavedAllClients);
1182 ORBITS(ClientsWithInput, ClientsWithInput, SavedClientsWithInput);
1183 GrabDone = FALSE;
1184 }
1185}
1186
1187