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