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