|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: connection.c,v 1.62 87/09/07 17:12:18 rws Exp $ */
25: /*****************************************************************
26: * Stuff to create connections --- OS dependent
27: *
28: * EstablishNewConnections, CreateWellKnownSockets,
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: #undef NULL
43: #include "X.h"
44: #include "Xproto.h"
45: #include <sys/param.h>
46: #include <errno.h>
47: #include <sys/types.h>
48: #include <sys/filio.h>
49: #include <signal.h>
50: #include <setjmp.h>
51: #include <ipc.h>
52: #include <stdio.h>
53: #include <strings.h>
54: #include "osstruct.h"
55: #include "osdep.h"
56: #include "opaque.h"
57:
58: #include "dixstruct.h"
59:
60: char *display; /* The display number */
61: int lastfdesc; /* maximum file descriptor */
62:
63: long WellKnownConnections; /* Listener mask */
64: long EnabledDevices; /* mask for input devices that are on */
65: long AllSockets[mskcnt]; /* select on this */
66: long AllClients[mskcnt]; /* available clients */
67: long LastSelectMask[mskcnt]; /* mask returned from last select call */
68: long ClientsWithInput[mskcnt];
69: long MaxClients = MAXSOCKS ;
70: long NConnBitArrays = mskcnt;
71: long FirstClient;
72:
73: static Bool debug_conns = FALSE;
74:
75: static char whichByteIsFirst;
76:
77: static int SavedAllClients[mskcnt];
78: static int SavedAllSockets[mskcnt];
79: static int SavedClientsWithInput[mskcnt];
80: static Bool GrabDone = FALSE;
81:
82: ClientPtr ConnectionTranslation[MAXSOCKS];
83: extern ClientPtr NextAvailableClient();
84:
85: extern ConnectionInput inputBuffers[];
86:
87: int swappedClients[MAXSOCKS];
88:
89: extern int AutoResetServer();
90: extern int GiveUp();
91:
92: /*****************
93: * CreateWellKnownSockets
94: * At initialization, create the sockets to listen on for new clients.
95: * There are potentially 4: DECnet, UNIX Domain, TCP-IP with MSB first,
96: * with TCP-IP with LSB first.
97: *****************/
98:
99: void
100: CreateWellKnownSockets()
101: {
102: char fname[32];
103: char port[32];
104: int request, i;
105: int whichbyte; /* used to figure out whether this is
106: LSB or MSB */
107: int retry;
108:
109: CLEARBITS(AllSockets);
110: CLEARBITS(AllClients);
111: CLEARBITS(LastSelectMask);
112: CLEARBITS(ClientsWithInput);
113:
114: for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = (ClientPtr)NULL;
115:
116: lastfdesc = MAXSOCKS - 1;
117:
118: /* hack test to decide where to log errors */
119:
120: if (write (2, fname, 0))
121: {
122: long t;
123:
124: char *ctime();
125: close(stdin);
126: close(stdout);
127: strcpy (fname, "/usr/adm/X");
128: strcat (fname, display);
129: strcat (fname, "msgs");
130: freopen (fname, "a+", stderr);
131: time (&t);
132: fprintf (stderr, "start %s", ctime(&t));
133: }
134: if (getpgrp (0) == 0)
135: setpgrp (0, getpid ());
136:
137: WellKnownConnections = 0;
138: whichbyte = 1;
139:
140: if (*(char *) &whichbyte)
141: whichByteIsFirst = 'l';
142: else
143: whichByteIsFirst = 'B';
144:
145:
146: retry = 10;
147: sprintf(port, "/cs/tcp.%d", atoi (display) + X_TCP_PORT);
148: while ((request = ipccreat(port, "heavy")) < 0)
149: {
150: if (--retry == 0)
151: Notice ("Binding TCP socket");
152: sleep (10);
153: }
154: WellKnownConnections |= (1 << request);
155: DefineSelf (request);
156:
157: if (WellKnownConnections == 0)
158: Error ("No Listeners, nothing to do");
159: signal (SIGPIPE, SIG_IGN);
160: signal (SIGHUP, AutoResetServer);
161: signal (SIGINT, GiveUp);
162: signal (SIGTERM, GiveUp);
163: FirstClient = request + 1;
164: AllSockets[0] = WellKnownConnections;
165: ResetHosts(display);
166:
167: for (i=0; i<MaxClients; i++)
168: {
169: inputBuffers[i].buffer = (char *) NULL;
170: inputBuffers[i].bufptr = (char *) NULL;
171: inputBuffers[i].bufcnt = 0;
172: inputBuffers[i].lenLastReq = 0;
173: inputBuffers[i].size = 0;
174: }
175: }
176:
177: /* We want to read the connection information. If the client doesn't
178: * send us enough data, however, we want to time out eventually.
179: * The scheme is to clear a flag, set an alarm, and keep doing non-blocking
180: * reads until we get all the data we want. If the alarm goes
181: * off, the handler will clear the flag. If we see that the flag is
182: * cleared, we know we've timed out and return with an error.
183: *
184: * there remains one problem with this code:
185: * there is a window of vulnerability in which we might get an alarm
186: * even though all the data has come in properly. This is because I
187: * can't atomically clear the alarm.
188: *
189: * Anyone who sees how to fix this problem should do so and
190: * submit a fix.
191: */
192:
193: jmp_buf env;
194: void TimeOut()
195: {
196: longjmp(env, 1);
197: }
198: static Bool
199: ReadBuffer(conn, buffer, charsWanted)
200: long conn;
201: char *buffer;
202: int charsWanted;
203: {
204: char *bptr = buffer;
205: int got, fTimeOut;
206:
207: signal(SIGALRM, TimeOut);
208: fTimeOut = FALSE;
209: /* only 1 alarm, please, not 1 per minute */
210: alarm(TimeOutValue);
211: /* It better not take a full minute to get to the read call */
212:
213: while (charsWanted && (fTimeOut = setjmp(env)) == FALSE)
214: {
215: got = read(conn, bptr, charsWanted);
216: if (got <= 0)
217: return FALSE;
218: if(got > 0)
219: {
220: charsWanted -= got;
221: bptr += got;
222: /* Ok, we got something, reset the timer */
223: alarm(TimeOutValue);
224: }
225: }
226: /* disable the timer */
227: alarm(0);
228: /* If we got here and we didn't time out, then return TRUE, because
229: * we must have read what we wanted. If we timed out, return FALSE */
230: if(fTimeOut && debug_conns)
231: ErrorF("Timed out on connection %d\n", conn);
232: return (!fTimeOut);
233: }
234:
235: /*****************************************************************
236: * ClientAuthorized
237: *
238: * Sent by the client at connection setup:
239: * typedef struct _xConnClientPrefix {
240: * CARD8 byteOrder;
241: * BYTE pad;
242: * CARD16 majorVersion, minorVersion;
243: * CARD16 nbytesAuthProto;
244: * CARD16 nbytesAuthString;
245: * } xConnClientPrefix;
246: *
247: * It is hoped that eventually one protocol will be agreed upon. In the
248: * mean time, a server that implements a different protocol than the
249: * client expects, or a server that only implements the host-based
250: * mechanism, will simply ignore this information.
251: *
252: *****************************************************************/
253:
254: int
255: ClientAuthorized(conn, pswapped, reason)
256: long conn;
257: int *pswapped;
258: char **reason; /* if authorization fails, put reason in here */
259: {
260: short slen;
261: xConnClientPrefix xccp;
262: char auth_proto[100];
263: char auth_string[100];
264:
265: if (!ReadBuffer(conn, &xccp, sizeof(xConnClientPrefix)))
266: {
267: /* If they can't even give us this much, just blow them off
268: * without an error message */
269: *reason = 0;
270: return 0;
271: }
272: if (xccp.byteOrder != whichByteIsFirst)
273: {
274: SwapConnClientPrefix(&xccp);
275: *pswapped = TRUE;
276: }
277: else
278: *pswapped = FALSE;
279: if ((xccp.majorVersion != X_PROTOCOL) ||
280: (xccp.minorVersion != X_PROTOCOL_REVISION))
281: {
282: #define STR "Protocol version mismatch"
283: *reason = (char *)Xalloc(strlen(STR) + 1);
284: strcpy(*reason, STR);
285: if (debug_conns)
286: ErrorF("%s\n", STR);
287: #undef STR
288: return 0;
289: }
290:
291: slen = (xccp.nbytesAuthProto + 3) & ~3;
292: if ( slen )
293: if (!ReadBuffer(conn, auth_proto, slen))
294: {
295: #define STR "Length error in xConnClientPrefix for protocol authorization "
296: *reason = (char *)Xalloc(strlen(STR));
297: strcpy(*reason, STR);
298: return 0;
299: #undef STR
300: }
301: auth_proto[slen] = '\0';
302:
303: slen = (xccp.nbytesAuthString + 3) & ~3;
304: if ( slen)
305: if (!ReadBuffer(conn, auth_string, slen))
306: {
307: #define STR "Length error in xConnClientPrefix for protocol string"
308: *reason = (char *)Xalloc(strlen(STR));
309: strcpy(*reason, STR);
310: return 0;
311: #undef STR
312: }
313: auth_string[slen] = '\0';
314:
315: /* At this point, if the client is authorized to change the access control
316: * list, we should getpeername() information, and add the client to
317: * the selfhosts list. It's not really the host machine, but the
318: * true purpose of the selfhosts list is to see who may change the
319: * access control list.
320: */
321: return(1);
322: }
323:
324: static int padlength[4] = {0, 3, 2, 1};
325:
326: /*****************
327: * EstablishNewConnections
328: * If anyone is waiting on listened sockets, accept them.
329: * Returns a mask with indices of new clients. Updates AllClients
330: * and AllSockets.
331: *****************/
332:
333: void
334: EstablishNewConnections(newclients, nnew)
335: ClientPtr *newclients;
336: int *nnew;
337: {
338: long readyconnections; /* mask of listeners that are ready */
339: long curconn; /* fd of listener that's ready */
340: long newconn; /* fd of new client */
341: int swapped; /* set by ClientAuthorized if connection is
342: * swapped */
343: char *reason;
344: ipcinfo *ip;
345:
346: *nnew = 0;
347: if (readyconnections = (LastSelectMask[0] & WellKnownConnections))
348: {
349: while (readyconnections)
350: {
351: curconn = ffs (readyconnections) - 1;
352: if ((ip = ipclisten(curconn)) && (newconn = ipcaccept(ip)) >= 0)
353: {
354: if (newconn >= lastfdesc)
355: {
356: if (debug_conns)
357: ErrorF("Didn't make connection: Out of file descriptors for connections\n");
358: close (newconn);
359: }
360: else
361: {
362: if (ClientAuthorized(newconn, &swapped, &reason))
363: {
364: ClientPtr next;
365:
366: (void) ioctl(newconn, FIOWNBLK, 0);
367: inputBuffers[newconn].used = 1;
368: if (! inputBuffers[newconn].size)
369: {
370: inputBuffers[newconn].buffer =
371: (char *)Xalloc(BUFSIZE);
372: inputBuffers[newconn].size = BUFSIZE;
373: inputBuffers[newconn].bufptr =
374: inputBuffers[newconn].buffer;
375: }
376: if (GrabDone)
377: {
378: BITSET(SavedAllClients, newconn);
379: BITSET(SavedAllSockets, newconn);
380: }
381: else
382: {
383: BITSET(AllClients, newconn);
384: BITSET(AllSockets, newconn);
385: }
386: next = NextAvailableClient();
387: if (next != (ClientPtr)NULL)
388: {
389: osPrivPtr priv;
390:
391: newclients[(*nnew)++] = next;
392: next->swapped = swapped;
393: ConnectionTranslation[newconn] = next;
394: priv = (osPrivPtr)Xalloc(sizeof(osPrivRec));
395: priv->fd = newconn;
396: next->osPrivate = (pointer)priv;
397: }
398: }
399: else
400: {
401: xConnSetupPrefix c;
402:
403: if(reason)
404: {
405: c.success = xFalse;
406: c.lengthReason = strlen(reason);
407: c.length = (c.lengthReason + 3) >> 2;
408: c.majorVersion = X_PROTOCOL;
409: c.minorVersion = X_PROTOCOL_REVISION;
410: if(swapped)
411: {
412: int n;
413:
414: swaps(&c.majorVersion, n);
415: swaps(&c.minorVersion, n);
416: swaps(&c.length, n);
417: }
418:
419: write(newconn, &c, sizeof(xConnSetupPrefix));
420: write(newconn, reason,
421: c.lengthReason+padlength[strlen(reason) & 3]);
422: if (debug_conns)
423: ErrorF("Didn't make connection:%s\n", reason);
424: }
425: close(newconn);
426: Xfree(reason);
427: }
428:
429: }
430: }
431: readyconnections &= ~(1 << curconn);
432: }
433: }
434: }
435:
436: /************
437: * CloseDwonFileDescriptor:
438: * Remove this file descriptor and it's inputbuffers, etc.
439: ************/
440:
441: void
442: CloseDownFileDescriptor(connection)
443: long connection;
444: {
445: close(connection);
446:
447: inputBuffers[connection].bufptr = inputBuffers[connection].buffer;
448: inputBuffers[connection].bufcnt = 0;
449: inputBuffers[connection].lenLastReq = 0;
450: inputBuffers[connection].used = 0;
451:
452: BITCLEAR(AllSockets, connection);
453: BITCLEAR(AllClients, connection);
454: BITCLEAR(ClientsWithInput, connection);
455:
456: }
457:
458: /*****************
459: * CheckConections
460: * Some connection has died, go find which one and shut it down
461: * The file descriptor has been closed, but is still in AllClients.
462: * If would truly be wonderful if select() would put the bogus
463: * file descriptors in the exception mask, but nooooo. So we have
464: * to check each and every socket individually.
465: *****************/
466:
467: void
468: CheckConnections()
469: {
470: long mask[mskcnt];
471: long tmask[mskcnt];
472: register int curclient;
473: int i;
474: ClientPtr bad;
475: int r;
476:
477: COPYBITS(AllClients, mask);
478: for (i=0; i<mskcnt; i++)
479: {
480: while (mask[i])
481: {
482: curclient = ffs (mask[i]) - 1 + (i << 5);
483: CLEARBITS(tmask);
484: BITSET(tmask, curclient);
485: r = select (curclient + 1, tmask, (int *)NULL, 0);
486: if (r < 0)
487: {
488: if (bad = ConnectionTranslation[curclient])
489: CloseDownClient(bad);
490: else
491: CloseDownFileDescriptor(curclient);
492: }
493: BITCLEAR(mask, curclient);
494: }
495: }
496: }
497:
498:
499: /*****************
500: * CloseDownConnection
501: * Delete client from AllClients and free resources
502: *****************/
503:
504: CloseDownConnection(client)
505: ClientPtr client;
506: {
507: int connection = ((osPrivPtr)client->osPrivate)->fd;
508:
509: ConnectionTranslation[connection] = (ClientPtr)NULL;
510: CloseDownFileDescriptor(connection);
511: Xfree(client->osPrivate);
512: }
513:
514:
515: AddEnabledDevice(fd)
516: int fd;
517: {
518: EnabledDevices |= (1<<fd);
519: BITSET(AllSockets, fd);
520: }
521:
522:
523: RemoveEnabledDevice(fd)
524: int fd;
525: {
526: EnabledDevices &= ~(1<<fd);
527: BITCLEAR(AllSockets, fd);
528: }
529:
530: /*****************
531: * OnlyListenToOneClient:
532: * Only accept requests from one client. Continue to handle new
533: * connections, but don't take any protocol requests from the new
534: * ones. Note that if GrabDone is set, EstablishNewConnections
535: * needs to put new clients into SavedAllSockets and SavedAllClients.
536: * Note also that there is no timeout for this in the protocol.
537: * This routine is "undone" by ListenToAllClients()
538: *****************/
539:
540: OnlyListenToOneClient(client)
541: ClientPtr client;
542: {
543: int connection = ((osPrivPtr)client->osPrivate)->fd;
544:
545: if (! GrabDone)
546: {
547: COPYBITS (ClientsWithInput, SavedClientsWithInput);
548: BITCLEAR (SavedClientsWithInput, connection);
549: if (GETBIT(ClientsWithInput, connection))
550: {
551: CLEARBITS(ClientsWithInput);
552: BITSET(ClientsWithInput, connection);
553: }
554: else
555: {
556: CLEARBITS(ClientsWithInput);
557: }
558: COPYBITS(AllSockets, SavedAllSockets);
559: COPYBITS(AllClients, SavedAllClients);
560:
561: UNSETBITS(AllSockets, AllClients);
562: BITSET(AllSockets, connection);
563: CLEARBITS(AllClients);
564: BITSET(AllClients, connection);
565: GrabDone = TRUE;
566: }
567: }
568:
569: /****************
570: * ListenToAllClients:
571: * Undoes OnlyListentToOneClient()
572: ****************/
573:
574: ListenToAllClients()
575: {
576: if (GrabDone)
577: {
578: ORBITS(AllSockets, AllSockets, SavedAllSockets);
579: ORBITS(AllClients, AllClients, SavedAllClients);
580: ORBITS(ClientsWithInput, ClientsWithInput, SavedClientsWithInput);
581: GrabDone = FALSE;
582: }
583: }
584:
585:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.