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