1 /*
2 
3 Copyright 1990, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 
25 */
26 
27 /*
28  * Copyright 1990 Network Computing Devices
29  *
30  * Permission to use, copy, modify, distribute, and sell this software and
31  * its documentation for any purpose is hereby granted without fee, provided
32  * that the above copyright notice appear in all copies and that both that
33  * copyright notice and this permission notice appear in supporting
34  * documentation, and that the names of Network Computing Devices, or Digital
35  * not be used in advertising or publicity pertaining to distribution
36  * of the software without specific, written prior permission.
37  *
38  * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
39  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
40  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
41  * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
42  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
43  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
44  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
45  * THIS SOFTWARE.
46  *
47  * Author:  	Dave Lemke, Network Computing Devices, Inc
48  */
49 /*
50  * font server specific font access
51  */
52 
53 #ifdef HAVE_CONFIG_H
54 #include <config.h>
55 #endif
56 
57 #ifdef WIN32
58 #define _WILLWINSOCK_
59 #endif
60 #define FONT_t
61 #define TRANS_CLIENT
62 #include	"X11/Xtrans/Xtrans.h"
63 #include	"X11/Xpoll.h"
64 #include	<X11/fonts/FS.h>
65 #include	<X11/fonts/FSproto.h>
66 #include	<X11/X.h>
67 #include	<X11/Xos.h>
68 #include	<X11/fonts/fontmisc.h>
69 #include	<X11/fonts/fontstruct.h>
70 #include	"fservestr.h"
71 #include	<X11/fonts/fontutil.h>
72 #include	<errno.h>
73 #include	<limits.h>
74 
75 #include	<time.h>
76 #define Time_t time_t
77 
78 #ifdef NCD
79 #include	<ncd/nvram.h>
80 #endif
81 
82 #include <stddef.h>
83 
84 #ifndef MIN
85 #define MIN(a,b)    ((a)<(b)?(a):(b))
86 #endif
87 #define TimeCmp(a,c,b)	((int) ((a) - (b)) c 0)
88 
89 #define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
90 			     (pci)->rightSideBearing || \
91 			     (pci)->ascent || \
92 			     (pci)->descent || \
93 			     (pci)->characterWidth)
94 
95 /*
96  * SIZEOF(r) is in bytes, length fields in the protocol are in 32-bit words,
97  * so this converts for doing size comparisons.
98  */
99 #define LENGTHOF(r)	(SIZEOF(r) >> 2)
100 
101 /* Somewhat arbitrary limit on maximum reply size we'll try to read. */
102 #define MAX_REPLY_LENGTH	((64 * 1024 * 1024) >> 2)
103 
104 extern void ErrorF(const char *f, ...);
105 
106 static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
107 static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
108 static int fs_read_list_info ( FontPathElementPtr fpe,
109 			       FSBlockDataPtr blockrec );
110 
111 extern fd_set _fs_fd_mask;
112 
113 static void fs_block_handler ( pointer data, OSTimePtr wt,
114 			       pointer LastSelectMask );
115 static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
116 
117 /*
118  * List of all FPEs
119  */
120 static FSFpePtr fs_fpes;
121 /*
122  * Union of all FPE blockStates
123  */
124 static CARD32	fs_blockState;
125 
126 static int _fs_restart_connection ( FSFpePtr conn );
127 static void fs_send_query_bitmaps ( FontPathElementPtr fpe,
128 				   FSBlockDataPtr blockrec );
129 static int fs_send_close_font ( FontPathElementPtr fpe, Font id );
130 static void fs_client_died ( pointer client, FontPathElementPtr fpe );
131 static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
132 static void _fs_client_resolution ( FSFpePtr conn );
133 static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
134 static int fs_await_reply (FSFpePtr conn);
135 static void _fs_do_blocked (FSFpePtr conn);
136 static void fs_cleanup_bfont (FSBlockedFontPtr bfont);
137 
138 char _fs_glyph_undefined;
139 char _fs_glyph_requested;
140 static char _fs_glyph_zero_length;
141 
142 static int  generationCount;
143 
144 static int FontServerRequestTimeout = 30 * 1000;
145 
146 static void
147 _fs_close_server (FSFpePtr conn);
148 
149 static FSFpePtr
150 _fs_init_conn (const char *servername);
151 
152 static int
153 _fs_wait_connect (FSFpePtr conn);
154 
155 static int
156 _fs_send_init_packets (FSFpePtr conn);
157 
158 static void
159 _fs_check_reconnect (FSFpePtr conn);
160 
161 static void
162 _fs_start_reconnect (FSFpePtr conn);
163 
164 static void
165 _fs_free_conn (FSFpePtr conn);
166 
167 static int
168 fs_free_fpe(FontPathElementPtr fpe);
169 
170 /*
171  * Font server access
172  *
173  * the basic idea for the non-blocking access is to have the function
174  * called multiple times until the actual data is returned, instead
175  * of ClientBlocked.
176  *
177  * the first call to the function will cause the request to be sent to
178  * the font server, and a block record to be stored in the fpe's list
179  * of outstanding requests.  the FS block handler also sticks the
180  * proper set of fd's into the select mask.  when data is ready to be
181  * read in, the FS wakup handler will be hit.  this will read the
182  * data off the wire into the proper block record, and then signal the
183  * client that caused the block so that it can restart.  it will then
184  * call the access function again, which will realize that the data has
185  * arrived and return it.
186  */
187 
188 
189 #ifdef DEBUG
190 static void
_fs_add_req_log(FSFpePtr conn,int opcode)191 _fs_add_req_log(FSFpePtr conn, int opcode)
192 {
193     conn->current_seq++;
194     fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
195 	     conn->current_seq, opcode);
196     conn->reqbuffer[conn->reqindex].opcode = opcode;
197     conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
198     conn->reqindex++;
199     if (conn->reqindex == REQUEST_LOG_SIZE)
200 	conn->reqindex = 0;
201 }
202 
203 static void
_fs_add_rep_log(FSFpePtr conn,fsGenericReply * rep)204 _fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
205 {
206     int	    i;
207 
208     for (i = 0; i < REQUEST_LOG_SIZE; i++)
209 	if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
210 	    break;
211     if (i == REQUEST_LOG_SIZE)
212 	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: unknown\n",
213 		 rep->sequenceNumber);
214     else
215 	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: %d\n",
216 		 rep->sequenceNumber,
217 		 conn->reqbuffer[i].opcode);
218 }
219 
220 #define _fs_reply_failed(rep, name, op) do {                            \
221     if (rep) {                                                          \
222         if (rep->type == FS_Error)                                      \
223             fprintf (stderr, "Error: %d Request: %s\n",                 \
224                      ((fsError *)rep)->request, #name);                 \
225         else                                                            \
226             fprintf (stderr, "Bad Length for %s Reply: %d %s %d\n",     \
227                      #name, rep->length, op, LENGTHOF(name));           \
228     }                                                                   \
229 } while (0)
230 
231 #else
232 #define _fs_add_req_log(conn,op)    ((conn)->current_seq++)
233 #define _fs_add_rep_log(conn,rep)
234 #define _fs_reply_failed(rep,name,op)
235 #endif
236 
237 static Bool
fs_name_check(const char * name)238 fs_name_check(const char *name)
239 {
240     /* Just make sure there is a protocol/ prefix */
241     return (name && *name != '/' && strchr(name, '/'));
242 }
243 
244 static void
_fs_client_resolution(FSFpePtr conn)245 _fs_client_resolution(FSFpePtr conn)
246 {
247     fsSetResolutionReq srreq;
248     int         num_res;
249     FontResolutionPtr res;
250 
251     res = GetClientResolutions(&num_res);
252 
253     if (num_res) {
254 	srreq.reqType = FS_SetResolution;
255 	srreq.num_resolutions = num_res;
256 	srreq.length = (SIZEOF(fsSetResolutionReq) +
257 			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
258 
259 	_fs_add_req_log(conn, FS_SetResolution);
260 	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
261 	    (void)_fs_write_pad(conn, (char *) res,
262 				(num_res * SIZEOF(fsResolution)));
263     }
264 }
265 
266 /*
267  * close font server and remove any state associated with
268  * this connection - this includes any client records.
269  */
270 
271 static void
fs_close_conn(FSFpePtr conn)272 fs_close_conn(FSFpePtr conn)
273 {
274     FSClientPtr	client, nclient;
275 
276     _fs_close_server (conn);
277 
278     for (client = conn->clients; client; client = nclient)
279     {
280 	nclient = client->next;
281 	free (client);
282     }
283     conn->clients = NULL;
284 }
285 
286 /*
287  * the wakeup handlers have to be set when the FPE is open, and not
288  * removed until it is freed, in order to handle unexpected data, like
289  * events
290  */
291 /* ARGSUSED */
292 static int
fs_init_fpe(FontPathElementPtr fpe)293 fs_init_fpe(FontPathElementPtr fpe)
294 {
295     FSFpePtr    conn;
296     const char  *name;
297     int         err;
298     int		ret;
299 
300     /* open font server */
301     /* create FS specific fpe info */
302     name = fpe->name;
303 
304     /* hack for old style names */
305     if (*name == ':')
306 	name++;			/* skip ':' */
307 
308     conn = _fs_init_conn (name);
309     if (!conn)
310 	err = AllocError;
311     else
312     {
313 	err = init_fs_handlers (fpe, fs_block_handler);
314 	if (err != Successful)
315 	{
316 	    _fs_free_conn (conn);
317 	    err = AllocError;
318 	}
319 	else
320 	{
321 	    fpe->private = conn;
322 	    conn->next = fs_fpes;
323 	    fs_fpes = conn;
324 	    ret = _fs_wait_connect (conn);
325 	    if (ret != FSIO_READY)
326 	    {
327 		fs_free_fpe (fpe);
328 		err = BadFontPath;
329 	    }
330 	    else
331 		err = Successful;
332 	}
333     }
334 
335     if (err == Successful)
336     {
337 #ifdef NCD
338 	if (configData.ExtendedFontDiags)
339 	    printf("Connected to font server \"%s\"\n", name);
340 #endif
341 #ifdef DEBUG
342 	fprintf (stderr, "connected to FS \"%s\"\n", name);
343 #endif
344     }
345     else
346     {
347 #ifdef DEBUG
348 	fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
349 #endif
350 #ifdef NCD
351 	if (configData.ExtendedFontDiags)
352 	    printf("Failed to connect to font server \"%s\"\n", name);
353 #endif
354 	;
355     }
356     return err;
357 }
358 
359 static int
fs_reset_fpe(FontPathElementPtr fpe)360 fs_reset_fpe(FontPathElementPtr fpe)
361 {
362     (void) _fs_send_init_packets((FSFpePtr) fpe->private);
363     return Successful;
364 }
365 
366 /*
367  * this shouldn't be called till all refs to the FPE are gone
368  */
369 
370 static int
fs_free_fpe(FontPathElementPtr fpe)371 fs_free_fpe(FontPathElementPtr fpe)
372 {
373     FSFpePtr    conn = (FSFpePtr) fpe->private, *prev;
374 
375     /* unhook from chain of all font servers */
376     for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
377     {
378 	if (*prev == conn)
379 	{
380 	    *prev = conn->next;
381 	    break;
382 	}
383     }
384     _fs_unmark_block (conn, conn->blockState);
385     fs_close_conn(conn);
386     remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
387     _fs_free_conn (conn);
388     fpe->private = (pointer) 0;
389 
390 #ifdef NCD
391     if (configData.ExtendedFontDiags)
392 	printf("Disconnected from font server \"%s\"\n", fpe->name);
393 #endif
394 #ifdef DEBUG
395     fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
396 #endif
397 
398     return Successful;
399 }
400 
401 static      FSBlockDataPtr
fs_new_block_rec(FontPathElementPtr fpe,pointer client,int type)402 fs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
403 {
404     FSBlockDataPtr blockrec,
405                 *prev;
406     FSFpePtr    conn = (FSFpePtr) fpe->private;
407     int         size;
408 
409     switch (type) {
410     case FS_OPEN_FONT:
411 	size = sizeof(FSBlockedFontRec);
412 	break;
413     case FS_LOAD_GLYPHS:
414 	size = sizeof(FSBlockedGlyphRec);
415 	break;
416     case FS_LIST_FONTS:
417 	size = sizeof(FSBlockedListRec);
418 	break;
419     case FS_LIST_WITH_INFO:
420 	size = sizeof(FSBlockedListInfoRec);
421 	break;
422     default:
423 	size = 0;
424 	break;
425     }
426     blockrec = malloc(sizeof(FSBlockDataRec) + size);
427     if (!blockrec)
428 	return (FSBlockDataPtr) 0;
429     blockrec->data = (pointer) (blockrec + 1);
430     blockrec->client = client;
431     blockrec->sequenceNumber = -1;
432     blockrec->errcode = StillWorking;
433     blockrec->type = type;
434     blockrec->depending = 0;
435     blockrec->next = (FSBlockDataPtr) 0;
436 
437     /* stick it on the end of the list (since its expected last) */
438     for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
439 	;
440     *prev = blockrec;
441 
442     return blockrec;
443 }
444 
445 static void
_fs_set_pending_reply(FSFpePtr conn)446 _fs_set_pending_reply (FSFpePtr conn)
447 {
448     FSBlockDataPtr  blockrec;
449 
450     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
451 	if (blockrec->errcode == StillWorking)
452 	    break;
453     if (blockrec)
454     {
455 	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
456 	_fs_mark_block (conn, FS_PENDING_REPLY);
457     }
458     else
459 	_fs_unmark_block (conn, FS_PENDING_REPLY);
460 }
461 
462 static void
_fs_remove_block_rec(FSFpePtr conn,FSBlockDataPtr blockrec)463 _fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
464 {
465     FSBlockDataPtr *prev;
466 
467     for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
468 	if (*prev == blockrec)
469 	{
470 	    *prev = blockrec->next;
471 	    break;
472 	}
473     if (blockrec->type == FS_LOAD_GLYPHS)
474     {
475 	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
476 	if (bglyph->num_expected_ranges)
477 	    free(bglyph->expected_ranges);
478     }
479     free(blockrec);
480     _fs_set_pending_reply (conn);
481 }
482 
483 static void
_fs_signal_clients_depending(FSClientsDependingPtr * clients_depending)484 _fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
485 {
486     FSClientsDependingPtr p;
487 
488     while ((p = *clients_depending))
489     {
490 	*clients_depending = p->next;
491 	ClientSignal(p->client);
492 	free(p);
493     }
494 }
495 
496 static int
_fs_add_clients_depending(FSClientsDependingPtr * clients_depending,pointer client)497 _fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
498 {
499     FSClientsDependingPtr   new, cd;
500 
501     for (; (cd = *clients_depending);
502 	 clients_depending = &(*clients_depending)->next)
503     {
504 	if (cd->client == client)
505 	    return Suspended;
506     }
507 
508     new = malloc (sizeof (FSClientsDependingRec));
509     if (!new)
510 	return BadAlloc;
511 
512     new->client = client;
513     new->next = 0;
514     *clients_depending = new;
515     return Suspended;
516 }
517 
518 /*
519  * When a request is aborted due to a font server failure,
520  * signal any depending clients to restart their dependant
521  * requests
522  */
523 static void
_fs_clean_aborted_blockrec(FSFpePtr conn,FSBlockDataPtr blockrec)524 _fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
525 {
526     switch(blockrec->type) {
527     case FS_OPEN_FONT: {
528 	FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
529 
530 	fs_cleanup_bfont (bfont);
531 	_fs_signal_clients_depending(&bfont->clients_depending);
532 	break;
533     }
534     case FS_LOAD_GLYPHS: {
535 	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
536 
537 	_fs_clean_aborted_loadglyphs(bglyph->pfont,
538 				     bglyph->num_expected_ranges,
539 				     bglyph->expected_ranges);
540 	_fs_signal_clients_depending(&bglyph->clients_depending);
541 	break;
542     }
543     case FS_LIST_FONTS:
544 	break;
545     case FS_LIST_WITH_INFO: {
546 	FSBlockedListInfoPtr binfo;
547 	binfo = (FSBlockedListInfoPtr) blockrec->data;
548 	if (binfo->status == FS_LFWI_REPLY)
549 	    FD_SET(conn->fs_fd, &_fs_fd_mask);
550 	_fs_free_props (&binfo->info);
551     }
552     default:
553 	break;
554     }
555 }
556 
557 static void
fs_abort_blockrec(FSFpePtr conn,FSBlockDataPtr blockrec)558 fs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
559 {
560     _fs_clean_aborted_blockrec (conn, blockrec);
561     _fs_remove_block_rec (conn, blockrec);
562 }
563 
564 /*
565  * Tell the font server we've failed to complete an open and
566  * then unload the partially created font
567  */
568 static void
fs_cleanup_bfont(FSBlockedFontPtr bfont)569 fs_cleanup_bfont (FSBlockedFontPtr bfont)
570 {
571     FSFontDataRec *fsd;
572 
573     if (bfont->pfont)
574     {
575 	fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
576 
577 	/* make sure the FS knows we choked on it */
578 	fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
579 
580 	/*
581 	 * Either unload the font if it's being opened for
582 	 * the first time, or smash the generation field to
583 	 * mark this font as an orphan
584 	 */
585 	if (!(bfont->flags & FontReopen))
586 	{
587 	    if (bfont->freeFont)
588 		(*bfont->pfont->unload_font) (bfont->pfont);
589 #ifdef DEBUG
590 	    else
591 		fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
592 #endif
593 	    bfont->pfont = 0;
594 	}
595 	else
596 	    fsd->generation = -1;
597     }
598 }
599 
600 /*
601  * Check to see if a complete reply is waiting
602  */
603 static fsGenericReply *
fs_get_reply(FSFpePtr conn,int * error)604 fs_get_reply (FSFpePtr conn, int *error)
605 {
606     char	    *buf;
607     fsGenericReply  *rep;
608     int		    ret;
609 
610     /* block if the connection is down or paused in lfwi */
611     if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
612     {
613 	*error = FSIO_BLOCK;
614 	return 0;
615     }
616 
617     ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
618     if (ret != FSIO_READY)
619     {
620 	*error = FSIO_BLOCK;
621 	return 0;
622     }
623 
624     rep = (fsGenericReply *) buf;
625 
626     /*
627      * Refuse to accept replies longer than a maximum reasonable length,
628      * before we pass to _fs_start_read, since it will try to resize the
629      * incoming connection buffer to this size.  Also avoids integer overflow
630      * on 32-bit systems.
631      */
632     if (rep->length > MAX_REPLY_LENGTH)
633     {
634 	ErrorF("fserve: reply length %ld > MAX_REPLY_LENGTH, disconnecting"
635 	       " from font server\n", (long)rep->length);
636 	_fs_connection_died (conn);
637 	*error = FSIO_ERROR;
638 	return 0;
639     }
640 
641     ret = _fs_start_read (conn, rep->length << 2, &buf);
642     if (ret != FSIO_READY)
643     {
644 	*error = FSIO_BLOCK;
645 	return 0;
646     }
647 
648     *error = FSIO_READY;
649 
650     return (fsGenericReply *) buf;
651 }
652 
653 static Bool
fs_reply_ready(FSFpePtr conn)654 fs_reply_ready (FSFpePtr conn)
655 {
656     fsGenericReply  *rep;
657 
658     if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
659 	return FALSE;
660     if (fs_data_read (conn) < sizeof (fsGenericReply))
661 	return FALSE;
662     rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
663     if (fs_data_read (conn) < rep->length << 2)
664 	return FALSE;
665     return TRUE;
666 }
667 
668 static void
_fs_pending_reply(FSFpePtr conn)669 _fs_pending_reply (FSFpePtr conn)
670 {
671     if (!(conn->blockState & FS_PENDING_REPLY))
672     {
673 	_fs_mark_block (conn, FS_PENDING_REPLY);
674 	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
675     }
676 }
677 
678 static void
_fs_prepare_for_reply(FSFpePtr conn)679 _fs_prepare_for_reply (FSFpePtr conn)
680 {
681     _fs_pending_reply (conn);
682     _fs_flush (conn);
683 }
684 
685 /*
686  * Block (for a while) awaiting a complete reply
687  */
688 static int
fs_await_reply(FSFpePtr conn)689 fs_await_reply (FSFpePtr conn)
690 {
691     int		    ret;
692 
693     if (conn->blockState & FS_COMPLETE_REPLY)
694 	return FSIO_READY;
695 
696     while (!fs_get_reply (conn, &ret))
697     {
698 	if (ret != FSIO_BLOCK)
699 	    return ret;
700 	if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
701 	{
702 	    _fs_connection_died (conn);
703 	    return FSIO_ERROR;
704 	}
705     }
706     return FSIO_READY;
707 }
708 
709 /*
710  * Process the reply to an OpenBitmapFont request
711  */
712 static int
fs_read_open_font(FontPathElementPtr fpe,FSBlockDataPtr blockrec)713 fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
714 {
715     FSFpePtr		    conn = (FSFpePtr) fpe->private;
716     FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
717     fsOpenBitmapFontReply   *rep;
718     FSBlockDataPtr	    blockOrig;
719     FSBlockedFontPtr	    origBfont;
720     int			    ret;
721 
722     rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
723     if (!rep || rep->type == FS_Error ||
724 	(rep->length != LENGTHOF(fsOpenBitmapFontReply)))
725     {
726 	if (ret == FSIO_BLOCK)
727 	    return StillWorking;
728 	if (rep)
729 	    _fs_done_read (conn, rep->length << 2);
730 	fs_cleanup_bfont (bfont);
731 	_fs_reply_failed (rep, fsOpenBitmapFontReply, "!=");
732 	return BadFontName;
733     }
734 
735     /* If we're not reopening a font and FS detected a duplicate font
736        open request, replace our reference to the new font with a
737        reference to an existing font (possibly one not finished
738        opening).  If this is a reopen, keep the new font reference...
739        it's got the metrics and extents we read when the font was opened
740        before.  This also gives us the freedom to easily close the font
741        if we we decide (in fs_read_query_info()) that we don't like what
742        we got. */
743 
744     if (rep->otherid && !(bfont->flags & FontReopen))
745     {
746 	fs_cleanup_bfont (bfont);
747 
748 	/* Find old font if we're completely done getting it from server. */
749 	bfont->pfont = find_old_font(rep->otherid);
750 	bfont->freeFont = FALSE;
751 	bfont->fontid = rep->otherid;
752 	bfont->state = FS_DONE_REPLY;
753 	/*
754 	 * look for a blocked request to open the same font
755 	 */
756 	for (blockOrig = conn->blockedRequests;
757 		blockOrig;
758 		blockOrig = blockOrig->next)
759 	{
760 	    if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
761 	    {
762 		origBfont = (FSBlockedFontPtr) blockOrig->data;
763 		if (origBfont->fontid == rep->otherid)
764 		{
765 		    blockrec->depending = blockOrig->depending;
766 		    blockOrig->depending = blockrec;
767 		    bfont->state = FS_DEPENDING;
768 		    bfont->pfont = origBfont->pfont;
769 		    break;
770 		}
771 	    }
772 	}
773 	if (bfont->pfont == NULL)
774 	{
775 	    /* XXX - something nasty happened */
776 	    ret = BadFontName;
777 	}
778 	else
779 	    ret = AccessDone;
780     }
781     else
782     {
783 	bfont->pfont->info.cachable = rep->cachable != 0;
784 	bfont->state = FS_INFO_REPLY;
785 	/*
786 	 * Reset the blockrec for the next reply
787 	 */
788 	blockrec->sequenceNumber = bfont->queryInfoSequence;
789 	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
790 	ret = StillWorking;
791     }
792     _fs_done_read (conn, rep->length << 2);
793     return ret;
794 }
795 
796 static Bool
fs_fonts_match(FontInfoPtr pInfo1,FontInfoPtr pInfo2)797 fs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
798 {
799     int	    i;
800 
801     if (pInfo1->firstCol != pInfo2->firstCol ||
802 	pInfo1->lastCol != pInfo2->lastCol ||
803 	pInfo1->firstRow != pInfo2->firstRow ||
804 	pInfo1->lastRow != pInfo2->lastRow ||
805 	pInfo1->defaultCh != pInfo2->defaultCh ||
806 	pInfo1->noOverlap != pInfo2->noOverlap ||
807 	pInfo1->terminalFont != pInfo2->terminalFont ||
808 	pInfo1->constantMetrics != pInfo2->constantMetrics ||
809 	pInfo1->constantWidth != pInfo2->constantWidth ||
810 	pInfo1->inkInside != pInfo2->inkInside ||
811 	pInfo1->inkMetrics != pInfo2->inkMetrics ||
812 	pInfo1->allExist != pInfo2->allExist ||
813 	pInfo1->drawDirection != pInfo2->drawDirection ||
814 	pInfo1->cachable != pInfo2->cachable ||
815 	pInfo1->anamorphic != pInfo2->anamorphic ||
816 	pInfo1->maxOverlap != pInfo2->maxOverlap ||
817 	pInfo1->fontAscent != pInfo2->fontAscent ||
818 	pInfo1->fontDescent != pInfo2->fontDescent ||
819 	pInfo1->nprops != pInfo2->nprops)
820 	return FALSE;
821 
822 #define MATCH(xci1, xci2) \
823     (((xci1).leftSideBearing == (xci2).leftSideBearing) && \
824      ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
825      ((xci1).characterWidth == (xci2).characterWidth) && \
826      ((xci1).ascent == (xci2).ascent) && \
827      ((xci1).descent == (xci2).descent) && \
828      ((xci1).attributes == (xci2).attributes))
829 
830     if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
831 	!MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
832 	!MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
833 	!MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
834 	return FALSE;
835 
836 #undef MATCH
837 
838     for (i = 0; i < pInfo1->nprops; i++)
839 	if (pInfo1->isStringProp[i] !=
840 		pInfo2->isStringProp[i] ||
841 	    pInfo1->props[i].name !=
842 		pInfo2->props[i].name ||
843 	    pInfo1->props[i].value !=
844 		pInfo2->props[i].value)
845 	{
846 	    return FALSE;
847 	}
848     return TRUE;
849 }
850 
851 static int
fs_read_query_info(FontPathElementPtr fpe,FSBlockDataPtr blockrec)852 fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
853 {
854     FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
855     FSFpePtr		conn = (FSFpePtr) fpe->private;
856     fsQueryXInfoReply	*rep;
857     char		*buf;
858     long		bufleft; /* length of reply left to use */
859     fsPropInfo		*pi;
860     fsPropOffset	*po;
861     pointer		pd;
862     FontInfoPtr		pInfo;
863     FontInfoRec		tempInfo;
864     int			err;
865     int			ret;
866 
867     rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
868     if (!rep || rep->type == FS_Error ||
869 	(rep->length < LENGTHOF(fsQueryXInfoReply)))
870     {
871 	if (ret == FSIO_BLOCK)
872 	    return StillWorking;
873 	if (rep)
874 	    _fs_done_read (conn, rep->length << 2);
875 	fs_cleanup_bfont (bfont);
876 	_fs_reply_failed (rep, fsQueryXInfoReply, "<");
877 	return BadFontName;
878     }
879 
880     /* If this is a reopen, accumulate the query info into a dummy
881        font and compare to our original data. */
882     if (bfont->flags & FontReopen)
883 	pInfo = &tempInfo;
884     else
885 	pInfo = &bfont->pfont->info;
886 
887     buf = (char *) rep;
888     buf += SIZEOF(fsQueryXInfoReply);
889 
890     bufleft = rep->length << 2;
891     bufleft -= SIZEOF(fsQueryXInfoReply);
892 
893     /* move the data over */
894     fsUnpack_XFontInfoHeader(rep, pInfo);
895 
896     /* compute accelerators */
897     _fs_init_fontinfo(conn, pInfo);
898 
899     /* Compute offsets into the reply */
900     if (bufleft < SIZEOF(fsPropInfo))
901     {
902 	ret = -1;
903 #ifdef DEBUG
904 	fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n",
905 		bufleft);
906 #endif
907 	goto bail;
908     }
909     pi = (fsPropInfo *) buf;
910     buf += SIZEOF (fsPropInfo);
911     bufleft -= SIZEOF(fsPropInfo);
912 
913     if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets)
914     {
915 	ret = -1;
916 #ifdef DEBUG
917 	fprintf(stderr,
918 		"fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %d\n",
919 		bufleft, pi->num_offsets);
920 #endif
921 	goto bail;
922     }
923     po = (fsPropOffset *) buf;
924     buf += pi->num_offsets * SIZEOF(fsPropOffset);
925     bufleft -= pi->num_offsets * SIZEOF(fsPropOffset);
926 
927     if (bufleft < pi->data_len)
928     {
929 	ret = -1;
930 #ifdef DEBUG
931 	fprintf(stderr,
932 		"fsQueryXInfo: bufleft (%ld) < data_len (%d)\n",
933 		bufleft, pi->data_len);
934 #endif
935 	goto bail;
936     }
937     pd = (pointer) buf;
938     buf += pi->data_len;
939     bufleft -= pi->data_len;
940 
941     /* convert the properties and step over the reply */
942     ret = _fs_convert_props(pi, po, pd, pInfo);
943   bail:
944     _fs_done_read (conn, rep->length << 2);
945 
946     if (ret == -1)
947     {
948 	fs_cleanup_bfont (bfont);
949 	return AllocError;
950     }
951 
952     if (bfont->flags & FontReopen)
953     {
954 	/* We're reopening a font that we lost because of a downed
955 	   connection.  In the interest of avoiding corruption from
956 	   opening a different font than the old one (we already have
957 	   its metrics, extents, and probably some of its glyphs),
958 	   verify that the metrics and properties all match.  */
959 
960 	if (fs_fonts_match (pInfo, &bfont->pfont->info))
961 	{
962 	    err = Successful;
963 	    bfont->state = FS_DONE_REPLY;
964 	}
965 	else
966 	{
967 	    fs_cleanup_bfont (bfont);
968 	    err = BadFontName;
969 	}
970 	_fs_free_props (pInfo);
971 
972 	return err;
973     }
974 
975     /*
976      * Ask for terminal format fonts if possible
977      */
978     if (bfont->pfont->info.terminalFont)
979 	bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
980 			 BitmapFormatImageRectMax);
981 
982     /*
983      * Figure out if the whole font should get loaded right now.
984      */
985     if (glyphCachingMode == CACHING_OFF ||
986 	(glyphCachingMode == CACHE_16_BIT_GLYPHS
987 	 && !bfont->pfont->info.lastRow))
988     {
989 	bfont->flags |= FontLoadAll;
990     }
991 
992     /*
993      * Ready to send the query bitmaps; the terminal font bit has
994      * been computed and glyphCaching has been considered
995      */
996     if (bfont->flags & FontLoadBitmaps)
997     {
998 	fs_send_query_bitmaps (fpe, blockrec);
999 	_fs_flush (conn);
1000     }
1001 
1002     bfont->state = FS_EXTENT_REPLY;
1003 
1004     /*
1005      * Reset the blockrec for the next reply
1006      */
1007     blockrec->sequenceNumber = bfont->queryExtentsSequence;
1008     conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
1009 
1010     return StillWorking;
1011 }
1012 
1013 static int
fs_read_extent_info(FontPathElementPtr fpe,FSBlockDataPtr blockrec)1014 fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1015 {
1016     FSFpePtr		    conn = (FSFpePtr) fpe->private;
1017     FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1018     FSFontDataPtr	    fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
1019     FSFontPtr		    fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
1020     fsQueryXExtents16Reply  *rep;
1021     char		    *buf;
1022     int			    i;
1023     int			    numExtents;
1024     int			    numInfos;
1025     int			    ret;
1026     Bool		    haveInk = FALSE; /* need separate ink metrics? */
1027     CharInfoPtr		    ci, pCI;
1028     char		    *fsci;
1029     fsXCharInfo		    fscilocal;
1030     FontInfoRec		    *fi = &bfont->pfont->info;
1031 
1032     rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
1033     if (!rep || rep->type == FS_Error ||
1034 	(rep->length < LENGTHOF(fsQueryXExtents16Reply)))
1035     {
1036 	if (ret == FSIO_BLOCK)
1037 	    return StillWorking;
1038 	if (rep)
1039 	    _fs_done_read (conn, rep->length << 2);
1040 	fs_cleanup_bfont (bfont);
1041 	_fs_reply_failed (rep, fsQueryXExtents16Reply, "<");
1042 	return BadFontName;
1043     }
1044 
1045     /* move the data over */
1046     /* need separate inkMetrics for fixed font server protocol version */
1047     numExtents = rep->num_extents;
1048     numInfos = numExtents;
1049     if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
1050     {
1051 	numInfos *= 2;
1052 	haveInk = TRUE;
1053     }
1054     if (numInfos >= (INT_MAX / sizeof(CharInfoRec))) {
1055 #ifdef DEBUG
1056 	fprintf(stderr,
1057 		"fsQueryXExtents16: numInfos (%d) >= %ld\n",
1058 		numInfos, (INT_MAX / sizeof(CharInfoRec)));
1059 #endif
1060 	pCI = NULL;
1061     }
1062     else if (numExtents > ((rep->length - LENGTHOF(fsQueryXExtents16Reply))
1063 			    / LENGTHOF(fsXCharInfo))) {
1064 #ifdef DEBUG
1065 	fprintf(stderr,
1066 		"fsQueryXExtents16: numExtents (%d) > (%d - %d) / %d\n",
1067 		numExtents, rep->length,
1068 		LENGTHOF(fsQueryXExtents16Reply), LENGTHOF(fsXCharInfo));
1069 #endif
1070 	pCI = NULL;
1071     }
1072     else
1073 	pCI = malloc(sizeof(CharInfoRec) * numInfos);
1074 
1075     if (!pCI)
1076     {
1077 	_fs_done_read (conn, rep->length << 2);
1078 	fs_cleanup_bfont(bfont);
1079 	return AllocError;
1080     }
1081     fsfont->encoding = pCI;
1082     if (haveInk)
1083 	fsfont->inkMetrics = pCI + numExtents;
1084     else
1085         fsfont->inkMetrics = pCI;
1086 
1087     buf = (char *) rep;
1088     buf += SIZEOF (fsQueryXExtents16Reply);
1089     fsci = buf;
1090 
1091     fsd->glyphs_to_get = 0;
1092     ci = fsfont->inkMetrics;
1093     for (i = 0; i < numExtents; i++)
1094     {
1095 	memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
1096 	_fs_convert_char_info(&fscilocal, &ci->metrics);
1097 	/* Bounds check. */
1098 	if (ci->metrics.ascent > fi->maxbounds.ascent)
1099 	{
1100 	    ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
1101 		   fpe->name, fsd->name,
1102 		   ci->metrics.ascent, fi->maxbounds.ascent);
1103 	    ci->metrics.ascent = fi->maxbounds.ascent;
1104 	}
1105 	if (ci->metrics.descent > fi->maxbounds.descent)
1106 	{
1107 	    ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
1108 		   fpe->name, fsd->name,
1109 		   ci->metrics.descent, fi->maxbounds.descent);
1110 	    ci->metrics.descent = fi->maxbounds.descent;
1111 	}
1112 	fsci = fsci + SIZEOF(fsXCharInfo);
1113 	/* Initialize the bits field for later glyph-caching use */
1114 	if (NONZEROMETRICS(&ci->metrics))
1115 	{
1116 	    if (!haveInk &&
1117 		(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
1118 		 ci->metrics.ascent == -ci->metrics.descent))
1119 		pCI[i].bits = &_fs_glyph_zero_length;
1120 	    else
1121 	    {
1122 		pCI[i].bits = &_fs_glyph_undefined;
1123 		fsd->glyphs_to_get++;
1124 	    }
1125 	}
1126 	else
1127 	    pCI[i].bits = (char *)0;
1128 	ci++;
1129     }
1130 
1131     /* Done with reply */
1132     _fs_done_read (conn, rep->length << 2);
1133 
1134     /* build bitmap metrics, ImageRectMax style */
1135     if (haveInk)
1136     {
1137 	CharInfoPtr ii;
1138 
1139 	ci = fsfont->encoding;
1140 	ii = fsfont->inkMetrics;
1141 	for (i = 0; i < numExtents; i++, ci++, ii++)
1142 	{
1143 	    if (NONZEROMETRICS(&ii->metrics))
1144 	    {
1145 		ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
1146 		ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
1147 		ci->metrics.ascent = FONT_MAX_ASCENT(fi);
1148 		ci->metrics.descent = FONT_MAX_DESCENT(fi);
1149 		ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
1150 		ci->metrics.attributes = ii->metrics.attributes;
1151 	    }
1152 	    else
1153 	    {
1154 		ci->metrics = ii->metrics;
1155 	    }
1156 	    /* Bounds check. */
1157 	    if (ci->metrics.ascent > fi->maxbounds.ascent)
1158 	    {
1159 		ErrorF("fserve: warning: %s %s ascent (%d) "
1160 		       "> maxascent (%d)\n",
1161 		       fpe->name, fsd->name,
1162 		       ci->metrics.ascent, fi->maxbounds.ascent);
1163 		ci->metrics.ascent = fi->maxbounds.ascent;
1164 	    }
1165 	    if (ci->metrics.descent > fi->maxbounds.descent)
1166 	    {
1167 		ErrorF("fserve: warning: %s %s descent (%d) "
1168 		       "> maxdescent (%d)\n",
1169 		       fpe->name, fsd->name,
1170 		       ci->metrics.descent, fi->maxbounds.descent);
1171 		ci->metrics.descent = fi->maxbounds.descent;
1172 	    }
1173 	}
1174     }
1175     {
1176 	unsigned int r, c, numCols, firstCol;
1177 
1178 	firstCol = bfont->pfont->info.firstCol;
1179 	numCols = bfont->pfont->info.lastCol - firstCol + 1;
1180 	c = bfont->pfont->info.defaultCh;
1181 	fsfont->pDefault = 0;
1182 	if (bfont->pfont->info.lastRow)
1183 	{
1184 	    r = c >> 8;
1185 	    r -= bfont->pfont->info.firstRow;
1186 	    c &= 0xff;
1187 	    c -= firstCol;
1188 	    if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
1189 		c < numCols)
1190 		fsfont->pDefault = &pCI[r * numCols + c];
1191 	}
1192 	else
1193 	{
1194 	    c -= firstCol;
1195 	    if (c < numCols)
1196 		fsfont->pDefault = &pCI[c];
1197 	}
1198     }
1199     bfont->state = FS_GLYPHS_REPLY;
1200 
1201     if (bfont->flags & FontLoadBitmaps)
1202     {
1203 	/*
1204 	 * Reset the blockrec for the next reply
1205 	 */
1206 	blockrec->sequenceNumber = bfont->queryBitmapsSequence;
1207 	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
1208 	return StillWorking;
1209     }
1210     return Successful;
1211 }
1212 
1213 #ifdef DEBUG
1214 static const char *fs_open_states[] = {
1215     "OPEN_REPLY  ",
1216     "INFO_REPLY  ",
1217     "EXTENT_REPLY",
1218     "GLYPHS_REPLY",
1219     "DONE_REPLY  ",
1220     "DEPENDING   ",
1221 };
1222 #endif
1223 
1224 static int
fs_do_open_font(FontPathElementPtr fpe,FSBlockDataPtr blockrec)1225 fs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1226 {
1227     FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
1228     int			err;
1229 
1230 #ifdef DEBUG
1231     fprintf (stderr, "fs_do_open_font state %s %s\n",
1232 	     fs_open_states[bfont->state],
1233 	     ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
1234 #endif
1235     err = BadFontName;
1236     switch (bfont->state) {
1237     case FS_OPEN_REPLY:
1238 	err = fs_read_open_font(fpe, blockrec);
1239 	if (err != StillWorking) {	/* already loaded, or error */
1240 	    /* if font's already loaded, massage error code */
1241 	    switch (bfont->state) {
1242 	    case FS_DONE_REPLY:
1243 		err = Successful;
1244 		break;
1245 	    case FS_DEPENDING:
1246 		err = StillWorking;
1247 		break;
1248 	    }
1249 	}
1250 	break;
1251     case FS_INFO_REPLY:
1252 	err = fs_read_query_info(fpe, blockrec);
1253 	break;
1254     case FS_EXTENT_REPLY:
1255 	err = fs_read_extent_info(fpe, blockrec);
1256 	break;
1257     case FS_GLYPHS_REPLY:
1258 	if (bfont->flags & FontLoadBitmaps)
1259 	    err = fs_read_glyphs(fpe, blockrec);
1260 	break;
1261     case FS_DEPENDING:		/* can't happen */
1262     default:
1263 	break;
1264     }
1265 #ifdef DEBUG
1266     fprintf (stderr, "fs_do_open_font err %d\n", err);
1267 #endif
1268     if (err != StillWorking)
1269     {
1270 	bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1271 	while ((blockrec = blockrec->depending))
1272 	{
1273 	    bfont = (FSBlockedFontPtr) blockrec->data;
1274 	    bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1275 	}
1276     }
1277     return err;
1278 }
1279 
1280 void
_fs_mark_block(FSFpePtr conn,CARD32 mask)1281 _fs_mark_block (FSFpePtr conn, CARD32 mask)
1282 {
1283     conn->blockState |= mask;
1284     fs_blockState |= mask;
1285 }
1286 
1287 void
_fs_unmark_block(FSFpePtr conn,CARD32 mask)1288 _fs_unmark_block (FSFpePtr conn, CARD32 mask)
1289 {
1290     FSFpePtr	c;
1291 
1292     if (conn->blockState & mask)
1293     {
1294 	conn->blockState &= ~mask;
1295 	fs_blockState = 0;
1296 	for (c = fs_fpes; c; c = c->next)
1297 	    fs_blockState |= c->blockState;
1298     }
1299 }
1300 
1301 /* ARGSUSED */
1302 static void
fs_block_handler(pointer data,OSTimePtr wt,pointer LastSelectMask)1303 fs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
1304 {
1305     static struct timeval block_timeout;
1306     CARD32	now, earliest, wakeup;
1307     int		soonest;
1308     FSFpePtr    conn;
1309 
1310     XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
1311 	      &_fs_fd_mask);
1312     /*
1313      * Flush all pending output
1314      */
1315     if (fs_blockState & FS_PENDING_WRITE)
1316 	for (conn = fs_fpes; conn; conn = conn->next)
1317 	    if (conn->blockState & FS_PENDING_WRITE)
1318 		_fs_flush (conn);
1319     /*
1320      * Check for any fpe with a complete reply, set sleep time to zero
1321      */
1322     if (fs_blockState & FS_COMPLETE_REPLY)
1323     {
1324 	block_timeout.tv_sec = 0;
1325 	block_timeout.tv_usec = 0;
1326 	if (*wt == NULL)
1327 	    *wt = &block_timeout;
1328 	else
1329 	    **wt = block_timeout;
1330     }
1331     /*
1332      * Walk through fpe list computing sleep time
1333      */
1334     else if (fs_blockState & (FS_BROKEN_WRITE|
1335 			      FS_BROKEN_CONNECTION|
1336 			      FS_PENDING_REPLY|
1337 			      FS_RECONNECTING))
1338     {
1339 	now = GetTimeInMillis ();
1340 	earliest = now + 10000000;
1341 	for (conn = fs_fpes; conn; conn = conn->next)
1342 	{
1343 	    if (conn->blockState & FS_RECONNECTING)
1344 	    {
1345 		wakeup = conn->blockedConnectTime;
1346 		if (TimeCmp (wakeup, <, earliest))
1347 		    earliest = wakeup;
1348 	    }
1349 	    if (conn->blockState & FS_BROKEN_CONNECTION)
1350 	    {
1351 		wakeup = conn->brokenConnectionTime;
1352 		if (TimeCmp (wakeup, <, earliest))
1353 		    earliest = wakeup;
1354 	    }
1355 	    if (conn->blockState & FS_BROKEN_WRITE)
1356 	    {
1357 		wakeup = conn->brokenWriteTime;
1358 		if (TimeCmp (wakeup, <, earliest))
1359 		    earliest = wakeup;
1360 	    }
1361 	    if (conn->blockState & FS_PENDING_REPLY)
1362 	    {
1363 		wakeup = conn->blockedReplyTime;
1364 		if (TimeCmp (wakeup, <, earliest))
1365 		    earliest = wakeup;
1366 	    }
1367 	}
1368 	soonest = earliest - now;
1369 	if (soonest < 0)
1370 	    soonest = 0;
1371 	block_timeout.tv_sec = soonest / 1000;
1372 	block_timeout.tv_usec = (soonest % 1000) * 1000;
1373 	if (*wt == NULL)
1374 	    *wt = &block_timeout;
1375 	else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
1376 	    **wt = block_timeout;
1377     }
1378 }
1379 
1380 static void
fs_handle_unexpected(FSFpePtr conn,fsGenericReply * rep)1381 fs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
1382 {
1383     if (rep->type == FS_Event && rep->data1 == KeepAlive)
1384     {
1385 	fsNoopReq   req;
1386 
1387 	/* ping it back */
1388 	req.reqType = FS_Noop;
1389 	req.length = SIZEOF(fsNoopReq) >> 2;
1390 	_fs_add_req_log(conn, FS_Noop);
1391 	_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
1392     }
1393     /* this should suck up unexpected replies and events */
1394     _fs_done_read (conn, rep->length << 2);
1395 }
1396 
1397 static void
fs_read_reply(FontPathElementPtr fpe,pointer client)1398 fs_read_reply (FontPathElementPtr fpe, pointer client)
1399 {
1400     FSFpePtr	    conn = (FSFpePtr) fpe->private;
1401     FSBlockDataPtr  blockrec;
1402     int		    ret;
1403     int		    err;
1404     fsGenericReply  *rep;
1405 
1406     if ((rep = fs_get_reply (conn, &ret)))
1407     {
1408 	_fs_add_rep_log (conn, rep);
1409 	for (blockrec = conn->blockedRequests;
1410 	     blockrec;
1411 	     blockrec = blockrec->next)
1412 	{
1413 	    if (blockrec->sequenceNumber == rep->sequenceNumber)
1414 		break;
1415 	}
1416 	err = Successful;
1417 	if (!blockrec)
1418 	{
1419 	    fs_handle_unexpected(conn, rep);
1420 	}
1421 	else
1422 	{
1423 	    /*
1424 	     * go read it, and if we're done,
1425 	     * wake up the appropriate client
1426 	     */
1427 	    switch (blockrec->type) {
1428 	    case FS_OPEN_FONT:
1429 		blockrec->errcode = fs_do_open_font(fpe, blockrec);
1430 		break;
1431 	    case FS_LOAD_GLYPHS:
1432 		blockrec->errcode = fs_read_glyphs(fpe, blockrec);
1433 		break;
1434 	    case FS_LIST_FONTS:
1435 		blockrec->errcode = fs_read_list(fpe, blockrec);
1436 		break;
1437 	    case FS_LIST_WITH_INFO:
1438 		blockrec->errcode = fs_read_list_info(fpe, blockrec);
1439 		break;
1440 	    default:
1441 		break;
1442 	    }
1443 	    err = blockrec->errcode;
1444 	    if (err != StillWorking)
1445 	    {
1446 		while (blockrec)
1447 		{
1448 		    blockrec->errcode = err;
1449 		    if (client != blockrec->client)
1450 			ClientSignal(blockrec->client);
1451 		    blockrec = blockrec->depending;
1452 		}
1453 		_fs_unmark_block (conn, FS_PENDING_REPLY);
1454 	    }
1455 	}
1456 	if (fs_reply_ready (conn))
1457 	    _fs_mark_block (conn, FS_COMPLETE_REPLY);
1458 	else
1459 	    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
1460     }
1461 }
1462 
1463 static int
fs_wakeup(FontPathElementPtr fpe,unsigned long * mask)1464 fs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
1465 {
1466     fd_set	    *LastSelectMask = (fd_set *) mask;
1467     FSFpePtr	    conn = (FSFpePtr) fpe->private;
1468 
1469     /*
1470      * Don't continue if the fd is -1 (which will be true when the
1471      * font server terminates
1472      */
1473     if ((conn->blockState & FS_RECONNECTING))
1474 	_fs_check_reconnect (conn);
1475     else if ((conn->blockState & FS_COMPLETE_REPLY) ||
1476 	     (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
1477 	fs_read_reply (fpe, 0);
1478     if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
1479 	_fs_do_blocked (conn);
1480 #ifdef DEBUG
1481     {
1482 	FSBlockDataPtr	    blockrec;
1483 	FSBlockedFontPtr    bfont;
1484 	static CARD32	    lastState;
1485 	static FSBlockDataPtr	lastBlock;
1486 
1487 	if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
1488 	{
1489 	    fprintf (stderr, "  Block State 0x%x\n", (int) conn->blockState);
1490 	    lastState = conn->blockState;
1491 	    lastBlock = conn->blockedRequests;
1492 	}
1493 	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1494 	{
1495 	    switch (blockrec->type) {
1496 	    case FS_OPEN_FONT:
1497 		bfont = (FSBlockedFontPtr) blockrec->data;
1498 		fprintf (stderr, "  Blocked font errcode %d sequence %d state %s %s\n",
1499 			 blockrec->errcode,
1500 			 blockrec->sequenceNumber,
1501 			 fs_open_states[bfont->state],
1502 			 bfont->pfont ?
1503 			 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
1504 			 "<freed>");
1505 		break;
1506 	    case FS_LIST_FONTS:
1507 		fprintf (stderr, "  Blocked list errcode %d sequence %d\n",
1508 			 blockrec->errcode, blockrec->sequenceNumber);
1509 		break;
1510 	    default:
1511 		fprintf (stderr, "  Blocked type %d errcode %d sequence %d\n",
1512 			 blockrec->type,
1513 			 blockrec->errcode,
1514 			 blockrec->sequenceNumber);
1515 		break;
1516 	    }
1517 	}
1518     }
1519 #endif
1520     return FALSE;
1521 }
1522 
1523 /*
1524  * Notice a dead connection and prepare for reconnect
1525  */
1526 
1527 void
_fs_connection_died(FSFpePtr conn)1528 _fs_connection_died(FSFpePtr conn)
1529 {
1530     if (conn->blockState & FS_BROKEN_CONNECTION)
1531 	return;
1532     fs_close_conn(conn);
1533     conn->brokenConnectionTime = GetTimeInMillis ();
1534     _fs_mark_block (conn, FS_BROKEN_CONNECTION);
1535     _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
1536 }
1537 
1538 /*
1539  * Signal clients that the connection has come back up
1540  */
1541 static int
_fs_restart_connection(FSFpePtr conn)1542 _fs_restart_connection(FSFpePtr conn)
1543 {
1544     FSBlockDataPtr block;
1545 
1546     _fs_unmark_block (conn, FS_GIVE_UP);
1547     while ((block = (FSBlockDataPtr) conn->blockedRequests))
1548     {
1549 	if (block->errcode == StillWorking)
1550 	{
1551 	    ClientSignal(block->client);
1552 	    fs_abort_blockrec(conn, block);
1553 	}
1554     }
1555     return TRUE;
1556 }
1557 
1558 /*
1559  * Declare this font server connection useless
1560  */
1561 static void
_fs_giveup(FSFpePtr conn)1562 _fs_giveup (FSFpePtr conn)
1563 {
1564     FSBlockDataPtr  block;
1565 
1566     if (conn->blockState & FS_GIVE_UP)
1567 	return;
1568 #ifdef DEBUG
1569     fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
1570 #endif
1571     _fs_mark_block (conn, FS_GIVE_UP);
1572     while ((block = (FSBlockDataPtr) conn->blockedRequests))
1573     {
1574 	if (block->errcode == StillWorking)
1575 	{
1576 	    ClientSignal (block->client);
1577 	    fs_abort_blockrec (conn, block);
1578 	}
1579     }
1580     if (conn->fs_fd >= 0)
1581 	_fs_connection_died (conn);
1582 }
1583 
1584 static void
_fs_do_blocked(FSFpePtr conn)1585 _fs_do_blocked (FSFpePtr conn)
1586 {
1587     CARD32      now;
1588 
1589     now = GetTimeInMillis ();
1590     if ((conn->blockState & FS_PENDING_REPLY) &&
1591 	TimeCmp (conn->blockedReplyTime, <=, now))
1592     {
1593 	_fs_giveup (conn);
1594     }
1595     else
1596     {
1597 	if (conn->blockState & FS_BROKEN_CONNECTION)
1598 	{
1599 	    /* Try to reconnect broken connections */
1600 	    if (TimeCmp (conn->brokenConnectionTime, <=, now))
1601 		_fs_start_reconnect (conn);
1602 	}
1603 	else if (conn->blockState & FS_BROKEN_WRITE)
1604 	{
1605 	    /* Try to flush blocked connections */
1606 	    if (TimeCmp (conn->brokenWriteTime, <=, now))
1607 		_fs_flush (conn);
1608 	}
1609     }
1610 }
1611 
1612 /*
1613  * sends the actual request out
1614  */
1615 /* ARGSUSED */
1616 static int
fs_send_open_font(pointer client,FontPathElementPtr fpe,Mask flags,const char * name,int namelen,fsBitmapFormat format,fsBitmapFormatMask fmask,XID id,FontPtr * ppfont)1617 fs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1618 		  const char *name, int namelen,
1619 		  fsBitmapFormat format, fsBitmapFormatMask fmask,
1620 		  XID id, FontPtr *ppfont)
1621 {
1622     FSFpePtr		    conn = (FSFpePtr) fpe->private;
1623     FontPtr		    font;
1624     FSBlockDataPtr	    blockrec = NULL;
1625     FSBlockedFontPtr	    bfont;
1626     FSFontDataPtr	    fsd;
1627     fsOpenBitmapFontReq	    openreq;
1628     fsQueryXInfoReq	    inforeq;
1629     fsQueryXExtents16Req    extreq;
1630     int			    err;
1631     unsigned char	    buf[1024];
1632 
1633     if (conn->blockState & FS_GIVE_UP)
1634 	return BadFontName;
1635 
1636     if (namelen < 0 || namelen > sizeof (buf) - 1)
1637 	return BadFontName;
1638 
1639     /*
1640      * Get the font structure put together, either by reusing
1641      * the existing one or creating a new one
1642      */
1643     if (flags & FontReopen)
1644     {
1645 	Atom	nameatom, fn = None;
1646 	int	i;
1647 
1648 	font = *ppfont;
1649 	fsd = (FSFontDataPtr)font->fpePrivate;
1650 	/* This is an attempt to reopen a font.  Did the font have a
1651 	   NAME property? */
1652 	if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
1653 	{
1654 	    for (i = 0; i < font->info.nprops; i++)
1655 		if (font->info.props[i].name == nameatom &&
1656 		    font->info.isStringProp[i])
1657 		{
1658 		    fn = font->info.props[i].value;
1659 		    break;
1660 		}
1661 	}
1662 	if (fn == None || !(name = NameForAtom(fn)))
1663 	{
1664 	    name = fsd->name;
1665 	    namelen = fsd->namelen;
1666 	}
1667 	else
1668 	    namelen = strlen(name);
1669     }
1670     else
1671     {
1672 	font = fs_create_font (fpe, name, namelen, format, fmask);
1673 	if (!font)
1674 	    return AllocError;
1675 
1676 	fsd = (FSFontDataPtr)font->fpePrivate;
1677     }
1678 
1679     /* make a new block record, and add it to the end of the list */
1680     blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
1681     if (!blockrec)
1682     {
1683 	if (!(flags & FontReopen))
1684 	    (*font->unload_font) (font);
1685 	return AllocError;
1686     }
1687 
1688     /*
1689      * Must check this before generating any protocol, otherwise we'll
1690      * mess up a reconnect in progress
1691      */
1692     if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
1693     {
1694 	_fs_pending_reply (conn);
1695 	return Suspended;
1696     }
1697 
1698     fsd->generation = conn->generation;
1699 
1700     bfont = (FSBlockedFontPtr) blockrec->data;
1701     bfont->fontid = fsd->fontid;
1702     bfont->pfont = font;
1703     bfont->state = FS_OPEN_REPLY;
1704     bfont->flags = flags;
1705     bfont->format = fsd->format;
1706     bfont->clients_depending = (FSClientsDependingPtr)0;
1707     bfont->freeFont = (flags & FontReopen) == 0;
1708 
1709     _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
1710     _fs_client_resolution(conn);
1711 
1712     /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
1713     buf[0] = (unsigned char) namelen;
1714     memcpy(&buf[1], name, namelen);
1715     openreq.reqType = FS_OpenBitmapFont;
1716     openreq.pad = 0;
1717     openreq.fid = fsd->fontid;
1718     openreq.format_hint = fsd->format;
1719     openreq.format_mask = fsd->fmask;
1720     openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
1721 
1722     _fs_add_req_log(conn, FS_OpenBitmapFont);
1723     _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
1724     _fs_write_pad(conn, (char *) buf, namelen + 1);
1725 
1726     blockrec->sequenceNumber = conn->current_seq;
1727 
1728     inforeq.reqType = FS_QueryXInfo;
1729     inforeq.pad = 0;
1730     inforeq.id = fsd->fontid;
1731     inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
1732 
1733     bfont->queryInfoSequence = conn->current_seq + 1;
1734 
1735     _fs_add_req_log(conn, FS_QueryXInfo);
1736     _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
1737 
1738     if (!(bfont->flags & FontReopen))
1739     {
1740 	extreq.reqType = FS_QueryXExtents16;
1741 	extreq.range = fsTrue;
1742 	extreq.fid = fsd->fontid;
1743 	extreq.num_ranges = 0;
1744 	extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
1745 
1746 	bfont->queryExtentsSequence = conn->current_seq + 1;
1747 
1748 	_fs_add_req_log(conn, FS_QueryXExtents16);
1749 	_fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
1750     }
1751 
1752 #ifdef NCD
1753     if (configData.ExtendedFontDiags)
1754     {
1755 	memcpy(buf, name, MIN(256, namelen));
1756 	buf[MIN(256, namelen)] = '\0';
1757 	printf("Requesting font \"%s\" from font server \"%s\"\n",
1758 	       buf, font->fpe->name);
1759     }
1760 #endif
1761     _fs_prepare_for_reply (conn);
1762 
1763     err = blockrec->errcode;
1764     if (bfont->flags & FontOpenSync)
1765     {
1766 	while (blockrec->errcode == StillWorking)
1767 	{
1768 	    if (fs_await_reply (conn) != FSIO_READY)
1769 	    {
1770 		blockrec->errcode = BadFontName;
1771 		break;
1772 	    }
1773 	    fs_read_reply (font->fpe, client);
1774 	}
1775 	err = blockrec->errcode;
1776 	if (err == Successful)
1777 	    *ppfont = bfont->pfont;
1778 	else
1779 	    fs_cleanup_bfont (bfont);
1780 	bfont->freeFont = FALSE;
1781 	_fs_remove_block_rec (conn, blockrec);
1782     }
1783     return err == StillWorking ? Suspended : err;
1784 }
1785 
1786 static void
fs_send_query_bitmaps(FontPathElementPtr fpe,FSBlockDataPtr blockrec)1787 fs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1788 {
1789     FSFpePtr		    conn = (FSFpePtr) fpe->private;
1790     FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1791     fsQueryXBitmaps16Req    bitreq;
1792 
1793     /* send the request */
1794     bitreq.reqType = FS_QueryXBitmaps16;
1795     bitreq.fid = bfont->fontid;
1796     bitreq.format = bfont->format;
1797     bitreq.range = TRUE;
1798     bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
1799     bitreq.num_ranges = 0;
1800 
1801     bfont->queryBitmapsSequence = conn->current_seq + 1;
1802 
1803     _fs_add_req_log(conn, FS_QueryXBitmaps16);
1804     _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
1805 }
1806 
1807 /* ARGSUSED */
1808 static int
fs_open_font(pointer client,FontPathElementPtr fpe,Mask flags,const char * name,int namelen,fsBitmapFormat format,fsBitmapFormatMask fmask,XID id,FontPtr * ppfont,char ** alias,FontPtr non_cachable_font)1809 fs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1810 	     const char *name, int namelen,
1811 	     fsBitmapFormat format, fsBitmapFormatMask fmask,
1812 	     XID id, FontPtr *ppfont,
1813 	     char **alias, FontPtr non_cachable_font)
1814 {
1815     FSFpePtr		conn = (FSFpePtr) fpe->private;
1816     FSBlockDataPtr	blockrec;
1817     FSBlockedFontPtr	bfont;
1818     int			err;
1819 
1820     /* libfont interface expects ImageRectMin glyphs */
1821     format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
1822 
1823     *alias = (char *) 0;
1824     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1825     {
1826 	if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
1827 	{
1828 	    err = blockrec->errcode;
1829 	    if (err == StillWorking)
1830 		return Suspended;
1831 
1832 	    bfont = (FSBlockedFontPtr) blockrec->data;
1833 	    if (err == Successful)
1834 		*ppfont = bfont->pfont;
1835 	    else
1836 		fs_cleanup_bfont (bfont);
1837 	    _fs_remove_block_rec (conn, blockrec);
1838 	    return err;
1839 	}
1840     }
1841     return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
1842 			     id, ppfont);
1843 }
1844 
1845 /* ARGSUSED */
1846 static int
fs_send_close_font(FontPathElementPtr fpe,Font id)1847 fs_send_close_font(FontPathElementPtr fpe, Font id)
1848 {
1849     FSFpePtr    conn = (FSFpePtr) fpe->private;
1850     fsCloseReq  req;
1851 
1852     if (conn->blockState & FS_GIVE_UP)
1853 	return Successful;
1854     /* tell the font server to close the font */
1855     req.reqType = FS_CloseFont;
1856     req.pad = 0;
1857     req.length = SIZEOF(fsCloseReq) >> 2;
1858     req.id = id;
1859     _fs_add_req_log(conn, FS_CloseFont);
1860     _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
1861 
1862     return Successful;
1863 }
1864 
1865 /* ARGSUSED */
1866 static void
fs_close_font(FontPathElementPtr fpe,FontPtr pfont)1867 fs_close_font(FontPathElementPtr fpe, FontPtr pfont)
1868 {
1869     FSFontDataPtr   fsd = (FSFontDataPtr) pfont->fpePrivate;
1870     FSFpePtr	    conn = (FSFpePtr) fpe->private;
1871 
1872     if (conn->generation == fsd->generation)
1873 	fs_send_close_font(fpe, fsd->fontid);
1874 
1875 #ifdef DEBUG
1876     {
1877 	FSBlockDataPtr	    blockrec;
1878 	FSBlockedFontPtr    bfont;
1879 
1880 	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1881 	{
1882 	    if (blockrec->type == FS_OPEN_FONT)
1883 	    {
1884 		bfont = (FSBlockedFontPtr) blockrec->data;
1885 		if (bfont->pfont == pfont)
1886 		    fprintf (stderr, "closing font which hasn't been opened\n");
1887 	    }
1888 	}
1889     }
1890 #endif
1891     (*pfont->unload_font) (pfont);
1892 }
1893 
1894 static int
fs_read_glyphs(FontPathElementPtr fpe,FSBlockDataPtr blockrec)1895 fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1896 {
1897     FSBlockedGlyphPtr	    bglyph = (FSBlockedGlyphPtr) blockrec->data;
1898     FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1899     FSFpePtr		    conn = (FSFpePtr) fpe->private;
1900     FontPtr		    pfont = bglyph->pfont;
1901 					/* works for either blocked font
1902 					   or glyph rec...  pfont is at
1903 					   the very beginning of both
1904 					   blockrec->data structures */
1905     FSFontDataPtr	    fsd = (FSFontDataPtr) (pfont->fpePrivate);
1906     FSFontPtr		    fsdata = (FSFontPtr) pfont->fontPrivate;
1907     FontInfoPtr		    pfi = &pfont->info;
1908     fsQueryXBitmaps16Reply  *rep;
1909     char		    *buf;
1910     long		    bufleft; /* length of reply left to use */
1911     fsOffset32		    *ppbits;
1912     fsOffset32		    local_off;
1913     char		    *off_adr;
1914     pointer		    pbitmaps;
1915     char		    *bits, *allbits;
1916 #ifdef DEBUG
1917     char		    *origallbits;
1918 #endif
1919     int			    i,
1920 			    err;
1921     int			    nranges = 0;
1922     int			    ret;
1923     fsRange		    *nextrange = 0;
1924     unsigned long	    minchar, maxchar;
1925 
1926     rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
1927     if (!rep || rep->type == FS_Error ||
1928 	(rep->length < LENGTHOF(fsQueryXBitmaps16Reply)))
1929     {
1930 	if (ret == FSIO_BLOCK)
1931 	    return StillWorking;
1932 	if (rep)
1933 	    _fs_done_read (conn, rep->length << 2);
1934 	err = AllocError;
1935 	_fs_reply_failed (rep, fsQueryXBitmaps16Reply, "<");
1936 	goto bail;
1937     }
1938 
1939     buf = (char *) rep;
1940     buf += SIZEOF (fsQueryXBitmaps16Reply);
1941 
1942     bufleft = rep->length << 2;
1943     bufleft -= SIZEOF (fsQueryXBitmaps16Reply);
1944 
1945     if ((bufleft / SIZEOF (fsOffset32)) < rep->num_chars)
1946     {
1947 #ifdef DEBUG
1948 	fprintf(stderr,
1949 		"fsQueryXBitmaps16: num_chars (%d) > bufleft (%ld) / %d\n",
1950 		rep->num_chars, bufleft, SIZEOF (fsOffset32));
1951 #endif
1952 	err = AllocError;
1953 	goto bail;
1954     }
1955     ppbits = (fsOffset32 *) buf;
1956     buf += SIZEOF (fsOffset32) * (rep->num_chars);
1957     bufleft -= SIZEOF (fsOffset32) * (rep->num_chars);
1958 
1959     if (bufleft < rep->nbytes)
1960     {
1961 #ifdef DEBUG
1962 	fprintf(stderr,
1963 		"fsQueryXBitmaps16: nbytes (%d) > bufleft (%ld)\n",
1964 		rep->nbytes, bufleft);
1965 #endif
1966 	err = AllocError;
1967 	goto bail;
1968     }
1969     pbitmaps = (pointer ) buf;
1970 
1971     if (blockrec->type == FS_LOAD_GLYPHS)
1972     {
1973 	nranges = bglyph->num_expected_ranges;
1974 	nextrange = bglyph->expected_ranges;
1975     }
1976 
1977     /* place the incoming glyphs */
1978     if (nranges)
1979     {
1980 	/* We're operating under the assumption that the ranges
1981 	   requested in the LoadGlyphs call were all legal for this
1982 	   font, and that individual ranges do not cover multiple
1983 	   rows...  fs_build_range() is designed to ensure this. */
1984 	minchar = (nextrange->min_char_high - pfi->firstRow) *
1985 		  (pfi->lastCol - pfi->firstCol + 1) +
1986 		  nextrange->min_char_low - pfi->firstCol;
1987 	maxchar = (nextrange->max_char_high - pfi->firstRow) *
1988 		  (pfi->lastCol - pfi->firstCol + 1) +
1989 		  nextrange->max_char_low - pfi->firstCol;
1990 	nextrange++;
1991     }
1992     else
1993     {
1994 	minchar = 0;
1995 	maxchar = rep->num_chars;
1996     }
1997 
1998     off_adr = (char *)ppbits;
1999 
2000     allbits = fs_alloc_glyphs (pfont, rep->nbytes);
2001 
2002     if (!allbits)
2003     {
2004 	err = AllocError;
2005 	goto bail;
2006     }
2007 
2008 #ifdef DEBUG
2009     origallbits = allbits;
2010     fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
2011 	     (int) rep->num_chars, (int) rep->nbytes, fsd->name);
2012 #endif
2013 
2014     for (i = 0; i < rep->num_chars; i++)
2015     {
2016 	memcpy(&local_off, off_adr, SIZEOF(fsOffset32));	/* align it */
2017 	if (blockrec->type == FS_OPEN_FONT ||
2018 	    fsdata->encoding[minchar].bits == &_fs_glyph_requested)
2019 	{
2020 	    /*
2021 	     * Broken X font server returns bits for missing characters
2022 	     * when font is padded
2023 	     */
2024 	    if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
2025 	    {
2026 		if (local_off.length &&
2027 		    (local_off.position < rep->nbytes) &&
2028 		    (local_off.length <= (rep->nbytes - local_off.position)))
2029 		{
2030 		    bits = allbits;
2031 		    allbits += local_off.length;
2032 		    memcpy(bits, (char *)pbitmaps + local_off.position,
2033 			   local_off.length);
2034 		}
2035 		else
2036 		    bits = &_fs_glyph_zero_length;
2037 	    }
2038 	    else
2039 		bits = 0;
2040 	    if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
2041 		fsd->glyphs_to_get--;
2042 	    fsdata->encoding[minchar].bits = bits;
2043 	}
2044 	if (minchar++ == maxchar)
2045 	{
2046 	    if (!--nranges) break;
2047 	    minchar = (nextrange->min_char_high - pfi->firstRow) *
2048 		      (pfi->lastCol - pfi->firstCol + 1) +
2049 		      nextrange->min_char_low - pfi->firstCol;
2050 	    maxchar = (nextrange->max_char_high - pfi->firstRow) *
2051 		      (pfi->lastCol - pfi->firstCol + 1) +
2052 		      nextrange->max_char_low - pfi->firstCol;
2053 	    nextrange++;
2054 	}
2055 	off_adr += SIZEOF(fsOffset32);
2056     }
2057 #ifdef DEBUG
2058     fprintf (stderr, "Used %d bytes instead of %d\n",
2059 	     (int) (allbits - origallbits), (int) rep->nbytes);
2060 #endif
2061 
2062     if (blockrec->type == FS_OPEN_FONT)
2063     {
2064 	fsd->glyphs_to_get = 0;
2065 	bfont->state = FS_DONE_REPLY;
2066     }
2067     err = Successful;
2068 
2069 bail:
2070     _fs_done_read (conn, rep->length << 2);
2071     return err;
2072 }
2073 
2074 static int
fs_send_load_glyphs(pointer client,FontPtr pfont,int nranges,fsRange * ranges)2075 fs_send_load_glyphs(pointer client, FontPtr pfont,
2076 		    int nranges, fsRange *ranges)
2077 {
2078     FontPathElementPtr	    fpe = pfont->fpe;
2079     FSFpePtr		    conn = (FSFpePtr) fpe->private;
2080     FSBlockedGlyphPtr	    blockedglyph;
2081     fsQueryXBitmaps16Req    req;
2082     FSBlockDataPtr	    blockrec;
2083 
2084     if (conn->blockState & FS_GIVE_UP)
2085 	return BadCharRange;
2086 
2087     /* make a new block record, and add it to the end of the list */
2088     blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
2089     if (!blockrec)
2090 	return AllocError;
2091     blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2092     blockedglyph->pfont = pfont;
2093     blockedglyph->num_expected_ranges = nranges;
2094     /* Assumption: it's our job to free ranges */
2095     blockedglyph->expected_ranges = ranges;
2096     blockedglyph->clients_depending = (FSClientsDependingPtr)0;
2097 
2098     if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
2099     {
2100 	_fs_pending_reply (conn);
2101 	return Suspended;
2102     }
2103 
2104     /* send the request */
2105     req.reqType = FS_QueryXBitmaps16;
2106     req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
2107     req.format = pfont->format;
2108     if (pfont->info.terminalFont)
2109 	req.format = (req.format & ~(BitmapFormatImageRectMask)) |
2110 		     BitmapFormatImageRectMax;
2111     req.range = TRUE;
2112     /* each range takes up 4 bytes */
2113     req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
2114     req.num_ranges = nranges * 2;	/* protocol wants count of fsChar2bs */
2115     _fs_add_req_log(conn, FS_QueryXBitmaps16);
2116     _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
2117 
2118     blockrec->sequenceNumber = conn->current_seq;
2119 
2120     /* Send ranges to the server... pack into a char array by hand
2121        to avoid structure-packing portability problems and to
2122        handle swapping for version1 protocol */
2123     if (nranges)
2124     {
2125 #define RANGE_BUFFER_SIZE 64
2126 #define RANGE_BUFFER_SIZE_MASK 63
2127 	int i;
2128 	char range_buffer[RANGE_BUFFER_SIZE * 4];
2129 	char *range_buffer_p;
2130 
2131 	range_buffer_p = range_buffer;
2132 	for (i = 0; i < nranges;)
2133 	{
2134 	    if (conn->fsMajorVersion > 1)
2135 	    {
2136 		*range_buffer_p++ = ranges[i].min_char_high;
2137 		*range_buffer_p++ = ranges[i].min_char_low;
2138 		*range_buffer_p++ = ranges[i].max_char_high;
2139 		*range_buffer_p++ = ranges[i].max_char_low;
2140 	    }
2141 	    else
2142 	    {
2143 		*range_buffer_p++ = ranges[i].min_char_low;
2144 		*range_buffer_p++ = ranges[i].min_char_high;
2145 		*range_buffer_p++ = ranges[i].max_char_low;
2146 		*range_buffer_p++ = ranges[i].max_char_high;
2147 	    }
2148 
2149 	    if (!(++i & RANGE_BUFFER_SIZE_MASK))
2150 	    {
2151 		_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
2152 		range_buffer_p = range_buffer;
2153 	    }
2154 	}
2155 	if (i &= RANGE_BUFFER_SIZE_MASK)
2156 	    _fs_write(conn, range_buffer, i * 4);
2157     }
2158 
2159     _fs_prepare_for_reply (conn);
2160     return Suspended;
2161 }
2162 
2163 
2164 extern pointer __GetServerClient(void);	/* This could be any number that
2165 				   doesn't conflict with existing
2166 				   client values. */
2167 
2168 static int
_fs_load_glyphs(pointer client,FontPtr pfont,Bool range_flag,unsigned int nchars,int item_size,unsigned char * data)2169 _fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
2170 		unsigned int nchars, int item_size, unsigned char *data)
2171 {
2172     FSFpePtr		    conn = (FSFpePtr) pfont->fpe->private;
2173     int			    nranges = 0;
2174     fsRange		    *ranges = NULL;
2175     int			    res;
2176     FSBlockDataPtr	    blockrec;
2177     FSBlockedGlyphPtr	    blockedglyph;
2178     FSClientsDependingPtr   *clients_depending = NULL;
2179     int			    err;
2180 
2181     /* see if the result is already there */
2182     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2183     {
2184 	if (blockrec->type == FS_LOAD_GLYPHS)
2185 	{
2186 	    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2187 	    if (blockedglyph->pfont == pfont)
2188 	    {
2189 		/* Look for this request */
2190 		if (blockrec->client == client)
2191 		{
2192 		    err = blockrec->errcode;
2193 		    if (err == StillWorking)
2194 			return Suspended;
2195 		    _fs_signal_clients_depending(&blockedglyph->clients_depending);
2196 		    _fs_remove_block_rec(conn, blockrec);
2197 		    return err;
2198 		}
2199 		/* We've found an existing LoadGlyphs blockrec for this
2200 		   font but for another client.  Rather than build a
2201 		   blockrec for it now (which entails some complex
2202 		   maintenance), we'll add it to a queue of clients to
2203 		   be signalled when the existing LoadGlyphs is
2204 		   completed.  */
2205 		clients_depending = &blockedglyph->clients_depending;
2206 		break;
2207 	    }
2208 	}
2209 	else if (blockrec->type == FS_OPEN_FONT)
2210 	{
2211 	    FSBlockedFontPtr bfont;
2212 	    bfont = (FSBlockedFontPtr) blockrec->data;
2213 	    if (bfont->pfont == pfont)
2214 	    {
2215 		/*
2216 		 * An OpenFont is pending for this font, this must
2217 		 * be from a reopen attempt, so finish the open
2218 		 * attempt and retry the LoadGlyphs
2219 		 */
2220 		if (blockrec->client == client)
2221 		{
2222 		    err = blockrec->errcode;
2223 		    if (err == StillWorking)
2224 			return Suspended;
2225 
2226 		    _fs_signal_clients_depending(&bfont->clients_depending);
2227 		    _fs_remove_block_rec(conn, blockrec);
2228 		    if (err != Successful)
2229 			return err;
2230 		    break;
2231 		}
2232 		/* We've found an existing OpenFont blockrec for this
2233 		   font but for another client.  Rather than build a
2234 		   blockrec for it now (which entails some complex
2235 		   maintenance), we'll add it to a queue of clients to
2236 		   be signalled when the existing OpenFont is
2237 		   completed.  */
2238 		if (blockrec->errcode == StillWorking)
2239 		{
2240 		    clients_depending = &bfont->clients_depending;
2241 		    break;
2242 		}
2243 	    }
2244 	}
2245     }
2246 
2247     /*
2248      * see if the desired glyphs already exist, and return Successful if they
2249      * do, otherwise build up character range/character string
2250      */
2251     res = fs_build_range(pfont, range_flag, nchars, item_size, data,
2252 			 &nranges, &ranges);
2253 
2254     switch (res)
2255     {
2256 	case AccessDone:
2257 	    return Successful;
2258 
2259 	case Successful:
2260 	    break;
2261 
2262 	default:
2263 	    return res;
2264     }
2265 
2266     /*
2267      * If clients_depending is not null, this request must wait for
2268      * some prior request(s) to complete.
2269      */
2270     if (clients_depending)
2271     {
2272 	/* Since we're not ready to send the load_glyphs request yet,
2273 	   clean up the damage (if any) caused by the fs_build_range()
2274 	   call. */
2275 	if (nranges)
2276 	{
2277 	    _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2278 	    free(ranges);
2279 	}
2280 	return _fs_add_clients_depending(clients_depending, client);
2281     }
2282 
2283     /*
2284      * If fsd->generation != conn->generation, the font has been closed
2285      * due to a lost connection.  We will reopen it, which will result
2286      * in one of three things happening:
2287      *	 1) The open will succeed and obtain the same font.  Life
2288      *	    is wonderful.
2289      *	 2) The open will fail.  There is code above to recognize this
2290      *	    and flunk the LoadGlyphs request.  The client might not be
2291      *	    thrilled.
2292      *	 3) Worst case: the open will succeed but the font we open will
2293      *	    be different.  The fs_read_query_info() procedure attempts
2294      *	    to detect this by comparing the existing metrics and
2295      *	    properties against those of the reopened font... if they
2296      *	    don't match, we flunk the reopen, which eventually results
2297      *	    in flunking the LoadGlyphs request.  We could go a step
2298      *	    further and compare the extents, but this should be
2299      *	    sufficient.
2300      */
2301     if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
2302     {
2303 	/* Since we're not ready to send the load_glyphs request yet,
2304 	   clean up the damage caused by the fs_build_range() call. */
2305 	_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2306 	free(ranges);
2307 
2308 	/* Now try to reopen the font. */
2309 	return fs_send_open_font(client, pfont->fpe,
2310 				 (Mask)FontReopen, (char *)0, 0,
2311 				 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
2312 				 (XID)0, &pfont);
2313     }
2314 
2315     return fs_send_load_glyphs(client, pfont, nranges, ranges);
2316 }
2317 
2318 int
fs_load_all_glyphs(FontPtr pfont)2319 fs_load_all_glyphs(FontPtr pfont)
2320 {
2321     int		err;
2322     FSFpePtr	conn = (FSFpePtr) pfont->fpe->private;
2323 
2324     /*
2325      * The purpose of this procedure is to load all glyphs in the event
2326      * that we're dealing with someone who doesn't understand the finer
2327      * points of glyph caching...  it is called from _fs_get_glyphs() if
2328      * the latter is called to get glyphs that have not yet been loaded.
2329      * We assume that the caller will not know how to handle a return
2330      * value of Suspended (usually the case for a GetGlyphs() caller),
2331      * so this procedure hangs around, freezing the server, for the
2332      * request to complete.  This is an unpleasant kluge called to
2333      * perform an unpleasant job that, we hope, will never be required.
2334      */
2335 
2336     while ((err = _fs_load_glyphs(__GetServerClient(), pfont, TRUE, 0, 0, NULL)) ==
2337 	   Suspended)
2338     {
2339 	if (fs_await_reply (conn) != FSIO_READY)
2340 	{
2341 	    /* Get rid of blockrec */
2342 	    fs_client_died(__GetServerClient(), pfont->fpe);
2343 	    err = BadCharRange;
2344 	    break;
2345 	}
2346 	fs_read_reply (pfont->fpe, __GetServerClient());
2347     }
2348     return err;
2349 }
2350 
2351 static int
fs_read_list(FontPathElementPtr fpe,FSBlockDataPtr blockrec)2352 fs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2353 {
2354     FSFpePtr		conn = (FSFpePtr) fpe->private;
2355     FSBlockedListPtr	blist = (FSBlockedListPtr) blockrec->data;
2356     fsListFontsReply	*rep;
2357     char		*data;
2358     long		dataleft; /* length of reply left to use */
2359     int			length,
2360 			i,
2361 			ret;
2362     int			err;
2363 
2364     rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
2365     if (!rep || rep->type == FS_Error ||
2366 	(rep->length < LENGTHOF(fsListFontsReply)))
2367     {
2368 	if (ret == FSIO_BLOCK)
2369 	    return StillWorking;
2370 	if (rep)
2371 	    _fs_done_read (conn, rep->length << 2);
2372 	_fs_reply_failed (rep, fsListFontsReply, "<");
2373 	return AllocError;
2374     }
2375     data = (char *) rep + SIZEOF (fsListFontsReply);
2376     dataleft = (rep->length << 2) - SIZEOF (fsListFontsReply);
2377 
2378     err = Successful;
2379     /* copy data into FontPathRecord */
2380     for (i = 0; i < rep->nFonts; i++)
2381     {
2382 	if (dataleft < 1)
2383 	    break;
2384 	length = *(unsigned char *)data++;
2385 	dataleft--; /* used length byte */
2386 	if (length > dataleft) {
2387 #ifdef DEBUG
2388 	    fprintf(stderr,
2389 		    "fsListFonts: name length (%d) > dataleft (%ld)\n",
2390 		    length, dataleft);
2391 #endif
2392 	    err = BadFontName;
2393 	    break;
2394 	}
2395 	err = AddFontNamesName(blist->names, data, length);
2396 	if (err != Successful)
2397 	    break;
2398 	data += length;
2399 	dataleft -= length;
2400     }
2401     _fs_done_read (conn, rep->length << 2);
2402     return err;
2403 }
2404 
2405 static int
fs_send_list_fonts(pointer client,FontPathElementPtr fpe,const char * pattern,int patlen,int maxnames,FontNamesPtr newnames)2406 fs_send_list_fonts(pointer client, FontPathElementPtr fpe, const char *pattern,
2407 		   int patlen, int maxnames, FontNamesPtr newnames)
2408 {
2409     FSFpePtr		conn = (FSFpePtr) fpe->private;
2410     FSBlockDataPtr	blockrec;
2411     FSBlockedListPtr	blockedlist;
2412     fsListFontsReq	req;
2413 
2414     if (conn->blockState & FS_GIVE_UP)
2415 	return BadFontName;
2416 
2417     /* make a new block record, and add it to the end of the list */
2418     blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
2419     if (!blockrec)
2420 	return AllocError;
2421     blockedlist = (FSBlockedListPtr) blockrec->data;
2422     blockedlist->names = newnames;
2423 
2424     if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2425     {
2426 	_fs_pending_reply (conn);
2427 	return Suspended;
2428     }
2429 
2430     _fs_client_access (conn, client, FALSE);
2431     _fs_client_resolution(conn);
2432 
2433     /* send the request */
2434     req.reqType = FS_ListFonts;
2435     req.pad = 0;
2436     req.maxNames = maxnames;
2437     req.nbytes = patlen;
2438     req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
2439     _fs_add_req_log(conn, FS_ListFonts);
2440     _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
2441     _fs_write_pad(conn, (char *) pattern, patlen);
2442 
2443     blockrec->sequenceNumber = conn->current_seq;
2444 
2445 #ifdef NCD
2446     if (configData.ExtendedFontDiags) {
2447 	char        buf[256];
2448 
2449 	memcpy(buf, pattern, MIN(256, patlen));
2450 	buf[MIN(256, patlen)] = '\0';
2451 	printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
2452 	       buf, fpe->name);
2453     }
2454 #endif
2455 
2456     _fs_prepare_for_reply (conn);
2457     return Suspended;
2458 }
2459 
2460 static int
fs_list_fonts(pointer client,FontPathElementPtr fpe,const char * pattern,int patlen,int maxnames,FontNamesPtr newnames)2461 fs_list_fonts(pointer client, FontPathElementPtr fpe,
2462 	      const char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
2463 {
2464     FSFpePtr		conn = (FSFpePtr) fpe->private;
2465     FSBlockDataPtr	blockrec;
2466     int			err;
2467 
2468     /* see if the result is already there */
2469     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2470     {
2471 	if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
2472 	{
2473 	    err = blockrec->errcode;
2474 	    if (err == StillWorking)
2475 		return Suspended;
2476 	    _fs_remove_block_rec(conn, blockrec);
2477 	    return err;
2478 	}
2479     }
2480 
2481     /* didn't find waiting record, so send a new one */
2482     return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
2483 }
2484 
2485 /*
2486  * Read a single list info reply and restart for the next reply
2487  */
2488 static int
fs_read_list_info(FontPathElementPtr fpe,FSBlockDataPtr blockrec)2489 fs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2490 {
2491     FSBlockedListInfoPtr	binfo = (FSBlockedListInfoPtr) blockrec->data;
2492     fsListFontsWithXInfoReply	*rep;
2493     char			*buf;
2494     long			bufleft;
2495     FSFpePtr			conn = (FSFpePtr) fpe->private;
2496     fsPropInfo			*pi;
2497     fsPropOffset		*po;
2498     pointer			pd;
2499     int				ret;
2500     int				err;
2501 
2502     /* clean up anything from the last trip */
2503     _fs_free_props (&binfo->info);
2504 
2505     rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
2506     if (!rep || rep->type == FS_Error ||
2507 	((rep->nameLength != 0) &&
2508 	 (rep->length < LENGTHOF(fsListFontsWithXInfoReply))))
2509     {
2510 	if (ret == FSIO_BLOCK)
2511 	    return StillWorking;
2512 	binfo->status = FS_LFWI_FINISHED;
2513 	err = AllocError;
2514 	_fs_reply_failed (rep, fsListFontsWithXInfoReply, "<");
2515 	goto done;
2516     }
2517     /*
2518      * Normal termination -- the list ends with a name of length 0
2519      */
2520     if (rep->nameLength == 0)
2521     {
2522 #ifdef DEBUG
2523 	fprintf (stderr, "fs_read_list_info done\n");
2524 #endif
2525 	binfo->status = FS_LFWI_FINISHED;
2526 	err = BadFontName;
2527 	goto done;
2528     }
2529 
2530     buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
2531     bufleft = (rep->length << 2) - SIZEOF (fsListFontsWithXInfoReply);
2532 
2533     /*
2534      * The original FS implementation didn't match
2535      * the spec, version 1 was respecified to match the FS.
2536      * Version 2 matches the original intent
2537      */
2538     if (conn->fsMajorVersion <= 1)
2539     {
2540 	if (rep->nameLength > bufleft) {
2541 #ifdef DEBUG
2542 	    fprintf(stderr,
2543 		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
2544 		    (int) rep->nameLength, bufleft);
2545 #endif
2546 	    err = AllocError;
2547 	    goto done;
2548 	}
2549 	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
2550 	memcpy (binfo->name, buf, rep->nameLength);
2551 	buf += _fs_pad_length (rep->nameLength);
2552 	bufleft -= _fs_pad_length (rep->nameLength);
2553     }
2554     pi = (fsPropInfo *) buf;
2555     if (SIZEOF (fsPropInfo) > bufleft) {
2556 #ifdef DEBUG
2557 	fprintf(stderr,
2558 		"fsListFontsWithXInfo: PropInfo length (%d) > bufleft (%ld)\n",
2559 		(int) SIZEOF (fsPropInfo), bufleft);
2560 #endif
2561 	err = AllocError;
2562 	goto done;
2563     }
2564     bufleft -= SIZEOF (fsPropInfo);
2565     buf += SIZEOF (fsPropInfo);
2566     po = (fsPropOffset *) buf;
2567     if (pi->num_offsets > (bufleft / SIZEOF (fsPropOffset))) {
2568 #ifdef DEBUG
2569 	fprintf(stderr,
2570 		"fsListFontsWithXInfo: offset length (%d * %d) > bufleft (%ld)\n",
2571 		pi->num_offsets, (int) SIZEOF (fsPropOffset), bufleft);
2572 #endif
2573 	err = AllocError;
2574 	goto done;
2575     }
2576     bufleft -= pi->num_offsets * SIZEOF (fsPropOffset);
2577     buf += pi->num_offsets * SIZEOF (fsPropOffset);
2578     pd = (pointer) buf;
2579     if (pi->data_len > bufleft) {
2580 #ifdef DEBUG
2581 	fprintf(stderr,
2582 		"fsListFontsWithXInfo: data length (%d) > bufleft (%ld)\n",
2583 		pi->data_len, bufleft);
2584 #endif
2585 	err = AllocError;
2586 	goto done;
2587     }
2588     bufleft -= pi->data_len;
2589     buf += pi->data_len;
2590     if (conn->fsMajorVersion > 1)
2591     {
2592 	if (rep->nameLength > bufleft) {
2593 #ifdef DEBUG
2594 	    fprintf(stderr,
2595 		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
2596 		    (int) rep->nameLength, bufleft);
2597 #endif
2598 	    err = AllocError;
2599 	    goto done;
2600 	}
2601 	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
2602 	memcpy (binfo->name, buf, rep->nameLength);
2603 	buf += _fs_pad_length (rep->nameLength);
2604 	bufleft -= _fs_pad_length (rep->nameLength);
2605     }
2606 
2607 #ifdef DEBUG
2608     binfo->name[rep->nameLength] = '\0';
2609     fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
2610 #endif
2611     err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
2612     if (err != Successful)
2613     {
2614 	binfo->status = FS_LFWI_FINISHED;
2615 	goto done;
2616     }
2617     binfo->namelen = rep->nameLength;
2618     binfo->remaining = rep->nReplies;
2619 
2620     binfo->status = FS_LFWI_REPLY;
2621 
2622     /* disable this font server until we've processed this response */
2623     _fs_unmark_block (conn, FS_COMPLETE_REPLY);
2624     FD_CLR(conn->fs_fd, &_fs_fd_mask);
2625 done:
2626     _fs_done_read (conn, rep->length << 2);
2627     return err;
2628 }
2629 
2630 /* ARGSUSED */
2631 static int
fs_start_list_with_info(pointer client,FontPathElementPtr fpe,const char * pattern,int len,int maxnames,pointer * pdata)2632 fs_start_list_with_info(pointer client, FontPathElementPtr fpe,
2633 			const char *pattern, int len, int maxnames, pointer *pdata)
2634 {
2635     FSFpePtr		    conn = (FSFpePtr) fpe->private;
2636     FSBlockDataPtr	    blockrec;
2637     FSBlockedListInfoPtr    binfo;
2638     fsListFontsWithXInfoReq req;
2639 
2640     if (conn->blockState & FS_GIVE_UP)
2641 	return BadFontName;
2642 
2643     /* make a new block record, and add it to the end of the list */
2644     blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
2645     if (!blockrec)
2646 	return AllocError;
2647 
2648     binfo = (FSBlockedListInfoPtr) blockrec->data;
2649     bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
2650     binfo->status = FS_LFWI_WAITING;
2651 
2652     if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2653     {
2654 	_fs_pending_reply (conn);
2655 	return Suspended;
2656     }
2657 
2658     _fs_client_access (conn, client, FALSE);
2659     _fs_client_resolution(conn);
2660 
2661     /* send the request */
2662     req.reqType = FS_ListFontsWithXInfo;
2663     req.pad = 0;
2664     req.maxNames = maxnames;
2665     req.nbytes = len;
2666     req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
2667     _fs_add_req_log(conn, FS_ListFontsWithXInfo);
2668     (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
2669     (void) _fs_write_pad(conn, pattern, len);
2670 
2671     blockrec->sequenceNumber = conn->current_seq;
2672 
2673 #ifdef NCD
2674     if (configData.ExtendedFontDiags) {
2675 	char        buf[256];
2676 
2677 	memcpy(buf, pattern, MIN(256, len));
2678 	buf[MIN(256, len)] = '\0';
2679 	printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
2680 	       buf, fpe->name);
2681     }
2682 #endif
2683 
2684     _fs_prepare_for_reply (conn);
2685     return Successful;
2686 }
2687 
2688 /* ARGSUSED */
2689 static int
fs_next_list_with_info(pointer client,FontPathElementPtr fpe,char ** namep,int * namelenp,FontInfoPtr * pFontInfo,int * numFonts,pointer private)2690 fs_next_list_with_info(pointer client, FontPathElementPtr fpe,
2691 		       char **namep, int *namelenp,
2692 		       FontInfoPtr *pFontInfo, int *numFonts,
2693 		       pointer private)
2694 {
2695     FSFpePtr		    conn = (FSFpePtr) fpe->private;
2696     FSBlockDataPtr	    blockrec;
2697     FSBlockedListInfoPtr    binfo;
2698     int			    err;
2699 
2700     /* see if the result is already there */
2701     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2702 	if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
2703 	    break;
2704 
2705     if (!blockrec)
2706     {
2707 	/* The only good reason for not finding a blockrec would be if
2708 	   disconnect/reconnect to the font server wiped it out and the
2709 	   code that called us didn't do the right thing to create
2710 	   another one.  Under those circumstances, we need to return an
2711 	   error to prevent that code from attempting to interpret the
2712 	   information we don't return.  */
2713 	return BadFontName;
2714     }
2715 
2716     binfo = (FSBlockedListInfoPtr) blockrec->data;
2717 
2718     if (binfo->status == FS_LFWI_WAITING)
2719 	return Suspended;
2720 
2721     *namep = binfo->name;
2722     *namelenp = binfo->namelen;
2723     *pFontInfo = &binfo->info;
2724     *numFonts = binfo->remaining;
2725 
2726     /* Restart reply processing from this font server */
2727     FD_SET(conn->fs_fd, &_fs_fd_mask);
2728     if (fs_reply_ready (conn))
2729 	_fs_mark_block (conn, FS_COMPLETE_REPLY);
2730 
2731     err = blockrec->errcode;
2732     switch (binfo->status) {
2733     case FS_LFWI_FINISHED:
2734 	_fs_remove_block_rec(conn, blockrec);
2735 	break;
2736     case FS_LFWI_REPLY:
2737 	binfo->status = FS_LFWI_WAITING;
2738 	blockrec->errcode = StillWorking;
2739 	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
2740 	_fs_mark_block (conn, FS_PENDING_REPLY);
2741 	break;
2742     }
2743 
2744     return err;
2745 }
2746 
2747 /*
2748  * Called when client exits
2749  */
2750 
2751 static void
fs_client_died(pointer client,FontPathElementPtr fpe)2752 fs_client_died(pointer client, FontPathElementPtr fpe)
2753 {
2754     FSFpePtr	    conn = (FSFpePtr) fpe->private;
2755     FSBlockDataPtr  blockrec,
2756 		    depending;
2757     FSClientPtr	    *prev, cur;
2758     fsFreeACReq	    freeac;
2759 
2760     for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2761     {
2762 	if (cur->client == client) {
2763 	    freeac.reqType = FS_FreeAC;
2764 	    freeac.pad = 0;
2765 	    freeac.id = cur->acid;
2766 	    freeac.length = sizeof (fsFreeACReq) >> 2;
2767 	    _fs_add_req_log(conn, FS_FreeAC);
2768 	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2769 	    *prev = cur->next;
2770 	    free (cur);
2771 	    break;
2772 	}
2773     }
2774     /* find a pending requests */
2775     for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2776 	if (blockrec->client == client)
2777 	    break;
2778 
2779     if (!blockrec)
2780 	return;
2781 
2782     /* replace the client pointers in this block rec with the chained one */
2783     if ((depending = blockrec->depending))
2784     {
2785 	blockrec->client = depending->client;
2786 	blockrec->depending = depending->depending;
2787 	blockrec = depending;
2788     }
2789     fs_abort_blockrec(conn, blockrec);
2790 }
2791 
2792 static void
_fs_client_access(FSFpePtr conn,pointer client,Bool sync)2793 _fs_client_access (FSFpePtr conn, pointer client, Bool sync)
2794 {
2795     FSClientPtr	*prev,	    cur;
2796     fsCreateACReq	    crac;
2797     fsSetAuthorizationReq   setac;
2798     char		    *authorizations;
2799     int			    authlen;
2800     Bool		    new_cur = FALSE;
2801     char		    padding[4] = { 0, 0, 0, 0 };
2802 
2803 #ifdef DEBUG
2804     if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
2805     {
2806 	fprintf (stderr, "Sending requests without a connection\n");
2807     }
2808 #endif
2809     for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2810     {
2811 	if (cur->client == client)
2812 	{
2813 	    if (prev != &conn->clients)
2814 	    {
2815 		*prev = cur->next;
2816 		cur->next = conn->clients;
2817 		conn->clients = cur;
2818 	    }
2819 	    break;
2820 	}
2821     }
2822     if (!cur)
2823     {
2824 	cur = malloc (sizeof (FSClientRec));
2825 	if (!cur)
2826 	    return;
2827 	cur->client = client;
2828 	cur->next = conn->clients;
2829 	conn->clients = cur;
2830 	cur->acid = GetNewFontClientID ();
2831 	new_cur = TRUE;
2832     }
2833     if (new_cur || cur->auth_generation != client_auth_generation(client))
2834     {
2835 	if (!new_cur)
2836 	{
2837 	    fsFreeACReq	freeac;
2838 	    freeac.reqType = FS_FreeAC;
2839 	    freeac.pad = 0;
2840 	    freeac.id = cur->acid;
2841 	    freeac.length = sizeof (fsFreeACReq) >> 2;
2842 	    _fs_add_req_log(conn, FS_FreeAC);
2843 	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2844 	}
2845 	crac.reqType = FS_CreateAC;
2846 	crac.num_auths = set_font_authorizations(&authorizations, &authlen,
2847 						 client);
2848 	/* Work around bug in xfs versions up through modular release 1.0.8
2849 	   which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
2850 	if (crac.num_auths == 0) {
2851 	    authorizations = padding;
2852 	    authlen = 4;
2853 	}
2854 	crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
2855 	crac.acid = cur->acid;
2856 	_fs_add_req_log(conn, FS_CreateAC);
2857 	_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
2858 	_fs_write_pad(conn, authorizations, authlen);
2859 	/* ignore reply; we don't even care about it */
2860 	conn->curacid = 0;
2861 	cur->auth_generation = client_auth_generation(client);
2862     }
2863     if (conn->curacid != cur->acid)
2864     {
2865     	setac.reqType = FS_SetAuthorization;
2866 	setac.pad = 0;
2867     	setac.length = sizeof (fsSetAuthorizationReq) >> 2;
2868     	setac.id = cur->acid;
2869     	_fs_add_req_log(conn, FS_SetAuthorization);
2870     	_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
2871 	conn->curacid = cur->acid;
2872     }
2873 }
2874 
2875 /*
2876  * Poll a pending connect
2877  */
2878 
2879 static int
_fs_check_connect(FSFpePtr conn)2880 _fs_check_connect (FSFpePtr conn)
2881 {
2882     int	    ret;
2883 
2884     ret = _fs_poll_connect (conn->trans_conn, 0);
2885     switch (ret) {
2886     case FSIO_READY:
2887 	conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
2888 	FD_SET (conn->fs_fd, &_fs_fd_mask);
2889 	break;
2890     case FSIO_BLOCK:
2891 	break;
2892     }
2893     return ret;
2894 }
2895 
2896 /*
2897  * Return an FSIO status while waiting for the completed connection
2898  * reply to arrive
2899  */
2900 
2901 static fsConnSetup *
_fs_get_conn_setup(FSFpePtr conn,int * error,int * setup_len)2902 _fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
2903 {
2904     int			ret;
2905     char		*data;
2906     int			headlen;
2907     int			len;
2908     fsConnSetup		*setup;
2909     fsConnSetupAccept	*accept;
2910 
2911     ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
2912     if (ret != FSIO_READY)
2913     {
2914 	*error = ret;
2915 	return 0;
2916     }
2917 
2918     setup = (fsConnSetup *) data;
2919     if (setup->major_version > FS_PROTOCOL)
2920     {
2921 	*error = FSIO_ERROR;
2922 	return 0;
2923     }
2924 
2925     headlen = (SIZEOF (fsConnSetup) +
2926 	       (setup->alternate_len << 2) +
2927 	       (setup->auth_len << 2));
2928     /* On anything but Success, no extra data is sent */
2929     if (setup->status != AuthSuccess)
2930     {
2931 	len = headlen;
2932     }
2933     else
2934     {
2935 	ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
2936 	if (ret != FSIO_READY)
2937 	{
2938 	    *error = ret;
2939 	    return 0;
2940 	}
2941 	setup = (fsConnSetup *) data;
2942 	accept = (fsConnSetupAccept *) (data + headlen);
2943 	len = headlen + (accept->length << 2);
2944     }
2945     ret = _fs_start_read (conn, len, &data);
2946     if (ret != FSIO_READY)
2947     {
2948 	*error = ret;
2949 	return 0;
2950     }
2951     *setup_len = len;
2952     return (fsConnSetup *) data;
2953 }
2954 
2955 static int
_fs_send_conn_client_prefix(FSFpePtr conn)2956 _fs_send_conn_client_prefix (FSFpePtr conn)
2957 {
2958     fsConnClientPrefix	req;
2959     int			endian;
2960     int			ret;
2961 
2962     /* send setup prefix */
2963     endian = 1;
2964     if (*(char *) &endian)
2965 	req.byteOrder = 'l';
2966     else
2967 	req.byteOrder = 'B';
2968 
2969     req.major_version = FS_PROTOCOL;
2970     req.minor_version = FS_PROTOCOL_MINOR;
2971 
2972 /* XXX add some auth info here */
2973     req.num_auths = 0;
2974     req.auth_len = 0;
2975     ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
2976     if (ret != FSIO_READY)
2977 	return FSIO_ERROR;
2978     conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
2979     return ret;
2980 }
2981 
2982 static int
_fs_recv_conn_setup(FSFpePtr conn)2983 _fs_recv_conn_setup (FSFpePtr conn)
2984 {
2985     int			ret = FSIO_ERROR;
2986     fsConnSetup		*setup;
2987     FSFpeAltPtr		alts;
2988     unsigned int	i, alt_len;
2989     int			setup_len;
2990     char		*alt_save, *alt_names;
2991 
2992     setup = _fs_get_conn_setup (conn, &ret, &setup_len);
2993     if (!setup)
2994 	return ret;
2995     conn->current_seq = 0;
2996     conn->fsMajorVersion = setup->major_version;
2997     /*
2998      * Create an alternate list from the initial server, but
2999      * don't chain looking for alternates.
3000      */
3001     if (conn->alternate == 0)
3002     {
3003 	/*
3004 	 * free any existing alternates list, allowing the list to
3005 	 * be updated
3006 	 */
3007 	if (conn->alts)
3008 	{
3009 	    free (conn->alts);
3010 	    conn->alts = 0;
3011 	    conn->numAlts = 0;
3012 	}
3013 	if (setup->num_alternates)
3014 	{
3015 	    size_t alt_name_len = setup->alternate_len << 2;
3016 	    alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
3017 			   alt_name_len);
3018 	    if (alts)
3019 	    {
3020 		alt_names = (char *) (setup + 1);
3021 		alt_save = (char *) (alts + setup->num_alternates);
3022 		for (i = 0; i < setup->num_alternates; i++)
3023 		{
3024 		    alts[i].subset = alt_names[0];
3025 		    alt_len = alt_names[1];
3026 		    if (alt_len >= alt_name_len) {
3027 			/*
3028 			 * Length is longer than setup->alternate_len
3029 			 * told us to allocate room for, assume entire
3030 			 * alternate list is corrupted.
3031 			 */
3032 #ifdef DEBUG
3033 			fprintf (stderr,
3034 				 "invalid alt list (length %lx >= %lx)\n",
3035 				 (long) alt_len, (long) alt_name_len);
3036 #endif
3037 			free(alts);
3038 			return FSIO_ERROR;
3039 		    }
3040 		    alts[i].name = alt_save;
3041 		    memcpy (alt_save, alt_names + 2, alt_len);
3042 		    alt_save[alt_len] = '\0';
3043 		    alt_save += alt_len + 1;
3044 		    alt_name_len -= alt_len + 1;
3045 		    alt_names += _fs_pad_length (alt_len + 2);
3046 		}
3047 		conn->numAlts = setup->num_alternates;
3048 		conn->alts = alts;
3049 	    }
3050 	}
3051     }
3052     _fs_done_read (conn, setup_len);
3053     if (setup->status != AuthSuccess)
3054 	return FSIO_ERROR;
3055     return FSIO_READY;
3056 }
3057 
3058 static int
_fs_open_server(FSFpePtr conn)3059 _fs_open_server (FSFpePtr conn)
3060 {
3061     int	    ret;
3062     char    *servername;
3063 
3064     if (conn->alternate == 0)
3065 	servername = conn->servername;
3066     else
3067 	servername = conn->alts[conn->alternate-1].name;
3068     conn->trans_conn = _fs_connect (servername, &ret);
3069     conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
3070     return ret;
3071 }
3072 
3073 static char *
_fs_catalog_name(char * servername)3074 _fs_catalog_name (char *servername)
3075 {
3076     char    *sp;
3077 
3078     sp = strchr (servername, '/');
3079     if (!sp)
3080 	return 0;
3081     return strrchr (sp + 1, '/');
3082 }
3083 
3084 static int
_fs_send_init_packets(FSFpePtr conn)3085 _fs_send_init_packets (FSFpePtr conn)
3086 {
3087     fsSetResolutionReq	    srreq;
3088     fsSetCataloguesReq	    screq;
3089     int			    num_cats,
3090 			    clen;
3091     char		    *catalogues;
3092     char		    *cat;
3093     char		    len;
3094     char		    *end;
3095     int			    num_res;
3096     FontResolutionPtr	    res;
3097 
3098 #define	CATALOGUE_SEP	'+'
3099 
3100     res = GetClientResolutions(&num_res);
3101     if (num_res)
3102     {
3103 	srreq.reqType = FS_SetResolution;
3104 	srreq.num_resolutions = num_res;
3105 	srreq.length = (SIZEOF(fsSetResolutionReq) +
3106 			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
3107 
3108 	_fs_add_req_log(conn, FS_SetResolution);
3109 	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
3110 	    return FSIO_ERROR;
3111 	if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
3112 	    return FSIO_ERROR;
3113     }
3114 
3115     catalogues = 0;
3116     if (conn->alternate != 0)
3117 	catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
3118     if (!catalogues)
3119 	catalogues = _fs_catalog_name (conn->servername);
3120 
3121     if (!catalogues)
3122     {
3123 	conn->has_catalogues = FALSE;
3124 	return FSIO_READY;
3125     }
3126     conn->has_catalogues = TRUE;
3127 
3128     /* turn cats into counted list */
3129     catalogues++;
3130 
3131     cat = catalogues;
3132     num_cats = 0;
3133     clen = 0;
3134     while (*cat)
3135     {
3136 	num_cats++;
3137 	end = strchr(cat, CATALOGUE_SEP);
3138 	if (!end)
3139 	    end = cat + strlen (cat);
3140 	clen += (end - cat) + 1;	/* length byte + string */
3141 	cat = end;
3142     }
3143 
3144     screq.reqType = FS_SetCatalogues;
3145     screq.num_catalogues = num_cats;
3146     screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
3147 
3148     _fs_add_req_log(conn, FS_SetCatalogues);
3149     if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
3150 	return FSIO_ERROR;
3151 
3152     while (*cat)
3153     {
3154 	num_cats++;
3155 	end = strchr(cat, CATALOGUE_SEP);
3156 	if (!end)
3157 	    end = cat + strlen (cat);
3158 	len = end - cat;
3159 	if (_fs_write (conn, &len, 1) != FSIO_READY)
3160 	    return FSIO_ERROR;
3161 	if (_fs_write (conn, cat, (int) len) != FSIO_READY)
3162 	    return FSIO_ERROR;
3163 	cat = end;
3164     }
3165 
3166     if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
3167 	return FSIO_ERROR;
3168 
3169     return FSIO_READY;
3170 }
3171 
3172 static int
_fs_send_cat_sync(FSFpePtr conn)3173 _fs_send_cat_sync (FSFpePtr conn)
3174 {
3175     fsListCataloguesReq	    lcreq;
3176 
3177     /*
3178      * now sync up with the font server, to see if an error was generated
3179      * by a bogus catalogue
3180      */
3181     lcreq.reqType = FS_ListCatalogues;
3182     lcreq.data = 0;
3183     lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
3184     lcreq.maxNames = 0;
3185     lcreq.nbytes = 0;
3186     lcreq.pad2 = 0;
3187     _fs_add_req_log(conn, FS_SetCatalogues);
3188     if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
3189 	return FSIO_ERROR;
3190     conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
3191     return FSIO_READY;
3192 }
3193 
3194 static int
_fs_recv_cat_sync(FSFpePtr conn)3195 _fs_recv_cat_sync (FSFpePtr conn)
3196 {
3197     fsGenericReply  *reply;
3198     fsError	    *error;
3199     int		    err;
3200     int		    ret;
3201 
3202     reply = fs_get_reply (conn, &err);
3203     if (!reply)
3204 	return err;
3205 
3206     ret = FSIO_READY;
3207     if (reply->type == FS_Error)
3208     {
3209 	error = (fsError *) reply;
3210 	if (error->major_opcode == FS_SetCatalogues)
3211 	    ret = FSIO_ERROR;
3212     }
3213     _fs_done_read (conn, reply->length << 2);
3214     return ret;
3215 }
3216 
3217 static void
_fs_close_server(FSFpePtr conn)3218 _fs_close_server (FSFpePtr conn)
3219 {
3220     _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
3221     if (conn->trans_conn)
3222     {
3223 	_FontTransClose (conn->trans_conn);
3224 	conn->trans_conn = 0;
3225 	_fs_io_reinit (conn);
3226     }
3227     if (conn->fs_fd >= 0)
3228     {
3229 	FD_CLR (conn->fs_fd, &_fs_fd_mask);
3230 	conn->fs_fd = -1;
3231     }
3232     conn->fs_conn_state = FS_CONN_UNCONNECTED;
3233 }
3234 
3235 static int
_fs_do_setup_connection(FSFpePtr conn)3236 _fs_do_setup_connection (FSFpePtr conn)
3237 {
3238     int	    ret;
3239 
3240     do
3241     {
3242 #ifdef DEBUG
3243 	fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
3244 #endif
3245 	switch (conn->fs_conn_state) {
3246 	case FS_CONN_UNCONNECTED:
3247 	    ret = _fs_open_server (conn);
3248 	    if (ret == FSIO_BLOCK)
3249 		conn->fs_conn_state = FS_CONN_CONNECTING;
3250 	    break;
3251 	case FS_CONN_CONNECTING:
3252 	    ret = _fs_check_connect (conn);
3253 	    break;
3254 	case FS_CONN_CONNECTED:
3255 	    ret = _fs_send_conn_client_prefix (conn);
3256 	    break;
3257 	case FS_CONN_SENT_PREFIX:
3258 	    ret = _fs_recv_conn_setup (conn);
3259 	    break;
3260 	case FS_CONN_RECV_INIT:
3261 	    ret = _fs_send_init_packets (conn);
3262 	    if (conn->has_catalogues)
3263 		ret = _fs_send_cat_sync (conn);
3264 	    break;
3265 	case FS_CONN_SENT_CAT:
3266 	    if (conn->has_catalogues)
3267 		ret = _fs_recv_cat_sync (conn);
3268 	    else
3269 		ret = FSIO_READY;
3270 	    break;
3271 	default:
3272 	    ret = FSIO_READY;
3273 	    break;
3274 	}
3275 	switch (ret) {
3276 	case FSIO_READY:
3277 	    if (conn->fs_conn_state < FS_CONN_RUNNING)
3278 		conn->fs_conn_state++;
3279 	    break;
3280 	case FSIO_BLOCK:
3281 	    if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
3282 		break;
3283 	    ret = FSIO_ERROR;
3284 	    /* fall through... */
3285 	case FSIO_ERROR:
3286 	    _fs_close_server (conn);
3287 	    /*
3288 	     * Try the next alternate
3289 	     */
3290 	    if (conn->alternate < conn->numAlts)
3291 	    {
3292 		conn->alternate++;
3293 		ret = FSIO_READY;
3294 	    }
3295 	    else
3296 		conn->alternate = 0;
3297 	    break;
3298 	}
3299     } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
3300     if (ret == FSIO_READY)
3301 	conn->generation = ++generationCount;
3302     return ret;
3303 }
3304 
3305 static int
_fs_wait_connect(FSFpePtr conn)3306 _fs_wait_connect (FSFpePtr conn)
3307 {
3308     int	    ret;
3309 
3310     for (;;)
3311     {
3312 	ret = _fs_do_setup_connection (conn);
3313 	if (ret != FSIO_BLOCK)
3314 	    break;
3315 	if (conn->fs_conn_state <= FS_CONN_CONNECTING)
3316 	    ret = _fs_poll_connect (conn->trans_conn, 1000);
3317 	else
3318 	    ret = _fs_wait_for_readable (conn, 1000);
3319 	if (ret == FSIO_ERROR)
3320 	    break;
3321     }
3322     return ret;
3323 }
3324 
3325 /*
3326  * Poll a connection in the process of reconnecting
3327  */
3328 static void
_fs_check_reconnect(FSFpePtr conn)3329 _fs_check_reconnect (FSFpePtr conn)
3330 {
3331     int	    ret;
3332 
3333     ret = _fs_do_setup_connection (conn);
3334     switch (ret) {
3335     case FSIO_READY:
3336 	_fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
3337 	_fs_restart_connection (conn);
3338 	break;
3339     case FSIO_BLOCK:
3340 	break;
3341     case FSIO_ERROR:
3342 	conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
3343 	break;
3344     }
3345 }
3346 
3347 /*
3348  * Start the reconnection process
3349  */
3350 static void
_fs_start_reconnect(FSFpePtr conn)3351 _fs_start_reconnect (FSFpePtr conn)
3352 {
3353     if (conn->blockState & FS_RECONNECTING)
3354 	return;
3355     conn->alternate = 0;
3356     _fs_mark_block (conn, FS_RECONNECTING);
3357     _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
3358     _fs_check_reconnect (conn);
3359 }
3360 
3361 
3362 static FSFpePtr
_fs_init_conn(const char * servername)3363 _fs_init_conn (const char *servername)
3364 {
3365     FSFpePtr	conn;
3366 
3367     conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
3368     if (!conn)
3369 	return 0;
3370     if (!_fs_io_init (conn))
3371     {
3372 	free (conn);
3373 	return 0;
3374     }
3375     conn->servername = (char *) (conn + 1);
3376     conn->fs_conn_state = FS_CONN_UNCONNECTED;
3377     conn->fs_fd = -1;
3378     strcpy (conn->servername, servername);
3379     return conn;
3380 }
3381 
3382 static void
_fs_free_conn(FSFpePtr conn)3383 _fs_free_conn (FSFpePtr conn)
3384 {
3385     _fs_close_server (conn);
3386     _fs_io_fini (conn);
3387     if (conn->alts)
3388 	free (conn->alts);
3389     free (conn);
3390 }
3391 
3392 /*
3393  * called at server init time
3394  */
3395 
3396 void
fs_register_fpe_functions(void)3397 fs_register_fpe_functions(void)
3398 {
3399     RegisterFPEFunctions(fs_name_check,
3400 			 fs_init_fpe,
3401 			 fs_free_fpe,
3402 			 fs_reset_fpe,
3403 			 fs_open_font,
3404 			 fs_close_font,
3405 			 fs_list_fonts,
3406 			 fs_start_list_with_info,
3407 			 fs_next_list_with_info,
3408 			 fs_wakeup,
3409 			 fs_client_died,
3410 			 _fs_load_glyphs,
3411 			 NULL,
3412 			 NULL,
3413 			 NULL);
3414 }
3415