|
|
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.