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