home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / fonts / server / os / connection.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  13.0 KB  |  555 lines

  1. /* $XConsortium: connection.c,v 1.19 92/05/18 13:51:29 gildea Exp $ */
  2. /*
  3.  * handles connections
  4.  */
  5. /*
  6.  * Copyright 1990, 1991 Network Computing Devices;
  7.  * Portions Copyright 1987 by Digital Equipment Corporation and the
  8.  * Massachusetts Institute of Technology
  9.  *
  10.  * Permission to use, copy, modify, and distribute this protoype software
  11.  * and its documentation to Members and Affiliates of the MIT X Consortium
  12.  * any purpose and without fee is hereby granted, provided
  13.  * that the above copyright notice appear in all copies and that both that
  14.  * copyright notice and this permission notice appear in supporting
  15.  * documentation, and that the names of Network Computing Devices, Digital or
  16.  * MIT not be used in advertising or publicity pertaining to distribution of
  17.  * the software without specific, written prior permission.
  18.  *
  19.  * NETWORK COMPUTING DEVICES, DIGITAL AND MIT DISCLAIM ALL WARRANTIES WITH
  20.  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  21.  * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, DIGITAL OR MIT BE
  22.  * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  23.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  24.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  25.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  26.  */
  27.  
  28. /* sorry, streams support not here yet */
  29. #ifdef STREAMSCONN
  30. #undef STREAMSCONN
  31. #define TCPCONN
  32. #endif
  33.  
  34. #include    <X11/Xos.h>
  35. #include    <stdio.h>
  36. #include    <errno.h>
  37. #include    <sys/param.h>
  38. #include    <sys/socket.h>
  39. #include    <sys/uio.h>
  40. #include    <signal.h>
  41.  
  42. #ifdef TCPCONN
  43. #include    <netinet/in.h>
  44. #include    <netinet/tcp.h>
  45. #endif
  46.  
  47. #include    "FS.h"
  48. #include    "FSproto.h"
  49. #include    "clientstr.h"
  50. #include    "osdep.h"
  51. #include    "globals.h"
  52. #include    "osstruct.h"
  53. #include    "servermd.h"
  54.  
  55. extern int  errno;
  56.  
  57. int         ListenPort = DEFAULT_FS_PORT;   /* port to listen on */
  58. int         lastfdesc;
  59.  
  60. extern int  ListenSock;
  61.  
  62. long        WellKnownConnections;
  63. long        AllSockets[mskcnt];
  64. long        AllClients[mskcnt];
  65. long        LastSelectMask[mskcnt];
  66. long        ClientsWithInput[mskcnt];
  67. long        ClientsWriteBlocked[mskcnt];
  68. long        OutputPending[mskcnt];
  69. extern long MaxClients;
  70. long        OutputBufferSize = BUFSIZE;
  71.  
  72. Bool        NewOutputPending;
  73. Bool        AnyClientsWriteBlocked;
  74.  
  75. int         ConnectionTranslation[MAXSOCKS];
  76.  
  77. extern ClientPtr NextAvailableClient();
  78.  
  79. #ifdef SIGNALRETURNSINT
  80. #define SIGVAL int
  81. #else
  82. #define SIGVAL void
  83. #endif
  84.  
  85. extern SIGVAL AutoResetServer();
  86. extern SIGVAL GiveUp();
  87. extern SIGVAL ServerReconfig();
  88. extern SIGVAL ServerCacheFlush();
  89.  
  90. extern void FreeOsBuffers();
  91.  
  92. static void error_conn_max();
  93. static void close_fd();
  94.  
  95.  
  96. #ifdef    TCPCONN
  97. static int
  98. open_tcp_socket()
  99. {
  100.     struct sockaddr_in insock;
  101.     int         request;
  102.     int         retry;
  103.  
  104. #ifndef SO_DONTLINGER
  105.  
  106. #ifdef SO_LINGER
  107.     static int  linger[2] = {0, 0};
  108.  
  109. #endif                /* SO_LINGER */
  110.  
  111. #endif                /* SO_DONTLINGER */
  112.  
  113.     if ((request = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  114.     Error("Creating TCP socket");
  115.     return -1;
  116.     }
  117.  
  118. #ifdef SO_REUSEADDR
  119.     {
  120.     int         one = 1;
  121.  
  122.     setsockopt(request, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
  123.     }
  124. #endif                /* SO_REUSEADDR */
  125.  
  126.     bzero((char *) &insock, sizeof(insock));
  127.     insock.sin_family = AF_INET;
  128.     insock.sin_port = htons((unsigned short) (ListenPort));
  129.     insock.sin_addr.s_addr = htonl(INADDR_ANY);
  130.     retry = 20;
  131.     while (bind(request, (struct sockaddr *) & insock, sizeof(insock))) {
  132.     if (--retry == 0) {
  133.         Error("Binding TCP socket");
  134.         close(request);
  135.         return -1;
  136.     }
  137.  
  138. #ifdef SO_REUSEADDR
  139.     sleep(1);
  140. #else
  141.     sleep(10);
  142. #endif                /* SO_REUSEADDR */
  143.     }
  144.  
  145. #ifdef SO_DONTLINGER
  146.     if (setsockopt(request, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0))
  147.     Error("Setting TCP SO_DONTLINGER");
  148. #else
  149.  
  150. #ifdef SO_LINGER
  151.     if (setsockopt(request, SOL_SOCKET, SO_LINGER,
  152.            (char *) linger, sizeof(linger)))
  153.     Error("Setting TCP SO_LINGER");
  154. #endif                /* SO_LINGER */
  155.  
  156. #endif                /* SO_DONTLINGER */
  157.  
  158.     if (listen(request, 5)) {
  159.     Error("TCP listening");
  160.     close(request);
  161.     return -1;
  162.     }
  163.     ListenSock = request;
  164.     return request;
  165. }
  166.  
  167. #endif                /* TCPCONN */
  168.  
  169. StopListening()
  170. {
  171.     BITCLEAR(AllSockets, ListenSock);
  172.     close(ListenSock);
  173. }
  174.  
  175. /*
  176.  * creates the sockets for listening to clients
  177.  *
  178.  * only called when server first started
  179.  */
  180. void
  181. CreateSockets(oldsock)
  182.     int         oldsock;
  183. {
  184.     int         request,
  185.                 i;
  186.  
  187.     CLEARBITS(AllSockets);
  188.     CLEARBITS(AllClients);
  189.     CLEARBITS(LastSelectMask);
  190.     CLEARBITS(ClientsWithInput);
  191.  
  192.     for (i = 0; i < MAXSOCKS; i++)
  193.     ConnectionTranslation[i] = 0;
  194.  
  195. #if defined(hpux) || defined(SVR4)
  196.     lastfdesc = _NFILE - 1;
  197. #else
  198.     lastfdesc = getdtablesize() - 1;
  199. #endif                /* hpux */
  200.  
  201.     if (lastfdesc > MAXSOCKS) {
  202.     lastfdesc = MAXSOCKS;
  203.     }
  204.     WellKnownConnections = 0;
  205.  
  206. #ifdef TCPCONN
  207.     if (oldsock >= 0) {        /* must be forked, and have a different socket
  208.                  * to listen to */
  209. #ifdef NOTDEf
  210.     if (listen(oldsock, 5)) {
  211.         Error("TCP listening");
  212.         close(oldsock);
  213.         FatalError("Cannot re-establish the listening socket");
  214.         return;
  215.     }
  216. #endif
  217.     NoticeF("Reusing existing file descriptor %d\n", oldsock);
  218.     WellKnownConnections |= (1L << oldsock);
  219.     } else {
  220.     if ((request = open_tcp_socket()) != -1) {
  221.         WellKnownConnections |= (1L << request);
  222.     }
  223.     }
  224. #endif                /* TCPCONN */
  225.  
  226.     if (WellKnownConnections == 0)
  227.     FatalError("Cannot establish any listening sockets");
  228.  
  229.  
  230.     /* set up all the signal handlers */
  231.     signal(SIGPIPE, SIG_IGN);
  232.     signal(SIGHUP, AutoResetServer);
  233.     signal(SIGINT, GiveUp);
  234.     signal(SIGTERM, GiveUp);
  235.     signal(SIGUSR1, ServerReconfig);
  236.     signal(SIGUSR2, ServerCacheFlush);
  237.  
  238.     AllSockets[0] = WellKnownConnections;
  239. }
  240.  
  241. /*
  242.  * called when server cycles
  243.  */
  244. ResetSockets()
  245. {
  246. }
  247.  
  248. /*
  249.  * accepts new connections
  250.  */
  251. void
  252. MakeNewConnections()
  253. {
  254.     long        readyconnections;
  255.     int         curconn;
  256.     int         newconn;
  257.     long        connect_time;
  258.     int         i;
  259.     ClientPtr   client;
  260.     OsCommPtr   oc;
  261.  
  262. #ifdef TCP_NODELAY
  263.     union {
  264.     struct sockaddr sa;
  265.  
  266. #ifdef TCPCONN
  267.     struct sockaddr_in in;
  268. #endif                /* TCPCONN */
  269.     }           from;
  270.     int         fromlen;
  271.  
  272. #endif                /* TCP_NODELAY */
  273.  
  274.     readyconnections = (LastSelectMask[0] & WellKnownConnections);
  275.     if (!readyconnections)
  276.     return;
  277.     connect_time = GetTimeInMillis();
  278.  
  279.     /* kill off stragglers */
  280.     for (i = MINCLIENT; i < currentMaxClients; i++) {
  281.     if ((client = clients[i]) != NullClient) {
  282.         oc = (OsCommPtr) client->osPrivate;
  283.         if (oc && (oc->conn_time != 0) &&
  284.             (connect_time - oc->conn_time) >= TimeOutValue)
  285.         CloseDownClient(client);
  286.     }
  287.     }
  288.  
  289.     while (readyconnections) {
  290.     curconn = ffs(readyconnections) - 1;
  291.     readyconnections &= ~(1 << curconn);
  292.     if ((newconn = accept(curconn, (struct sockaddr *) NULL,
  293.                   (int *) NULL)) < 0)
  294.         continue;
  295.  
  296. #ifdef TCP_NODELAY
  297.     fromlen = sizeof(from);
  298.     if (!getpeername(newconn, &from.sa, &fromlen)) {
  299.         if (fromlen && (from.sa.sa_family == AF_INET)) {
  300.         int         mi = 1;
  301.  
  302.         setsockopt(newconn, IPPROTO_TCP, TCP_NODELAY,
  303.                (char *) &mi, sizeof(int));
  304.         }
  305.     }
  306. #endif                /* TCP_NODELAY */
  307.  
  308.     /* ultrix reads hang on Unix sockets, hpux reads fail */
  309.  
  310. #if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux) && !defined(AIXV3))
  311.     (void) fcntl(newconn, F_SETFL, O_NONBLOCK);
  312. #else
  313. #ifdef FIOSNBIO
  314.     {
  315.         int         arg = 1;
  316.  
  317.         ioctl(newconn, FIOSNBIO, &arg);
  318.     }
  319. #else
  320. #if defined(AIXV3) && defined(FIONBIO)
  321.     {
  322.         int arg;
  323.         arg = 1;
  324.         ioctl(newconn, FIONBIO, &arg);
  325.     }
  326. #else
  327.     (void) fcntl(newconn, F_SETFL, FNDELAY);
  328. #endif
  329. #endif
  330. #endif
  331.  
  332.     oc = (OsCommPtr) fsalloc(sizeof(OsCommRec));
  333.     if (!oc) {
  334.         fsfree(oc);
  335.         error_conn_max(newconn);
  336.         close(newconn);
  337.         continue;
  338.     }
  339.     BITSET(AllClients, newconn);
  340.     BITSET(AllSockets, newconn);
  341.     oc->fd = newconn;
  342.     oc->input = (ConnectionInputPtr) NULL;
  343.     oc->output = (ConnectionOutputPtr) NULL;
  344.     oc->conn_time = connect_time;
  345.  
  346.     if ((newconn < lastfdesc) &&
  347.         (client = NextAvailableClient((pointer) oc))) {
  348.         ConnectionTranslation[newconn] = client->index;
  349.     } else {
  350.         error_conn_max(newconn);
  351.         close_fd(oc);
  352.     }
  353.     }
  354. }
  355.  
  356. #define    NOROOM    "Maximum number of clients reached"
  357.  
  358. static void
  359. error_conn_max(fd)
  360.     int         fd;
  361. {
  362.     fsConnSetup conn;
  363.     char        pad[3];
  364.     char        byteOrder = 0;
  365.     int         whichbyte = 1;
  366.     struct timeval waittime;
  367.     long        mask[mskcnt];
  368.  
  369.  
  370.     waittime.tv_usec = BOTIMEOUT / MILLI_PER_SECOND;
  371.     waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
  372.     (1000000 / MILLI_PER_SECOND);
  373.     CLEARBITS(mask);
  374.     BITSET(mask, fd);
  375.     (void) select(fd + 1, (int *) mask, (int *) NULL, (int *) NULL, &waittime);
  376.     /* try to read the byteorder of the connection */
  377.     (void) read(fd, &byteOrder, 1);
  378.     if ((byteOrder == 'l') || (byteOrder == 'B')) {
  379.     int         num_alts;
  380.     AlternateServerPtr altservers,
  381.                 as;
  382.     int         i,
  383.                 altlen = 0;
  384.  
  385.     num_alts = ListAlternateServers(&altservers);
  386.     conn.status = AuthDenied;
  387.     conn.major_version = FS_PROTOCOL;
  388.     conn.minor_version = FS_PROTOCOL_MINOR;
  389.     conn.num_alternates = num_alts;
  390.     for (i = 0, as = altservers; i < num_alts; i++, as++) {
  391.         altlen += (2 + as->namelen + 3) >> 2;
  392.     }
  393.     conn.alternate_len = altlen;
  394.     /* blow off the auth info */
  395.     conn.auth_index = 0;
  396.     conn.auth_len = 0;
  397.  
  398.     if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
  399.         (!(*(char *) &whichbyte) && (byteOrder == 'l'))) {
  400.         swaps(&conn.status, whichbyte);
  401.         swaps(&conn.major_version, whichbyte);
  402.         swaps(&conn.minor_version, whichbyte);
  403.         swaps(&conn.alternate_len, whichbyte);
  404.     }
  405.     (void) write(fd, (char *) &conn, sizeof(fsConnSetup));
  406.     /* dump alternates */
  407.     for (i = 0, as = altservers; i < num_alts; i++, as++) {
  408.         (void) write(fd, (char *) as, 2);    /* XXX */
  409.         (void) write(fd, (char *) as->name, as->namelen);
  410.         altlen = 2 + as->namelen;
  411.         /* pad it */
  412.         if (altlen & 3)
  413.         (void) write(fd, (char *) pad, ((4 - (altlen & 3)) & 3));
  414.     }
  415.     if (num_alts)
  416.         fsfree((char *) altservers);
  417.     }
  418. }
  419.  
  420. static void
  421. close_fd(oc)
  422.     OsCommPtr   oc;
  423. {
  424.     int         fd = oc->fd;
  425.  
  426.     close(fd);
  427.     FreeOsBuffers(oc);
  428.     BITCLEAR(AllSockets, fd);
  429.     BITCLEAR(AllClients, fd);
  430.     BITCLEAR(ClientsWithInput, fd);
  431.     BITCLEAR(ClientsWriteBlocked, fd);
  432.     if (!ANYSET(ClientsWriteBlocked))
  433.     AnyClientsWriteBlocked = FALSE;
  434.     BITCLEAR(OutputPending, fd);
  435.     fsfree(oc);
  436. }
  437.  
  438. CheckConnections()
  439. {
  440.     long        mask[mskcnt];
  441.     long        tmask[mskcnt];
  442.     int         curclient;
  443.     int         i;
  444.     struct timeval notime;
  445.     int         r;
  446.  
  447.     notime.tv_sec = 0;
  448.     notime.tv_usec = 0;
  449.  
  450.     COPYBITS(AllClients, mask);
  451.     for (i = 0; i < mskcnt; i++) {
  452.     while (mask[i]) {
  453.         curclient = ffs(mask[i]) - 1 + (i << 5);
  454.         CLEARBITS(tmask);
  455.         BITSET(tmask, curclient);
  456.         r = select(curclient + 1, (int *) tmask, (int *) NULL,
  457.                (int *) NULL, ¬ime);
  458.         if (r < 0)
  459.         CloseDownClient(clients[ConnectionTranslation[curclient]]);
  460.         BITCLEAR(mask, curclient);
  461.     }
  462.     }
  463. }
  464.  
  465. CloseDownConnection(client)
  466.     ClientPtr   client;
  467. {
  468.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  469.  
  470.     if (oc->output && oc->output->count)
  471.     FlushClient(client, oc, (char *) NULL, 0, 0);
  472.     ConnectionTranslation[oc->fd] = 0;
  473.     close_fd(oc);
  474.     client->osPrivate = (pointer) NULL;
  475. }
  476.  
  477.  
  478. /****************
  479.  * IgnoreClient
  480.  *    Removes one client from input masks.
  481.  *    Must have cooresponding call to AttendClient.
  482.  ****************/
  483.  
  484. static long IgnoredClientsWithInput[mskcnt];
  485.  
  486. IgnoreClient(client)
  487.     ClientPtr   client;
  488. {
  489.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  490.     int         connection = oc->fd;
  491.  
  492.     if (GETBIT(ClientsWithInput, connection))
  493.     BITSET(IgnoredClientsWithInput, connection);
  494.     else
  495.     BITCLEAR(IgnoredClientsWithInput, connection);
  496.     BITCLEAR(ClientsWithInput, connection);
  497.     BITCLEAR(AllSockets, connection);
  498.     BITCLEAR(AllClients, connection);
  499.     BITCLEAR(LastSelectMask, connection);
  500.     isItTimeToYield = TRUE;
  501. }
  502.  
  503. /****************
  504.  * AttendClient
  505.  *    Adds one client back into the input masks.
  506.  ****************/
  507.  
  508. AttendClient(client)
  509.     ClientPtr   client;
  510. {
  511.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  512.     int         connection = oc->fd;
  513.  
  514.     BITSET(AllClients, connection);
  515.     BITSET(AllSockets, connection);
  516.     BITSET(LastSelectMask, connection);
  517.     if (GETBIT(IgnoredClientsWithInput, connection))
  518.     BITSET(ClientsWithInput, connection);
  519. }
  520.  
  521. /*
  522.  * figure out which clients need to be toasted
  523.  */
  524. ReapAnyOldClients()
  525. {
  526.     int         i;
  527.     long        cur_time = GetTimeInMillis();
  528.     ClientPtr   client;
  529.     extern void SendKeepAliveEvent();
  530.  
  531. #ifdef DEBUG
  532.     fprintf(stderr, "Looking for clients to reap\n");
  533. #endif
  534.  
  535.     for (i = MINCLIENT; i < currentMaxClients; i++) {
  536.     client = clients[i];
  537.     if (client) {
  538.         if ((cur_time - client->last_request_time) >= ReapClientTime) {
  539.         if (client->clientGone == CLIENT_AGED) {
  540.             client->clientGone = CLIENT_TIMED_OUT;
  541.  
  542. #ifdef DEBUG
  543.             fprintf(stderr, "reaping client #%d\n", i);
  544. #endif
  545.  
  546.             CloseDownClient(client);
  547.         } else {
  548.             client->clientGone = CLIENT_AGED;
  549.             SendKeepAliveEvent(client);
  550.         }
  551.         }
  552.     }
  553.     }
  554. }
  555.