|
|
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: /* $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> ! 76: static 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: ! 95: extern char *isodetcpath; ! 96: ! 97: #ifdef ISODEBUG ! 98: /* ! 99: * Set to true for loads of TSAP messages... ! 100: */ ! 101: int 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: */ ! 108: int 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: ! 115: extern int accept(), TAcceptFromClient(); ! 116: int (*acceptfn[])() = ! 117: { ! 118: accept, TAcceptFromClient ! 119: }; ! 120: extern getpeername(), getISOpeername(); ! 121: int (*getpeerfn[])() = ! 122: { ! 123: getpeername, getISOpeername ! 124: }; ! 125: /* ! 126: * Note yuckiness here XXX ! 127: * TReadFromClient takes one more param than read - must fix... ! 128: */ ! 129: extern int read(), TReadFromClient(); ! 130: int (*readfn[])() = ! 131: { ! 132: read, TReadFromClient ! 133: }; ! 134: extern int write(), TWriteToClient(); ! 135: int (*writefn[])() = ! 136: { ! 137: write, TWriteToClient ! 138: }; ! 139: extern writev(), TWritevToClient(); ! 140: int (*writevfn[])() = ! 141: { ! 142: writev, TWritevToClient ! 143: }; ! 144: extern int close(), TDiscFromClient(); ! 145: int (*closefn[])() = ! 146: { ! 147: close, TDiscFromClient ! 148: }; ! 149: ! 150: #endif /* ISOCONN */ ! 151: ! 152: typedef 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 ! 160: char *display = NULLCP; /* The display number */ ! 161: #else /* ISOCONN */ ! 162: char *display; /* The display number */ ! 163: #endif /* ISOCONN */ ! 164: int lastfdesc; /* maximum file descriptor */ ! 165: ! 166: long WellKnownConnections; /* Listener mask */ ! 167: long EnabledDevices; /* mask for input devices that are on */ ! 168: long AllSockets[mskcnt]; /* select on this */ ! 169: long AllClients[mskcnt]; /* available clients */ ! 170: long LastSelectMask[mskcnt]; /* mask returned from last select call */ ! 171: long ClientsWithInput[mskcnt]; /* clients with FULL requests in buffer */ ! 172: long ClientsWriteBlocked[mskcnt];/* clients who cannot receive output */ ! 173: long OutputPending[mskcnt]; /* clients with reply/event data ready to go */ ! 174: long MaxClients = MAXSOCKS ; ! 175: long OutputBufferSize = BUFSIZ; /* output buffer size (must be > 0) */ ! 176: long NConnBitArrays = mskcnt; ! 177: long FirstClient; ! 178: Bool NewOutputPending; /* not yet attempted to write some new output */ ! 179: Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ ! 180: ! 181: static Bool debug_conns = FALSE; ! 182: ! 183: static char whichByteIsFirst; ! 184: ! 185: static int SavedAllClients[mskcnt]; ! 186: static int SavedAllSockets[mskcnt]; ! 187: static int SavedClientsWithInput[mskcnt]; ! 188: static Bool GrabDone = FALSE; ! 189: ! 190: ClientPtr ConnectionTranslation[MAXSOCKS]; ! 191: extern ClientPtr NextAvailableClient(); ! 192: ! 193: extern ConnectionInput inputBuffers[]; ! 194: ! 195: int swappedClients[MAXSOCKS]; ! 196: ! 197: extern int AutoResetServer(); ! 198: extern int GiveUp(); ! 199: ! 200: #ifdef UNIXCONN ! 201: ! 202: static struct sockaddr_un unsock; ! 203: ! 204: static 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: ! 239: void ! 240: CreateWellKnownSockets() ! 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: ! 442: void ! 443: ResetWellKnownSockets () ! 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: */ ! 476: TReadFromClient(client, data, size, nonblock) ! 477: int client, size, nonblock; ! 478: char *data; ! 479: { ! 480: struct TSAPdisconnect tds; ! 481: struct TSAPdisconnect *td = &tds; ! 482: int ret; ! 483: static struct TSAPdata txs; ! 484: static struct TSAPdata *tx = &txs; ! 485: char *aptr; ! 486: static struct qbuf *qb; ! 487: static char *qptr; ! 488: static 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: ! 582: jmp_buf env; ! 583: void TimeOut() ! 584: { ! 585: longjmp(env, 1); ! 586: } ! 587: static Bool ! 588: ReadBuffer(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: */ ! 639: getISOpeername (conn, from, alen) ! 640: int conn; ! 641: struct TSAPaddr *from; ! 642: int *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: ! 672: int ! 673: ClientAuthorized(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: ! 780: static 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: ! 789: void ! 790: #ifdef ISOCONN ! 791: EstablishNewConnections(newclients, nnew, vecp, vec) ! 792: ClientPtr *newclients; ! 793: int *nnew; ! 794: int vecp; ! 795: char **vec; ! 796: #else /* ISOCONN */ ! 797: EstablishNewConnections(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) ! 858: ErrorF("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: ! 1002: void ! 1003: CloseDownFileDescriptor(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: ! 1045: void ! 1046: CheckConnections() ! 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: ¬ime); ! 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: ! 1103: CloseDownConnection(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: ! 1116: AddEnabledDevice(fd) ! 1117: int fd; ! 1118: { ! 1119: EnabledDevices |= (1<<fd); ! 1120: BITSET(AllSockets, fd); ! 1121: } ! 1122: ! 1123: ! 1124: RemoveEnabledDevice(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: ! 1141: OnlyListenToOneClient(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: ! 1176: ListenToAllClients() ! 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.