dispatch.c revision bbe1b32b
1/* $Xorg: dispatch.c,v 1.6 2001/02/09 02:05:42 xorgcvs Exp $ */
2/*
3 * protocol dispatcher
4 */
5/*
6
7Copyright 1990, 1991, 1998  The Open Group
8
9Permission to use, copy, modify, distribute, and sell this software and its
10documentation for any purpose is hereby granted without fee, provided that
11the above copyright notice appear in all copies and that both that
12copyright notice and this permission notice appear in supporting
13documentation.
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of The Open Group shall not be
26used in advertising or otherwise to promote the sale, use or other dealings
27in this Software without prior written authorization from The Open Group.
28
29 * Copyright 1990, 1991 Network Computing Devices;
30 * Portions Copyright 1987 by Digital Equipment Corporation
31 *
32 * Permission to use, copy, modify, distribute, and sell this software and
33 * its documentation for any purpose is hereby granted without fee, provided
34 * that the above copyright notice appear in all copies and that both that
35 * copyright notice and this permission notice appear in supporting
36 * documentation, and that the names of Network Computing Devices, or Digital
37 * not be used in advertising or publicity pertaining to distribution
38 * of the software without specific, written prior permission.
39 *
40 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
41 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
43 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
47 * THIS SOFTWARE.
48 */
49/* $XFree86: xc/programs/xfs/difs/dispatch.c,v 3.12 2001/12/14 20:01:33 dawes Exp $ */
50
51#include	<stdlib.h>
52#include	"dispatch.h"
53#include	"swapreq.h"
54#include	"swaprep.h"
55
56#include	<X11/fonts/FS.h>
57#include	<X11/fonts/FSproto.h>
58#include	"clientstr.h"
59#include	"authstr.h"
60#include	"osstruct.h"
61#include	"extentst.h"
62#include	"globals.h"
63#include	"fsresource.h"
64#include	"difsfnst.h"
65#include	<X11/fonts/fontstruct.h>
66#include	"site.h"
67#include	"fsevents.h"
68#include	"cache.h"
69#include	"globals.h"
70#include	"difs.h"
71
72static void kill_all_clients(void);
73
74volatile char        dispatchException = 0;
75volatile char        isItTimeToYield;
76
77ClientPtr   currentClient;
78
79static int  nClients = 0;
80static int  nextFreeClientID;
81
82extern char *ConnectionInfo;
83extern int  ConnInfoLen;
84
85extern char *configfilename;
86
87extern Bool drone_server;
88
89#define	MAJOROP	((fsReq *)client->requestBuffer)->reqType
90
91#define	ALL_FORMAT_BITS	(BitmapFormatByteOrderMask | \
92			 BitmapFormatBitOrderMask | \
93			 BitmapFormatScanlineUnitMask | \
94			 BitmapFormatScanlinePadMask | \
95			 BitmapFormatImageRectMask)
96
97#define	ALL_FORMAT_MASK_BITS	(BitmapFormatMaskByte | \
98				 BitmapFormatMaskBit | \
99				 BitmapFormatMaskImageRectangle | \
100				 BitmapFormatMaskScanLinePad | \
101				 BitmapFormatMaskScanLineUnit)
102
103void
104Dispatch(void)
105{
106    int         nready,
107                result;
108    int        *clientReady;
109    ClientPtr   client;
110    int		op;
111
112    nextFreeClientID = MINCLIENT;
113    nClients = 0;
114
115    clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients);
116    if (!clientReady)
117	return;
118
119    while (1) {
120	/* wait for something */
121	nready = WaitForSomething(clientReady);
122
123	while (!dispatchException && (--nready >= 0)) {
124	    client = currentClient = clients[clientReady[nready]];
125
126	    /* Client can be NULL if CloseDownClient() is called during
127	       this dispatchException loop. */
128	    if (client == (ClientPtr)NULL) continue;
129
130	    isItTimeToYield = FALSE;
131
132	    while (!isItTimeToYield) {
133		result = ReadRequest(client);
134		if (result <= 0) {
135		    if (result < 0)
136			CloseDownClient(client);
137		    break;
138		}
139		client->sequence++;
140
141		if (result > (MAX_REQUEST_SIZE << 2))
142		    result = FSBadLength;
143		else
144		{
145		    op = MAJOROP;
146		    if (op >= NUM_PROC_VECTORS)
147			result = ProcBadRequest (client);
148		    else if (*client->requestVector[op] != NULL)
149			result = (*client->requestVector[op]) (client);
150		    else
151			result = FSBadRequest;
152		}
153		if (result != FSSuccess) {
154		    if (client->noClientException != FSSuccess)
155			CloseDownClient(client);
156		    break;
157		}
158	    }
159	    FlushAllOutput ();
160	}
161	/* reset if server is a drone and has run out of clients */
162	if (drone_server && nClients == 0) {
163	    dispatchException |= DE_RESET;
164	}
165	if (dispatchException) {
166	    /* re-read the config file */
167	    if (dispatchException & DE_RECONFIG) {
168		NoticeF("re-reading config file\n");
169		if (ReadConfigFile(configfilename) != FSSuccess)
170		    ErrorF("couldn't parse config file\n");
171		SetConfigValues();
172		dispatchException &= ~DE_RECONFIG;
173	    }
174	    /* flush all the caches */
175	    if (dispatchException & DE_FLUSH) {
176		NoticeF("flushing all caches\n");
177		CacheReset();
178		dispatchException &= ~DE_FLUSH;
179	    }
180	    /* reset */
181	    if (dispatchException & DE_RESET) {
182		NoticeF("resetting\n");
183		break;
184	    }
185	    /* die *now* */
186	    if (dispatchException & DE_TERMINATE) {
187		NoticeF("terminating\n");
188		kill_all_clients();
189		CloseSockets();
190		CloseErrors();
191		exit(0);
192		break;
193	    }
194	}
195    }
196    kill_all_clients();
197    dispatchException = 0;
198}
199
200int
201ProcInitialConnection(ClientPtr client)
202{
203    REQUEST(fsFakeReq);
204    fsConnClientPrefix *prefix;
205    int         whichbyte = 1;
206
207    nClients++;
208    prefix = (fsConnClientPrefix *) stuff+1;
209    if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B'))
210	return (client->noClientException = -2);
211    if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) ||
212	    (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) {
213	int status;
214
215	client->swapped = TRUE;
216	status = SwapConnClientPrefix(client, prefix);
217	if (status != FSSuccess)
218	    return (status);
219    }
220    client->major_version = prefix->major_version;
221    client->minor_version = prefix->minor_version;
222    stuff->reqType = 2;
223    stuff->length += prefix->auth_len;
224    if (client->swapped) {
225	stuff->length = lswaps(stuff->length);
226    }
227    ResetCurrentRequest(client);
228    return client->noClientException;
229}
230
231int
232ProcEstablishConnection(ClientPtr client)
233{
234    fsConnClientPrefix *prefix;
235    fsConnSetup csp;
236    int         ret;
237    pointer     auth_data;
238    char       *ad;
239    char       *server_auth_data;
240    AuthPtr     client_auth;
241    int         i,
242                num_alts,
243                altlen,
244                auth_accept,
245                auth_index,
246                auth_len;
247    AlternateServerPtr altservers;
248
249    REQUEST(fsFakeReq);
250
251    prefix = (fsConnClientPrefix *) stuff+1;
252    auth_data = prefix + sz_fsConnClientPrefix;
253    client_auth = (AuthPtr) ALLOCATE_LOCAL(prefix->num_auths * sizeof(AuthRec));
254    if (!client_auth) {
255	SendErrToClient(client, FSBadAlloc, (pointer) 0);
256	return FSBadAlloc;
257    }
258/* XXXX -- this needs work for multiple auth replies */
259
260    /* build up a list of the stuff */
261    for (i = 0, ad = auth_data; i < (int)prefix->num_auths; i++) {
262	if (ad - (char *)auth_data > (stuff->length << 2) - 4) {
263	    int lengthword = stuff->length;
264
265	    SendErrToClient(client, FSBadLength, (pointer)&lengthword);
266	    return (FSBadLength);
267	}
268	/* copy carefully in case wire data is not aligned */
269	client_auth[i].namelen = (((unsigned char *)ad)[0] << 8) +
270				 ((unsigned char *)ad)[1];
271	ad += 2;
272	client_auth[i].datalen = (((unsigned char *)ad)[0] << 8) +
273				 ((unsigned char *)ad)[1];
274	ad += 2;
275	client_auth[i].name = (char *) ad;
276	ad += client_auth[i].namelen;
277	client_auth[i].data = (char *) ad;
278	ad += client_auth[i].datalen;
279    }
280    if (!(int)prefix->num_auths)
281	ad += 4;
282    if (ad - (char *)auth_data > (stuff->length << 2)) {
283	int lengthword = stuff->length;
284
285	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
286	return (FSBadLength);
287    }
288
289    num_alts = ListAlternateServers(&altservers);
290    for (i = 0, altlen = 0; i < num_alts; i++) {
291	/* subset + len + namelen + pad */
292	altlen += (2 + altservers[i].namelen + 3) >> 2;
293    }
294
295    auth_index = prefix->num_auths;
296    client->auth_generation = 0;
297    ret = CheckClientAuthorization(client, client_auth,
298		    &auth_accept, &auth_index, &auth_len, &server_auth_data);
299    if (auth_index > 0)
300    {
301	AuthContextPtr authp;
302	authp = (AuthContextPtr) fsalloc(sizeof(AuthContextRec));
303	if (!authp) {
304	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
305	    return FSBadAlloc;
306	}
307	authp->authname = 0;
308	authp->authdata = 0;
309	authp->authname =
310	    (char *) fsalloc(client_auth[auth_index - 1].namelen + 1);
311	authp->authdata =
312	    (char *) fsalloc(client_auth[auth_index - 1].datalen + 1);
313	if (!authp->authname || !authp->authdata) {
314	    fsfree((char *) authp->authname);
315	    fsfree((char *) authp->authdata);
316	    fsfree((char *) authp);
317	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
318	    return FSBadAlloc;
319	}
320	memmove( authp->authname, client_auth[auth_index - 1].name,
321	      client_auth[auth_index - 1].namelen);
322	memmove( authp->authdata, client_auth[auth_index - 1].data,
323	      client_auth[auth_index - 1].datalen);
324	/* Save it with a zero resource id...  subsequent
325	   SetAuthorizations of None will find it.  And it will be freed
326	   by FreeClientResources when the connection closes.  */
327	if (!AddResource(client->index, 0, RT_AUTHCONT,(pointer) authp))
328	{
329	    fsfree((char *) authp->authname);
330	    fsfree((char *) authp->authdata);
331	    fsfree((char *) authp);
332	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
333	    return FSBadAlloc;
334	}
335	client->auth = client->default_auth = authp;
336    }
337    else
338	client->auth = client->default_auth = (AuthContextPtr)0;
339
340    DEALLOCATE_LOCAL(client_auth);
341
342    if (ret != FSSuccess) {
343	SendErrToClient(client, FSBadAlloc, (pointer) 0);
344	return FSBadAlloc;
345    }
346    csp.status = auth_accept;
347    if (client->major_version == 1)
348	/* we implement backwards compatibility for version 1.0 */
349	csp.major_version = client->major_version;
350    else
351	csp.major_version = FS_PROTOCOL;
352    csp.minor_version = FS_PROTOCOL_MINOR;
353    csp.num_alternates = num_alts;
354    csp.alternate_len = altlen;
355    csp.auth_len = auth_len >> 2;
356    csp.auth_index = auth_index;
357    if (client->swapped) {
358	WriteSConnSetup(client, &csp);
359    } else {
360	(void) WriteToClient(client, SIZEOF(fsConnSetup), (char *) &csp);
361    }
362
363    /* send the alternates info */
364    for (i = 0; i < num_alts; i++) {
365	char        tmp[258];
366
367	/* WriteToClient pads, so we have to fake some things */
368	tmp[0] = altservers[i].subset;
369	tmp[1] = altservers[i].namelen;
370	memmove( (char *) &tmp[2], altservers[i].name, altservers[i].namelen);
371	(void) WriteToClient(client, altservers[i].namelen + 2, tmp);
372    }
373
374    if (auth_len)
375	(void) WriteToClient(client, auth_len, (char *) server_auth_data);
376
377    if (auth_accept != AuthSuccess) {
378	nClients--;
379	return (client->noClientException = -2);
380    }
381    client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
382    client->sequence = 0;
383    if (client->swapped)
384	(void) WriteSConnectionInfo(client, ConnInfoLen, ConnectionInfo);
385    else
386	(void) WriteToClient(client, ConnInfoLen, ConnectionInfo);
387
388#ifdef DEBUG
389    fprintf(stderr, "Establishing new connection\n");
390#endif
391
392    return client->noClientException;
393}
394
395/*
396 * NOTE -- the incoming data may be mangled
397 */
398
399void
400DoSendErrToClient(
401    ClientPtr   client,
402    int         error,
403    pointer     data)		/* resource id, format, resolution, etc */
404{
405    fsError     rep;
406    int         extralen = 0;
407
408    switch (error) {
409    case FSBadFormat:
410	extralen = SIZEOF(fsBitmapFormat);
411	break;
412    case FSBadFont:
413    case FSBadAccessContext:
414    case FSBadIDChoice:
415    case FSBadEventMask:
416	if (data) {
417	    if (client->swapped)
418	        SwapLongs((long *) data, 1);
419	    extralen = 4;
420	}
421	break;
422    case FSBadRange:
423	extralen = SIZEOF(fsRange);
424	break;
425    case FSBadResolution:
426	if (data) {
427	    if (client->swapped)
428	        SwapShorts((short *) data, 1);
429	    /* note sneaky hack */
430	    rep.pad = *(CARD16 *) data;
431	    data = (char *)data + 2;
432	    extralen = 4;
433	}
434	break;
435    case FSBadLength:
436	if (data) {
437	    if (client->swapped)
438	        SwapLongs((long *) data, 1);
439	    extralen = 4;
440	}
441	break;
442    default:
443	/* nothing else to send */
444	break;
445    }
446
447    rep.type = FS_Error;
448    rep.sequenceNumber = client->sequence;
449    rep.request = error;
450    rep.major_opcode = ((fsReq *) client->requestBuffer)->reqType;
451    rep.minor_opcode = MinorOpcodeOfRequest(client),
452	rep.timestamp = GetTimeInMillis();
453    rep.length = (SIZEOF(fsError) + extralen) >> 2;
454
455    WriteErrorToClient(client, &rep);
456
457    if (extralen)
458	WriteToClient(client, extralen, (char *) data);
459}
460
461/* ARGSUSED */
462int
463ProcBadRequest(ClientPtr client)
464{
465    SendErrToClient(client, FSBadRequest, NULL);
466    return FSBadRequest;
467}
468
469int
470ProcNoop(ClientPtr client)
471{
472    REQUEST(fsReq);
473    REQUEST_AT_LEAST_SIZE(fsReq);
474
475    return client->noClientException;
476}
477
478int
479ProcListCatalogues(ClientPtr client)
480{
481    int         len,
482                num;
483    char       *catalogues;
484    fsListCataloguesReply rep;
485
486    REQUEST(fsListCataloguesReq);
487    REQUEST_AT_LEAST_SIZE(fsListCataloguesReq);
488
489    num = ListCatalogues((char *)stuff + SIZEOF(fsListCataloguesReq),
490			 stuff->nbytes, stuff->maxNames,
491			 &catalogues, &len);
492    rep.type = FS_Reply;
493    rep.num_replies = 0;
494    rep.num_catalogues = num;
495    rep.sequenceNumber = client->sequence;
496    rep.length = (SIZEOF(fsListCataloguesReply) + len + 3) >> 2;
497
498    WriteReplyToClient(client, SIZEOF(fsListCataloguesReply), &rep);
499    (void) WriteToClient(client, len, (char *) catalogues);
500    fsfree((char *) catalogues);
501    return client->noClientException;
502}
503
504int
505ProcSetCatalogues(ClientPtr client)
506{
507    char       *new_cat;
508    int         err,
509                len;
510    int         num;
511
512    REQUEST(fsSetCataloguesReq);
513    REQUEST_AT_LEAST_SIZE(fsSetCataloguesReq);
514
515    if (stuff->num_catalogues == 0) {
516	/* use the default */
517	num = ListCatalogues("*", 1, 10000, &new_cat, &len);
518    } else {
519	num = stuff->num_catalogues;
520	err = ValidateCatalogues(&num, (char *)stuff + SIZEOF(fsSetCataloguesReq));
521	if (err == FSSuccess) {
522	    len = (stuff->length << 2) - SIZEOF(fsSetCataloguesReq);
523	    new_cat = (char *) fsalloc(len);
524	    if (!new_cat)
525		return FSBadAlloc;
526	    memmove( new_cat, (char *)stuff + SIZEOF(fsSetCataloguesReq), len);
527	} else {
528	    SendErrToClient(client, err, (pointer) &num);
529	    return err;
530	}
531    }
532    if (client->catalogues)
533	fsfree((char *) client->catalogues);
534    client->catalogues = new_cat;
535    client->num_catalogues = num;
536    return client->noClientException;
537}
538
539int
540ProcGetCatalogues(ClientPtr client)
541{
542    int         len,
543                i,
544                size;
545    char       *cp;
546    fsGetCataloguesReply rep;
547
548    REQUEST(fsGetCataloguesReq);
549    REQUEST_AT_LEAST_SIZE(fsGetCataloguesReq);
550
551    for (i = 0, len = 0, cp = client->catalogues;
552	    i < client->num_catalogues; i++) {
553	size = *cp++;
554	len += size + 1;	/* str length + size byte */
555	cp += size;
556    }
557
558    rep.type = FS_Reply;
559    rep.num_catalogues = client->num_catalogues;
560    rep.sequenceNumber = client->sequence;
561    rep.length = (SIZEOF(fsGetCataloguesReply) + len + 3) >> 2;
562
563    WriteReplyToClient(client, SIZEOF(fsGetCataloguesReply), &rep);
564    (void) WriteToClient(client, len, client->catalogues);
565
566    return client->noClientException;
567}
568
569int
570ProcCreateAC(ClientPtr client)
571{
572    fsCreateACReply rep;
573    AuthPtr     acp;
574    AuthContextPtr authp;
575    int         accept,
576                i,
577                err,
578                index,
579                size;
580    char       *ad;
581    char       *auth_data;
582
583    REQUEST(fsCreateACReq);
584    REQUEST_AT_LEAST_SIZE(fsCreateACReq);
585
586    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->acid,
587					    RT_AUTHCONT);
588    if (authp) {
589	int aligned_acid = stuff->acid;
590	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_acid);
591	return FSBadIDChoice;
592    }
593    acp = 0;
594    if (stuff->num_auths)
595    {
596    	acp = (AuthPtr) ALLOCATE_LOCAL(stuff->num_auths * sizeof(AuthRec));
597    	if (!acp) {
598	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
599	    return FSBadAlloc;
600    	}
601    }
602    /* build up a list of the stuff */
603    for (i = 0, ad = (char *)stuff + SIZEOF(fsCreateACReq);
604         i < (int)stuff->num_auths; i++) {
605	if (ad - (char *)stuff + SIZEOF(fsCreateACReq) >
606	    (stuff->length << 2) - 4) {
607	    int lengthword = stuff->length;
608
609	    SendErrToClient(client, FSBadLength, (pointer)&lengthword);
610	    return (FSBadLength);
611	}
612	/* copy carefully in case data is not aligned */
613	acp[i].namelen = (((unsigned char *)ad)[0] << 8) +
614			 ((unsigned char *)ad)[1];
615	ad += 2;
616	acp[i].datalen = (((unsigned char *)ad)[0] << 8) +
617			 ((unsigned char *)ad)[1];
618	ad += 2;
619	acp[i].name = (char *) ad;
620	ad += acp[i].namelen;
621	acp[i].data = (char *) ad;
622	ad += acp[i].datalen;
623    }
624    if (!(int)stuff->num_auths)
625	ad += 4;
626    if (ad - (char *)stuff > (stuff->length << 2)) {
627	int lengthword = stuff->length;
628
629	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
630	return (FSBadLength);
631    }
632
633/* XXX needs work for AuthContinue */
634    index = stuff->num_auths;
635    err = CheckClientAuthorization(client, acp, &accept, &index, &size,
636				   &auth_data);
637
638    if (err != FSSuccess) {
639	SendErrToClient(client, err, (pointer) 0);
640	if (acp)
641	    DEALLOCATE_LOCAL(acp);
642	return err;
643    }
644    authp = (AuthContextPtr) fsalloc(sizeof(AuthContextRec));
645    if (!authp) {
646	goto alloc_failure;
647    }
648    authp->authname = 0;
649    authp->authdata = 0;
650    if (index > 0)
651    {
652	authp->authname = (char *) fsalloc(acp[index - 1].namelen + 1);
653	authp->authdata = (char *) fsalloc(acp[index - 1].datalen + 1);
654	if (!authp->authname || !authp->authdata) {
655	    fsfree((char *) authp->authname);
656	    fsfree((char *) authp->authdata);
657	    fsfree((char *) authp);
658	    goto alloc_failure;
659	}
660	memmove( authp->authname, acp[index - 1].name, acp[index - 1].namelen);
661	memmove( authp->authdata, acp[index - 1].data, acp[index - 1].datalen);
662    }
663    else
664	size = 0;
665    authp->acid = stuff->acid;
666    if (!AddResource(client->index, stuff->acid, RT_AUTHCONT,(pointer) authp))
667    {
668alloc_failure:
669	SendErrToClient(client, FSBadAlloc, (pointer) 0);
670	if (acp)
671	    DEALLOCATE_LOCAL(acp);
672	return FSBadAlloc;
673    }
674    DEALLOCATE_LOCAL(acp);
675    rep.type = FS_Reply;
676    rep.status = accept;
677    rep.auth_index = index;
678    rep.sequenceNumber = client->sequence;
679    rep.length = (SIZEOF(fsCreateACReply) + size) >> 2;
680
681    WriteReplyToClient(client, SIZEOF(fsCreateACReply), &rep);
682    if (size)
683	(void) WriteToClient(client, size, auth_data);
684
685    return client->noClientException;
686}
687
688/* ARGSUSED */
689int
690DeleteAuthCont (pointer value, FSID id)
691{
692    AuthContextPtr  authp = (AuthContextPtr) value;
693
694    if (authp->authname)
695	fsfree (authp->authname);
696    if (authp->authdata)
697	fsfree (authp->authdata);
698    fsfree (authp);
699    return 1;
700}
701
702int
703ProcFreeAC(ClientPtr client)
704{
705    AuthContextPtr authp;
706
707    REQUEST(fsFreeACReq);
708    REQUEST_AT_LEAST_SIZE(fsFreeACReq);
709    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
710					  RT_AUTHCONT);
711    if (!authp) {
712	int aligned_id = stuff->id;
713	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
714	return FSBadIDChoice;
715    }
716    if (client->auth == authp)
717	client->auth = client->default_auth;
718    FreeResource(client->index, stuff->id, RT_NONE);
719    return client->noClientException;
720}
721
722int
723ProcSetAuthorization(ClientPtr client)
724{
725    AuthContextPtr acp;
726
727    REQUEST(fsSetAuthorizationReq);
728    REQUEST_AT_LEAST_SIZE(fsSetAuthorizationReq);
729    acp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
730					  RT_AUTHCONT);
731    if (!acp) {
732	int aligned_id = stuff->id;
733	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
734	return FSBadIDChoice;
735    }
736    client->auth = acp;		/* XXX does this need a refcount? */
737    return client->noClientException;
738}
739
740int
741ProcSetResolution(ClientPtr client)
742{
743    fsResolution *new_res;
744
745    REQUEST(fsSetResolutionReq);
746    REQUEST_AT_LEAST_SIZE(fsSetResolutionReq);
747
748    if ((stuff->length << 2) - SIZEOF(fsSetResolutionReq) <
749        stuff->num_resolutions * SIZEOF(fsResolution)) {
750	int lengthword = stuff->length;
751
752	SendErrToClient(client, FSBadLength, &lengthword);
753	return FSBadLength;
754    }
755    new_res = (fsResolution *)
756	fsalloc(SIZEOF(fsResolution) * stuff->num_resolutions);
757    if (!new_res) {
758	SendErrToClient(client, FSBadAlloc, NULL);
759	return FSBadAlloc;
760    }
761    fsfree((char *) client->resolutions);
762    memmove( (char *) new_res, (char *)stuff + SIZEOF(fsSetResolutionReq),
763	  (stuff->num_resolutions * SIZEOF(fsResolution)));
764    client->resolutions = new_res;
765    client->num_resolutions = stuff->num_resolutions;
766
767    return client->noClientException;
768}
769
770int
771ProcGetResolution(ClientPtr client)
772{
773    fsGetResolutionReply reply;
774
775    REQUEST(fsReq);
776    REQUEST_AT_LEAST_SIZE(fsReq);
777
778    if ((stuff->length << 2) - SIZEOF(fsResolution) < client->num_resolutions *
779	sizeof(fsResolution)) {
780	int lengthword = stuff->length;
781
782	SendErrToClient(client, FSBadLength, &lengthword);
783	return FSBadLength;
784    }
785    reply.type = FS_Reply;
786    reply.num_resolutions = client->num_resolutions;
787    reply.sequenceNumber = client->sequence;
788    reply.length = (SIZEOF(fsGetResolutionReply) +
789		    client->num_resolutions * SIZEOF(fsResolution)) >> 2;
790
791    WriteReplyToClient(client, SIZEOF(fsGetResolutionReply), &reply);
792    if (client->swapped)
793	client->pSwapReplyFunc = CopySwap16Write;
794
795    WriteSwappedDataToClient(client,
796       (client->num_resolutions * SIZEOF(fsResolution)), (short *)client->resolutions);
797
798    return client->noClientException;
799}
800
801int
802ProcListFonts(ClientPtr client)
803{
804    REQUEST(fsListFontsReq);
805    REQUEST_FIXED_SIZE(fsListFontsReq, stuff->nbytes);
806
807    return ListFonts(client, stuff->nbytes,
808		     (unsigned char *)stuff + SIZEOF(fsListFontsReq),
809		     stuff->maxNames);
810}
811
812int
813ProcListFontsWithXInfo(ClientPtr client)
814{
815    REQUEST(fsListFontsWithXInfoReq);
816    REQUEST_FIXED_SIZE(fsListFontsWithXInfoReq, stuff->nbytes);
817
818    return StartListFontsWithInfo(client, stuff->nbytes,
819				  (unsigned char *)stuff + SIZEOF(fsListFontsWithXInfoReq), stuff->maxNames);
820}
821
822int
823ProcOpenBitmapFont(ClientPtr client)
824{
825    FontPtr     pfont;
826    int         nbytes,
827                err;
828    unsigned char *fname;
829
830    REQUEST(fsOpenBitmapFontReq);
831    fname = (unsigned char *)stuff + SIZEOF(fsOpenBitmapFontReq);
832    nbytes = *fname++;
833
834    REQUEST_FIXED_SIZE(fsOpenBitmapFontReq, (nbytes + 1));
835
836    pfont = (FontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
837    if (pfont) {
838	int aligned_fid = stuff->fid;
839	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_fid);
840	return FSBadIDChoice;
841    }
842    if (stuff->format_hint != 0 &&
843	    stuff->format_hint & ~ALL_FORMAT_BITS) {
844	int aligned_format_hint = stuff->format_hint;
845	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_hint);
846	return FSBadFormat;
847    }
848    if (stuff->format_mask & ~ALL_FORMAT_MASK_BITS) {
849	int aligned_format_mask = stuff->format_mask;
850	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_mask);
851	return FSBadFormat;
852    }
853    err = OpenFont(client, stuff->fid, stuff->format_hint, stuff->format_mask,
854		   nbytes, (char *) fname);
855
856    if (err == FSSuccess) {
857	return client->noClientException;
858    } else {
859	return err;
860    }
861}
862
863int
864ProcQueryXInfo(ClientPtr client)
865{
866    ClientFontPtr cfp;
867    int         err,
868                lendata;
869    fsQueryXInfoReply reply;
870    fsPropInfo *prop_info;
871
872    REQUEST(fsQueryXInfoReq);
873
874    REQUEST_AT_LEAST_SIZE(fsQueryXInfoReq);
875
876    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
877    if (!cfp) {
878	int aligned_id = stuff->id;
879	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
880	return FSBadFont;
881    }
882    reply.type = FS_Reply;
883    reply.sequenceNumber = client->sequence;
884
885    /* get the header */
886    fsPack_XFontInfoHeader(&cfp->font->info, &reply, client->major_version);
887    err = convert_props(&cfp->font->info, &prop_info);
888
889    switch (err)
890    {
891    case Successful:
892	break;
893    case AllocError:
894	SendErrToClient(client, FSBadAlloc, (pointer) 0);
895	return err;
896    default:
897	ErrorF("ProcQueryXInfo: unexpected return val %d from convert_props\n",
898	       err);
899	SendErrToClient(client, FSBadImplementation, (pointer) 0);
900	return err;
901    }
902    lendata = SIZEOF(fsPropInfo) +
903	prop_info->num_offsets * SIZEOF(fsPropOffset) +
904	prop_info->data_len;
905
906    reply.length = (SIZEOF(fsQueryXInfoReply) + lendata + 3) >> 2;
907    WriteReplyToClient(client, SIZEOF(fsQueryXInfoReply), &reply);
908
909    if (client->swapped)
910	SwapPropInfo(prop_info);
911    (void) WriteToClient(client, lendata, (char *) prop_info);
912
913    fsfree((char *) prop_info);
914    return client->noClientException;
915}
916
917int
918ProcQueryXExtents(ClientPtr client)
919{
920    ClientFontPtr cfp;
921    int         err;
922    int         item_size;
923
924    REQUEST(fsQueryXExtents8Req);
925
926    REQUEST_AT_LEAST_SIZE(fsQueryXExtents8Req);
927
928    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
929    if (!cfp) {
930	int aligned_fid = stuff->fid;
931	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
932	return FSBadFont;
933    }
934    item_size = (stuff->reqType == FS_QueryXExtents8) ? 1 : 2;
935
936    if (stuff->num_ranges >
937	 ((stuff->length << 2) - SIZEOF(fsQueryXExtents8Req))/item_size) {
938	int num_ranges = stuff->num_ranges;
939	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
940	return FSBadLength;
941    }
942
943    /* get the extents */
944    err = QueryExtents(client, cfp, item_size,
945		       stuff->num_ranges, stuff->range,
946		       (char *)stuff + SIZEOF(fsQueryXExtents8Req));
947
948    if (err != FSSuccess) {
949	return err;
950    } else
951	return client->noClientException;
952}
953
954int
955ProcQueryXBitmaps(ClientPtr client)
956{
957    ClientFontPtr cfp;
958    int         err;
959    int         item_size;
960
961    REQUEST(fsQueryXBitmaps8Req);
962
963    REQUEST_AT_LEAST_SIZE(fsQueryXBitmaps8Req);
964
965    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
966    if (!cfp) {
967	int aligned_fid = stuff->fid;
968	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
969	return FSBadFont;
970    }
971    if (stuff->format & ~ALL_FORMAT_BITS) {
972	int aligned_format = stuff->format;
973	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format);
974	return FSBadFormat;
975    }
976    assert((stuff->reqType == FS_QueryXBitmaps8) || (stuff->reqType == FS_QueryXBitmaps16));
977    item_size = (stuff->reqType == FS_QueryXBitmaps8) ? 1 : 2;
978
979    if (stuff->num_ranges >
980	((stuff->length << 2) - SIZEOF(fsQueryXBitmaps8Req))/item_size) {
981	int num_ranges = stuff->num_ranges;
982	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
983	return FSBadLength;
984    }
985    /* get the glyphs */
986    err = QueryBitmaps(client, cfp, item_size, stuff->format,
987		       stuff->num_ranges, stuff->range,
988		       (char *)stuff + SIZEOF(fsQueryXBitmaps8Req));
989
990    if (err != FSSuccess) {
991	return err;
992    } else {
993	return client->noClientException;
994    }
995}
996
997int
998ProcCloseFont(ClientPtr client)
999{
1000    ClientFontPtr cfp;
1001
1002    REQUEST(fsResourceReq);
1003
1004    REQUEST_SIZE_MATCH(fsResourceReq);
1005    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
1006    if (cfp) {
1007	FreeResource(client->index, stuff->id, RT_NONE);
1008	return client->noClientException;
1009    } else {
1010	int aligned_id = stuff->id;
1011	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
1012	return FSBadFont;
1013    }
1014}
1015
1016void
1017DoCloseDownClient(ClientPtr client)
1018{
1019    if (client->clientGone != CLIENT_GONE) {
1020	DeleteClientFontStuff(client);
1021	client->clientGone = CLIENT_GONE;
1022	CloseDownConnection(client);
1023	--nClients;
1024    }
1025
1026    if (ClientIsAsleep(client))
1027	ClientSignal((pointer)client);
1028    else
1029    {
1030	FreeClientResources(client);
1031	if (client->index < nextFreeClientID)
1032	    nextFreeClientID = client->index;
1033	clients[client->index] = NullClient;
1034#ifdef DebugConnectionTranslation
1035	CheckFileNumbers();
1036#endif /* DebugConnectionTranslation */
1037
1038#ifdef NOTYET
1039	/* reset server when last client goes away */
1040	if (client->requestVector != InitialVector && nClients == 0)
1041	    dispatchException |= DE_RESET;
1042#endif
1043
1044	if (currentClient == client)
1045	    currentClient = serverClient;
1046	fsfree(client);
1047
1048#ifdef DEBUG
1049	fprintf(stderr, "Shut down client\n");
1050#endif
1051
1052	while (!clients[currentMaxClients - 1])
1053	    currentMaxClients--;
1054    }
1055}
1056
1057static void
1058kill_all_clients(void)
1059{
1060    int         i;
1061
1062    for (i = MINCLIENT; i < currentMaxClients; i++) {
1063	if (clients[i])
1064	    CloseDownClient(clients[i]);
1065    }
1066}
1067
1068void
1069InitProcVectors(void)
1070{
1071    int         i;
1072
1073    for (i = 0; i < NUM_PROC_VECTORS; i++) {
1074	if (!ProcVector[i]) {
1075	    ProcVector[i] = SwappedProcVector[i] = ProcBadRequest;
1076	    ReplySwapVector[i] = (ReplySwapFunc)NotImplemented;
1077	}
1078    }
1079    for (i = FSLASTEvent; i < NUM_EVENT_VECTORS; i++) {
1080	EventSwapVector[i] = (EventSwapFunc)NotImplemented;
1081    }
1082}
1083
1084void
1085InitClient(
1086    ClientPtr   client,
1087    int         i,
1088    pointer     ospriv)
1089{
1090    client->index = i;
1091    client->sequence = 0;
1092    client->last_request_time = GetTimeInMillis();
1093    client->clientGone = CLIENT_ALIVE;
1094    client->noClientException = FSSuccess;
1095    client->requestVector = InitialVector;
1096    client->osPrivate = ospriv;
1097    client->swapped = FALSE;
1098
1099    client->auth = (AuthContextPtr) 0;
1100    client->catalogues = NULL;
1101    client->num_catalogues = 0;
1102    client->num_resolutions = 0;
1103    client->resolutions = (fsResolution *) 0;
1104    client->eventmask = (Mask) 0;
1105}
1106
1107ClientPtr
1108NextAvailableClient(pointer ospriv)
1109{
1110    int         i;
1111    ClientPtr   client;
1112    fsFakeReq   data;
1113
1114    i = nextFreeClientID;
1115    if (i == MaxClients)
1116	return NullClient;
1117
1118    clients[i] = client = (ClientPtr) fsalloc(sizeof(ClientRec));
1119    if (!client)
1120	return NullClient;
1121
1122    InitClient(client, i, ospriv);
1123
1124    if (!InitClientResources(client)) {
1125	fsfree(client);
1126	return NullClient;
1127    }
1128    data.reqType = 1;
1129    data.length = (sizeof(fsFakeReq) + SIZEOF(fsConnClientPrefix)) >> 2;
1130    if (!InsertFakeRequest(client, (char *) &data, sizeof(fsFakeReq))) {
1131	FreeClientResources(client);
1132	fsfree(client);
1133	return NullClient;
1134    }
1135    if (i == currentMaxClients)
1136	currentMaxClients++;
1137    while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
1138	nextFreeClientID++;
1139
1140    /* if we've maxed out, try to clone */
1141    if (nextFreeClientID == MaxClients) {
1142	CloneMyself();
1143    }
1144    return client;
1145}
1146
1147void
1148MarkClientException(ClientPtr client)
1149{
1150    client->noClientException = -2;
1151}
1152