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