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