fserve.c revision b0d196e1
1/* 2 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 104extern void ErrorF(const char *f, ...); 105 106static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); 107static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); 108static int fs_read_list_info ( FontPathElementPtr fpe, 109 FSBlockDataPtr blockrec ); 110 111extern fd_set _fs_fd_mask; 112 113static void fs_block_handler ( pointer data, OSTimePtr wt, 114 pointer LastSelectMask ); 115static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask ); 116 117/* 118 * List of all FPEs 119 */ 120static FSFpePtr fs_fpes; 121/* 122 * Union of all FPE blockStates 123 */ 124static CARD32 fs_blockState; 125 126static int _fs_restart_connection ( FSFpePtr conn ); 127static void fs_send_query_bitmaps ( FontPathElementPtr fpe, 128 FSBlockDataPtr blockrec ); 129static int fs_send_close_font ( FontPathElementPtr fpe, Font id ); 130static void fs_client_died ( pointer client, FontPathElementPtr fpe ); 131static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync ); 132static void _fs_client_resolution ( FSFpePtr conn ); 133static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error); 134static int fs_await_reply (FSFpePtr conn); 135static void _fs_do_blocked (FSFpePtr conn); 136static void fs_cleanup_bfont (FSBlockedFontPtr bfont); 137 138char _fs_glyph_undefined; 139char _fs_glyph_requested; 140static char _fs_glyph_zero_length; 141 142static int generationCount; 143 144static int FontServerRequestTimeout = 30 * 1000; 145 146static void 147_fs_close_server (FSFpePtr conn); 148 149static FSFpePtr 150_fs_init_conn (const char *servername); 151 152static int 153_fs_wait_connect (FSFpePtr conn); 154 155static int 156_fs_send_init_packets (FSFpePtr conn); 157 158static void 159_fs_check_reconnect (FSFpePtr conn); 160 161static void 162_fs_start_reconnect (FSFpePtr conn); 163 164static void 165_fs_free_conn (FSFpePtr conn); 166 167static int 168fs_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 190static void 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 203static void 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: %u %s %d\n", \ 227 #name, (unsigned) 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 237static Bool 238fs_name_check(const char *name) 239{ 240 /* Just make sure there is a protocol/ prefix */ 241 return (name && *name != '/' && strchr(name, '/')); 242} 243 244static void 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 271static void 272fs_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 */ 292static int 293fs_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 359static int 360fs_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 370static int 371fs_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 401static FSBlockDataPtr 402fs_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 445static void 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 462static void 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 483static void 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 496static int 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 */ 523static void 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 557static void 558fs_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 */ 568static void 569fs_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 */ 603static fsGenericReply * 604fs_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 653static Bool 654fs_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 668static void 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 678static void 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 */ 688static int 689fs_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 */ 712static int 713fs_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 796static Bool 797fs_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 851static int 852fs_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) < %u\n", 919 bufleft, (unsigned) 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 (%u)\n", 933 bufleft, (unsigned) 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 1013static int 1014fs_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) > (%u - %d) / %d\n", 1067 numExtents, (unsigned) 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 1214static 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 1224static int 1225fs_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 1280void 1281_fs_mark_block (FSFpePtr conn, CARD32 mask) 1282{ 1283 conn->blockState |= mask; 1284 fs_blockState |= mask; 1285} 1286 1287void 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 */ 1302static void 1303fs_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 1380static void 1381fs_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 1397static void 1398fs_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 1463static int 1464fs_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 1527void 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 */ 1541static int 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 */ 1561static void 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 1584static void 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 */ 1616static int 1617fs_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 1786static void 1787fs_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 */ 1808static int 1809fs_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 */ 1846static int 1847fs_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 */ 1866static void 1867fs_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 1894static int 1895fs_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 (%u) > bufleft (%ld) / %d\n", 1950 (unsigned) 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 (%u) > bufleft (%ld)\n", 1964 (unsigned) 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 2069bail: 2070 _fs_done_read (conn, rep->length << 2); 2071 return err; 2072} 2073 2074static int 2075fs_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 2164extern pointer __GetServerClient(void); /* This could be any number that 2165 doesn't conflict with existing 2166 client values. */ 2167 2168static int 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 2318int 2319fs_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 2351static int 2352fs_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 2405static int 2406fs_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 2460static int 2461fs_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 */ 2488static int 2489fs_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 (%u * %d) > bufleft (%ld)\n", 2571 (unsigned) 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 (%u) > bufleft (%ld)\n", 2583 (unsigned) 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); 2625done: 2626 _fs_done_read (conn, rep->length << 2); 2627 return err; 2628} 2629 2630/* ARGSUSED */ 2631static int 2632fs_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 */ 2689static int 2690fs_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 2751static void 2752fs_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 2792static void 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 2879static int 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 2901static fsConnSetup * 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 2955static int 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 2982static int 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 3058static int 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 3073static char * 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 3084static int 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 3172static int 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 3194static int 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 3217static void 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 3235static int 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 3305static int 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 */ 3328static void 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 */ 3350static void 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 3362static FSFpePtr 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 3382static void 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 3396void 3397fs_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