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