Home | History | Annotate | Line # | Download | only in os
      1 /*
      2  * handles connections
      3  */
      4 /*
      5 
      6 Copyright 1990, 1991, 1998  The Open Group
      7 
      8 Permission to use, copy, modify, distribute, and sell this software and its
      9 documentation for any purpose is hereby granted without fee, provided that
     10 the above copyright notice appear in all copies and that both that
     11 copyright notice and this permission notice appear in supporting
     12 documentation.
     13 
     14 The above copyright notice and this permission notice shall be included in
     15 all copies or substantial portions of the Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     20 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 
     24 Except as contained in this notice, the name of The Open Group shall not be
     25 used in advertising or otherwise to promote the sale, use or other dealings
     26 in this Software without prior written authorization from The Open Group.
     27 
     28  * Copyright 1990, 1991 Network Computing Devices;
     29  * Portions Copyright 1987 by Digital Equipment Corporation
     30  *
     31  * Permission to use, copy, modify, distribute, and sell this software and
     32  * its documentation for any purpose is hereby granted without fee, provided
     33  * that the above copyright notice appear in all copies and that both that
     34  * copyright notice and this permission notice appear in supporting
     35  * documentation, and that the names of Network Computing Devices, or Digital
     36  * not be used in advertising or publicity pertaining to distribution
     37  * of the software without specific, written prior permission.
     38  *
     39  * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
     40  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
     41  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
     42  * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     43  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     44  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     45  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     46  * THIS SOFTWARE.
     47  */
     48 /*
     49  * Copyright 1990, 1991 Network Computing Devices;
     50  * Portions Copyright 1987 by Digital Equipment Corporation
     51  *
     52  * Permission to use, copy, modify, distribute, and sell this software and
     53  * its documentation for any purpose is hereby granted without fee, provided
     54  * that the above copyright notice appear in all copies and that both that
     55  * copyright notice and this permission notice appear in supporting
     56  * documentation, and that the names of Network Computing Devices, or Digital
     57  * not be used in advertising or publicity pertaining to distribution
     58  * of the software without specific, written prior permission.
     59  *
     60  * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
     61  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
     62  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
     63  * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     64  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     65  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     66  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     67  * THIS SOFTWARE.
     68  */
     69 
     70 #include	"config.h"
     71 
     72 /* include Xpoll.h early for possible FD_SETSIZE re-definition */
     73 #include	"X11/Xpoll.h"
     74 #include	<stdlib.h>
     75 #include	<X11/Xtrans/Xtrans.h>
     76 #include	<stdlib.h>
     77 #include	"misc.h"
     78 #include	<stdio.h>
     79 #include	<errno.h>
     80 #include	<X11/Xos.h>
     81 #include	<sys/param.h>
     82 #include	<sys/socket.h>
     83 #include	<sys/uio.h>
     84 #include	<signal.h>
     85 
     86 #include	<X11/fonts/FS.h>
     87 #include	<X11/fonts/FSproto.h>
     88 #include	"clientstr.h"
     89 #include	"osdep.h"
     90 #include	"globals.h"
     91 #include	"osstruct.h"
     92 #include	"servermd.h"
     93 #include	"dispatch.h"
     94 #include	"fsevents.h"
     95 
     96 
     97 
     98 int         ListenPort = DEFAULT_FS_PORT;   /* port to listen on */
     99 int         lastfdesc;
    100 
    101 fd_set      WellKnownConnections;
    102 fd_set      AllSockets;
    103 fd_set      AllClients;
    104 fd_set      LastSelectMask;
    105 fd_set      ClientsWithInput;
    106 fd_set      ClientsWriteBlocked;
    107 fd_set      OutputPending;
    108 long        OutputBufferSize = BUFSIZE;
    109 
    110 Bool        NewOutputPending;
    111 Bool        AnyClientsWriteBlocked;
    112 
    113 int         ConnectionTranslation[MAXSOCKS];
    114 
    115 XtransConnInfo 	*ListenTransConns = NULL;
    116 int	       	*ListenTransFds = NULL;
    117 int		ListenTransCount;
    118 
    119 
    120 extern int  xfd_ffs (fd_mask);
    121 static void error_conn_max(XtransConnInfo trans_conn);
    122 static void close_fd(OsCommPtr oc);
    123 
    124 
    125 static XtransConnInfo
    126 lookup_trans_conn (int fd)
    127 {
    128     if (ListenTransFds)
    129     {
    130 	int i;
    131 	for (i = 0; i < ListenTransCount; i++)
    132 	    if (ListenTransFds[i] == fd)
    133 		return ListenTransConns[i];
    134     }
    135 
    136     return (NULL);
    137 }
    138 
    139 void
    140 StopListening(void)
    141 {
    142     int i;
    143 
    144     for (i = 0; i < ListenTransCount; i++)
    145     {
    146 	FD_CLR (ListenTransFds[i], &AllSockets);
    147 	_FontTransCloseForCloning (ListenTransConns[i]);
    148     }
    149 
    150     free ((char *) ListenTransFds);
    151     free ((char *) ListenTransConns);
    152 
    153     ListenTransFds = NULL;
    154     ListenTransConns = NULL;
    155     ListenTransCount = 0;
    156 }
    157 
    158 /*
    159  * creates the sockets for listening to clients
    160  *
    161  * only called when server first started
    162  */
    163 void
    164 CreateSockets(int old_listen_count, OldListenRec *old_listen)
    165 {
    166     int	i;
    167     struct sigaction act;
    168 
    169     FD_ZERO(&AllSockets);
    170     FD_ZERO(&AllClients);
    171     FD_ZERO(&LastSelectMask);
    172     FD_ZERO(&ClientsWithInput);
    173     FD_ZERO(&WellKnownConnections);
    174 
    175     for (i = 0; i < MAXSOCKS; i++)
    176 	ConnectionTranslation[i] = 0;
    177 
    178     lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
    179 
    180     if ((lastfdesc < 0) || (lastfdesc > MAXSOCKS)) {
    181 	lastfdesc = MAXSOCKS;
    182     }
    183 
    184     if (old_listen_count > 0) {
    185 
    186 	/*
    187 	 * The font server cloned itself.  Re-use previously opened
    188 	 * transports for listening.
    189 	 */
    190 
    191 	ListenTransConns = (XtransConnInfo *) malloc (
    192 	    old_listen_count * sizeof (XtransConnInfo));
    193 
    194 	ListenTransFds = (int *) malloc (old_listen_count * sizeof (int));
    195 
    196 	ListenTransCount = 0;
    197 
    198 	for (i = 0; i < old_listen_count; i++)
    199 	{
    200 	    char portnum[10];
    201 
    202 	    if (old_listen[i].portnum != ListenPort)
    203 		continue;		/* this should never happen */
    204 	    else
    205 		snprintf (portnum, sizeof(portnum), "%d", old_listen[i].portnum);
    206 
    207 	    if ((ListenTransConns[ListenTransCount] =
    208 		_FontTransReopenCOTSServer (old_listen[i].trans_id,
    209 		old_listen[i].fd, portnum)) != NULL)
    210 	    {
    211 		ListenTransFds[ListenTransCount] = old_listen[i].fd;
    212 		FD_SET (old_listen[i].fd, &WellKnownConnections);
    213 
    214 		NoticeF("reusing existing file descriptor %d\n",
    215 		    old_listen[i].fd);
    216 
    217 		ListenTransCount++;
    218 	    }
    219 	}
    220     } else {
    221 	char port[20];
    222 	int partial;
    223 
    224 	snprintf (port, sizeof(port), "%d", ListenPort);
    225 
    226 	if ((_FontTransMakeAllCOTSServerListeners (port, &partial,
    227 	    &ListenTransCount, &ListenTransConns) >= 0) &&
    228 	    (ListenTransCount >= 1))
    229 	{
    230 	    ListenTransFds = (int *) malloc (ListenTransCount * sizeof (int));
    231 
    232 	    for (i = 0; i < ListenTransCount; i++)
    233 	    {
    234 		int fd = _FontTransGetConnectionNumber (ListenTransConns[i]);
    235 
    236 		ListenTransFds[i] = fd;
    237 		FD_SET (fd, &WellKnownConnections);
    238 	    }
    239 	}
    240     }
    241 
    242     if (! XFD_ANYSET(&WellKnownConnections))
    243 	FatalError("cannot establish any listening sockets\n");
    244 
    245     /* set up all the signal handlers */
    246     sigemptyset(&act.sa_mask);
    247     act.sa_flags = SA_RESTART;
    248 #define HANDLE_SIGNAL(s, h)	act.sa_handler = h; sigaction(s, &act, NULL)
    249 
    250     HANDLE_SIGNAL(SIGPIPE, SIG_IGN);
    251     HANDLE_SIGNAL(SIGHUP, AutoResetServer);
    252     HANDLE_SIGNAL(SIGINT, GiveUp);
    253     HANDLE_SIGNAL(SIGTERM, GiveUp);
    254     HANDLE_SIGNAL(SIGUSR1, ServerReconfig);
    255     HANDLE_SIGNAL(SIGUSR2, ServerCacheFlush);
    256     HANDLE_SIGNAL(SIGCHLD, CleanupChild);
    257 
    258     XFD_COPYSET (&WellKnownConnections, &AllSockets);
    259 }
    260 
    261 /*
    262  * called when server cycles
    263  */
    264 void
    265 ResetSockets(void)
    266 {
    267 }
    268 
    269 void
    270 CloseSockets(void)
    271 {
    272     int i;
    273 
    274     for (i = 0; i < ListenTransCount; i++)
    275 	_FontTransClose (ListenTransConns[i]);
    276 }
    277 
    278 /*
    279  * accepts new connections
    280  */
    281 void
    282 MakeNewConnections(void)
    283 {
    284     fd_mask     readyconnections;
    285     int         curconn;
    286     int         newconn;
    287     long        connect_time;
    288     int         i;
    289     ClientPtr   client;
    290     OsCommPtr   oc;
    291     fd_set	tmask;
    292 
    293     XFD_ANDSET (&tmask, &LastSelectMask, &WellKnownConnections);
    294     readyconnections = tmask.fds_bits[0];
    295     if (!readyconnections)
    296 	return;
    297     connect_time = GetTimeInMillis();
    298 
    299     /* kill off stragglers */
    300     for (i = MINCLIENT; i < currentMaxClients; i++) {
    301 	if ((client = clients[i]) != NullClient) {
    302 	    oc = (OsCommPtr) client->osPrivate;
    303 	    if ((oc && (oc->conn_time != 0) &&
    304 		    (connect_time - oc->conn_time) >= TimeOutValue) ||
    305 		     ((client->noClientException != FSSuccess) &&
    306 		      (client->clientGone != CLIENT_GONE)))
    307 		CloseDownClient(client);
    308 	}
    309     }
    310 
    311     while (readyconnections) {
    312 	XtransConnInfo trans_conn, new_trans_conn;
    313 	int status;
    314 
    315 	curconn = xfd_ffs(readyconnections) - 1;
    316 	readyconnections &= ~(1 << curconn);
    317 
    318 	if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
    319 	    continue;
    320 
    321 	if ((new_trans_conn = _FontTransAccept (trans_conn, &status)) == NULL)
    322 	    continue;
    323 
    324 	newconn = _FontTransGetConnectionNumber (new_trans_conn);
    325 
    326 	_FontTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
    327 
    328 	oc = (OsCommPtr) FSalloc(sizeof(OsCommRec));
    329 	if (!oc) {
    330 	    FSfree(oc);
    331 	    error_conn_max(new_trans_conn);
    332 	    _FontTransClose(new_trans_conn);
    333 	    continue;
    334 	}
    335 	FD_SET(newconn, &AllClients);
    336 	FD_SET(newconn, &AllSockets);
    337 	oc->fd = newconn;
    338 	oc->trans_conn = new_trans_conn;
    339 	oc->input = (ConnectionInputPtr) NULL;
    340 	oc->output = (ConnectionOutputPtr) NULL;
    341 	oc->conn_time = connect_time;
    342 
    343 	if ((newconn < lastfdesc) &&
    344 		(client = NextAvailableClient((pointer) oc))) {
    345 	    ConnectionTranslation[newconn] = client->index;
    346 	} else {
    347 	    error_conn_max(new_trans_conn);
    348 	    close_fd(oc);
    349 	}
    350     }
    351 }
    352 
    353 #define	NOROOM	"maximum number of clients reached"
    354 
    355 static void
    356 error_conn_max(XtransConnInfo trans_conn)
    357 {
    358     int fd = _FontTransGetConnectionNumber (trans_conn);
    359     fsConnSetup conn;
    360     char        pad[3];
    361     char        byteOrder = 0;
    362     int         whichbyte = 1;
    363     struct timeval waittime;
    364     fd_set      mask;
    365 
    366 
    367     waittime.tv_usec = BOTIMEOUT / MILLI_PER_SECOND;
    368     waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
    369 	(1000000 / MILLI_PER_SECOND);
    370     FD_ZERO(&mask);
    371     FD_SET(fd, &mask);
    372     (void) Select(fd + 1, &mask, NULL, NULL, &waittime);
    373     /* try to read the byteorder of the connection */
    374     (void) _FontTransRead(trans_conn, &byteOrder, 1);
    375     if ((byteOrder == 'l') || (byteOrder == 'B')) {
    376 	int         num_alts;
    377 	AlternateServerPtr altservers,
    378 	            as;
    379 	int         i,
    380 	            altlen = 0;
    381 
    382 	num_alts = ListAlternateServers(&altservers);
    383 	conn.status = AuthDenied;
    384 	conn.major_version = FS_PROTOCOL;
    385 	conn.minor_version = FS_PROTOCOL_MINOR;
    386 	conn.num_alternates = num_alts;
    387 	for (i = 0, as = altservers; i < num_alts; i++, as++) {
    388 	    altlen += (2 + as->namelen + 3) >> 2;
    389 	}
    390 	conn.alternate_len = altlen;
    391 	/* blow off the auth info */
    392 	conn.auth_index = 0;
    393 	conn.auth_len = 0;
    394 
    395 	if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
    396 		(!(*(char *) &whichbyte) && (byteOrder == 'l'))) {
    397 	    conn.status = lswaps(conn.status);
    398 	    conn.major_version = lswaps(conn.major_version);
    399 	    conn.minor_version = lswaps(conn.minor_version);
    400 	    conn.alternate_len = lswaps(conn.alternate_len);
    401 	}
    402 	(void) _FontTransWrite(trans_conn,
    403 	    (char *) &conn, SIZEOF(fsConnSetup));
    404 	/* dump alternates */
    405 	for (i = 0, as = altservers; i < num_alts; i++, as++) {
    406 	    (void) _FontTransWrite(trans_conn,
    407 		(char *) as, 2);  /* XXX */
    408 	    (void) _FontTransWrite(trans_conn,
    409 		(char *) as->name, as->namelen);
    410 	    altlen = 2 + as->namelen;
    411 	    /* pad it */
    412 	    if (altlen & 3)
    413 		(void) _FontTransWrite(trans_conn,
    414 		(char *) pad, ((4 - (altlen & 3)) & 3));
    415 	}
    416     }
    417 }
    418 
    419 static void
    420 close_fd(OsCommPtr oc)
    421 {
    422     int         fd = oc->fd;
    423 
    424     if (oc->trans_conn)
    425 	_FontTransClose(oc->trans_conn);
    426     FreeOsBuffers(oc);
    427     FD_CLR(fd, &AllSockets);
    428     FD_CLR(fd, &AllClients);
    429     FD_CLR(fd, &ClientsWithInput);
    430     FD_CLR(fd, &ClientsWriteBlocked);
    431     if (!XFD_ANYSET(&ClientsWriteBlocked))
    432 	AnyClientsWriteBlocked = FALSE;
    433     FD_CLR(fd, &OutputPending);
    434     FSfree(oc);
    435 }
    436 
    437 void
    438 CheckConnections(void)
    439 {
    440     fd_set      mask;
    441     fd_set      tmask;
    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     XFD_COPYSET(&AllClients, &mask);
    451     for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
    452 	while (mask.fds_bits[i]) {
    453 	    curclient = xfd_ffs(mask.fds_bits[i]) - 1 + (i * (sizeof(fd_mask) * 8));
    454 	    FD_ZERO(&tmask);
    455 	    FD_SET(curclient, &tmask);
    456 	    r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
    457 	    if (r < 0)
    458 		CloseDownClient(clients[ConnectionTranslation[curclient]]);
    459 	    FD_CLR(curclient, &mask);
    460 	}
    461     }
    462 }
    463 
    464 void
    465 CloseDownConnection(ClientPtr client)
    466 {
    467     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
    468 
    469     if (oc == NULL)
    470 	return;
    471 
    472     if (oc->output && oc->output->count)
    473 	FlushClient(client, oc, (char *) NULL, 0, 0);
    474     ConnectionTranslation[oc->fd] = 0;
    475     close_fd(oc);
    476     client->osPrivate = (pointer) NULL;
    477 }
    478 
    479 
    480 /****************
    481  * IgnoreClient
    482  *    Removes one client from input masks.
    483  *    Must have corresponding call to AttendClient.
    484  ****************/
    485 
    486 static fd_set IgnoredClientsWithInput;
    487 
    488 void
    489 IgnoreClient(ClientPtr client)
    490 {
    491     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
    492     int         connection = oc->fd;
    493 
    494     if (FD_ISSET(connection, &ClientsWithInput))
    495 	FD_SET(connection, &IgnoredClientsWithInput);
    496     else
    497 	FD_CLR(connection, &IgnoredClientsWithInput);
    498     FD_CLR(connection, &ClientsWithInput);
    499     FD_CLR(connection, &AllSockets);
    500     FD_CLR(connection, &AllClients);
    501     FD_CLR(connection, &LastSelectMask);
    502     isItTimeToYield = TRUE;
    503 }
    504 
    505 /****************
    506  * AttendClient
    507  *    Adds one client back into the input masks.
    508  ****************/
    509 
    510 void
    511 AttendClient(ClientPtr client)
    512 {
    513     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
    514     int         connection = oc->fd;
    515 
    516     FD_SET(connection, &AllClients);
    517     FD_SET(connection, &AllSockets);
    518     FD_SET(connection, &LastSelectMask);
    519     if (FD_ISSET(connection, &IgnoredClientsWithInput))
    520 	FD_SET(connection, &ClientsWithInput);
    521 }
    522 
    523 /*
    524  * figure out which clients need to be toasted
    525  */
    526 void
    527 ReapAnyOldClients(void)
    528 {
    529     int         i;
    530     long        cur_time = GetTimeInMillis();
    531     ClientPtr   client;
    532 
    533 #ifdef DEBUG
    534     fprintf(stderr, "looking for clients to reap\n");
    535 #endif
    536 
    537     for (i = MINCLIENT; i < currentMaxClients; i++) {
    538 	client = clients[i];
    539 	if (client) {
    540 	    if ((cur_time - client->last_request_time) >= ReapClientTime) {
    541 		if (client->clientGone == CLIENT_AGED) {
    542 		    client->clientGone = CLIENT_TIMED_OUT;
    543 
    544 #ifdef DEBUG
    545 		    fprintf(stderr, "reaping client #%d\n", i);
    546 #endif
    547 
    548 		    CloseDownClient(client);
    549 		} else {
    550 		    client->clientGone = CLIENT_AGED;
    551 		    SendKeepAliveEvent(client);
    552 		}
    553 	    }
    554 	}
    555     }
    556 }
    557