connection.c revision 8ae5c7d9
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 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
98int         ListenPort = DEFAULT_FS_PORT;   /* port to listen on */
99int         lastfdesc;
100
101fd_set      WellKnownConnections;
102fd_set      AllSockets;
103fd_set      AllClients;
104fd_set      LastSelectMask;
105fd_set      ClientsWithInput;
106fd_set      ClientsWriteBlocked;
107fd_set      OutputPending;
108long        OutputBufferSize = BUFSIZE;
109
110Bool        NewOutputPending;
111Bool        AnyClientsWriteBlocked;
112
113int         ConnectionTranslation[MAXSOCKS];
114
115XtransConnInfo 	*ListenTransConns = NULL;
116int	       	*ListenTransFds = NULL;
117int		ListenTransCount;
118
119
120extern int  xfd_ffs (fd_mask);
121static void error_conn_max(XtransConnInfo trans_conn);
122static void close_fd(OsCommPtr oc);
123
124
125static XtransConnInfo
126lookup_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
139void
140StopListening(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 */
163void
164CreateSockets(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 */
264void
265ResetSockets(void)
266{
267}
268
269void
270CloseSockets(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 */
281void
282MakeNewConnections(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
355static void
356error_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
419static void
420close_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
437void
438CheckConnections(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
464void
465CloseDownConnection(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
486static fd_set IgnoredClientsWithInput;
487
488void
489IgnoreClient(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
510void
511AttendClient(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 */
526void
527ReapAnyOldClients(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