fserve.c revision fd60135f
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 %ld > MAX_REPLY_LENGTH, disconnecting" 653 " from font server\n", (long)rep->length); 654 _fs_connection_died (conn); 655 *error = FSIO_ERROR; 656 return 0; 657 } 658 659 ret = _fs_start_read (conn, rep->length << 2, &buf); 660 if (ret != FSIO_READY) 661 { 662 *error = FSIO_BLOCK; 663 return 0; 664 } 665 666 *error = FSIO_READY; 667 668 return (fsGenericReply *) buf; 669} 670 671static Bool 672fs_reply_ready (FSFpePtr conn) 673{ 674 fsGenericReply *rep; 675 676 if (conn->fs_fd == -1 || !conn->fs_listening) 677 return FALSE; 678 if (fs_data_read (conn) < sizeof (fsGenericReply)) 679 return FALSE; 680 rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove); 681 if (fs_data_read (conn) < rep->length << 2) 682 return FALSE; 683 return TRUE; 684} 685 686static void 687_fs_pending_reply (FSFpePtr conn) 688{ 689 if (!(conn->blockState & FS_PENDING_REPLY)) 690 { 691 _fs_mark_block (conn, FS_PENDING_REPLY); 692 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; 693 } 694} 695 696static void 697_fs_prepare_for_reply (FSFpePtr conn) 698{ 699 _fs_pending_reply (conn); 700 _fs_flush (conn); 701} 702 703/* 704 * Block (for a while) awaiting a complete reply 705 */ 706static int 707fs_await_reply (FSFpePtr conn) 708{ 709 int ret; 710 711 if (conn->blockState & FS_COMPLETE_REPLY) 712 return FSIO_READY; 713 714 while (!fs_get_reply (conn, &ret)) 715 { 716 if (ret != FSIO_BLOCK) 717 return ret; 718 if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY) 719 { 720 _fs_connection_died (conn); 721 return FSIO_ERROR; 722 } 723 } 724 return FSIO_READY; 725} 726 727/* 728 * Process the reply to an OpenBitmapFont request 729 */ 730static int 731fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec) 732{ 733 FSFpePtr conn = (FSFpePtr) fpe->private; 734 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; 735 fsOpenBitmapFontReply *rep; 736 FSBlockDataPtr blockOrig; 737 FSBlockedFontPtr origBfont; 738 int ret; 739 740 rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret); 741 if (!rep || rep->type == FS_Error || 742 (rep->length != LENGTHOF(fsOpenBitmapFontReply))) 743 { 744 if (ret == FSIO_BLOCK) 745 return StillWorking; 746 if (rep) 747 _fs_done_read (conn, rep->length << 2); 748 fs_cleanup_bfont (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 } 2860 crac.length = (sizeof (fsCreateACReq) + authlen) >> 2; 2861 crac.acid = cur->acid; 2862 _fs_add_req_log(conn, FS_CreateAC); 2863 _fs_write(conn, (char *) &crac, sizeof (fsCreateACReq)); 2864 _fs_write_pad(conn, authorizations, authlen); 2865 /* ignore reply; we don't even care about it */ 2866 conn->curacid = 0; 2867 cur->auth_generation = client_auth_generation(client); 2868 } 2869 if (conn->curacid != cur->acid) 2870 { 2871 setac.reqType = FS_SetAuthorization; 2872 setac.pad = 0; 2873 setac.length = sizeof (fsSetAuthorizationReq) >> 2; 2874 setac.id = cur->acid; 2875 _fs_add_req_log(conn, FS_SetAuthorization); 2876 _fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq)); 2877 conn->curacid = cur->acid; 2878 } 2879} 2880 2881/* 2882 * Poll a pending connect 2883 */ 2884 2885static int 2886_fs_check_connect (FSFpePtr conn) 2887{ 2888 int ret; 2889 2890 ret = _fs_poll_connect (conn->trans_conn, 0); 2891 switch (ret) { 2892 case FSIO_READY: 2893 conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn); 2894 conn_start_listening(conn); 2895 break; 2896 case FSIO_BLOCK: 2897 break; 2898 } 2899 return ret; 2900} 2901 2902/* 2903 * Return an FSIO status while waiting for the completed connection 2904 * reply to arrive 2905 */ 2906 2907static fsConnSetup * 2908_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len) 2909{ 2910 int ret; 2911 char *data; 2912 int headlen; 2913 int len; 2914 fsConnSetup *setup; 2915 fsConnSetupAccept *accept; 2916 2917 ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data); 2918 if (ret != FSIO_READY) 2919 { 2920 *error = ret; 2921 return 0; 2922 } 2923 2924 setup = (fsConnSetup *) data; 2925 if (setup->major_version > FS_PROTOCOL) 2926 { 2927 *error = FSIO_ERROR; 2928 return 0; 2929 } 2930 2931 headlen = (SIZEOF (fsConnSetup) + 2932 (setup->alternate_len << 2) + 2933 (setup->auth_len << 2)); 2934 /* On anything but Success, no extra data is sent */ 2935 if (setup->status != AuthSuccess) 2936 { 2937 len = headlen; 2938 } 2939 else 2940 { 2941 ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data); 2942 if (ret != FSIO_READY) 2943 { 2944 *error = ret; 2945 return 0; 2946 } 2947 setup = (fsConnSetup *) data; 2948 accept = (fsConnSetupAccept *) (data + headlen); 2949 len = headlen + (accept->length << 2); 2950 } 2951 ret = _fs_start_read (conn, len, &data); 2952 if (ret != FSIO_READY) 2953 { 2954 *error = ret; 2955 return 0; 2956 } 2957 *setup_len = len; 2958 return (fsConnSetup *) data; 2959} 2960 2961static int 2962_fs_send_conn_client_prefix (FSFpePtr conn) 2963{ 2964 fsConnClientPrefix req; 2965 int endian; 2966 int ret; 2967 2968 /* send setup prefix */ 2969 endian = 1; 2970 if (*(char *) &endian) 2971 req.byteOrder = 'l'; 2972 else 2973 req.byteOrder = 'B'; 2974 2975 req.major_version = FS_PROTOCOL; 2976 req.minor_version = FS_PROTOCOL_MINOR; 2977 2978/* XXX add some auth info here */ 2979 req.num_auths = 0; 2980 req.auth_len = 0; 2981 ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix)); 2982 if (ret != FSIO_READY) 2983 return FSIO_ERROR; 2984 conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout; 2985 return ret; 2986} 2987 2988static int 2989_fs_recv_conn_setup (FSFpePtr conn) 2990{ 2991 int ret = FSIO_ERROR; 2992 fsConnSetup *setup; 2993 FSFpeAltPtr alts; 2994 unsigned int i, alt_len; 2995 int setup_len; 2996 char *alt_save, *alt_names; 2997 2998 setup = _fs_get_conn_setup (conn, &ret, &setup_len); 2999 if (!setup) 3000 return ret; 3001 conn->current_seq = 0; 3002 conn->fsMajorVersion = setup->major_version; 3003 /* 3004 * Create an alternate list from the initial server, but 3005 * don't chain looking for alternates. 3006 */ 3007 if (conn->alternate == 0) 3008 { 3009 /* 3010 * free any existing alternates list, allowing the list to 3011 * be updated 3012 */ 3013 if (conn->alts) 3014 { 3015 free (conn->alts); 3016 conn->alts = 0; 3017 conn->numAlts = 0; 3018 } 3019 if (setup->num_alternates) 3020 { 3021 size_t alt_name_len = setup->alternate_len << 2; 3022 alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) + 3023 alt_name_len); 3024 if (alts) 3025 { 3026 alt_names = (char *) (setup + 1); 3027 alt_save = (char *) (alts + setup->num_alternates); 3028 for (i = 0; i < setup->num_alternates; i++) 3029 { 3030 alts[i].subset = alt_names[0]; 3031 alt_len = alt_names[1]; 3032 if (alt_len >= alt_name_len) { 3033 /* 3034 * Length is longer than setup->alternate_len 3035 * told us to allocate room for, assume entire 3036 * alternate list is corrupted. 3037 */ 3038#ifdef DEBUG 3039 fprintf (stderr, 3040 "invalid alt list (length %lx >= %lx)\n", 3041 (long) alt_len, (long) alt_name_len); 3042#endif 3043 free(alts); 3044 return FSIO_ERROR; 3045 } 3046 alts[i].name = alt_save; 3047 memcpy (alt_save, alt_names + 2, alt_len); 3048 alt_save[alt_len] = '\0'; 3049 alt_save += alt_len + 1; 3050 alt_name_len -= alt_len + 1; 3051 alt_names += _fs_pad_length (alt_len + 2); 3052 } 3053 conn->numAlts = setup->num_alternates; 3054 conn->alts = alts; 3055 } 3056 } 3057 } 3058 _fs_done_read (conn, setup_len); 3059 if (setup->status != AuthSuccess) 3060 return FSIO_ERROR; 3061 return FSIO_READY; 3062} 3063 3064static int 3065_fs_open_server (FSFpePtr conn) 3066{ 3067 int ret; 3068 char *servername; 3069 3070 if (conn->alternate == 0) 3071 servername = conn->servername; 3072 else 3073 servername = conn->alts[conn->alternate-1].name; 3074 conn->trans_conn = _fs_connect (servername, &ret); 3075 conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT; 3076 return ret; 3077} 3078 3079static char * 3080_fs_catalog_name (char *servername) 3081{ 3082 char *sp; 3083 3084 sp = strchr (servername, '/'); 3085 if (!sp) 3086 return 0; 3087 return strrchr (sp + 1, '/'); 3088} 3089 3090static int 3091_fs_send_init_packets (FSFpePtr conn) 3092{ 3093 fsSetResolutionReq srreq; 3094 fsSetCataloguesReq screq; 3095 int num_cats, 3096 clen; 3097 char *catalogues; 3098 char *cat; 3099 char len; 3100 char *end; 3101 int num_res; 3102 FontResolutionPtr res; 3103 3104#define CATALOGUE_SEP '+' 3105 3106 res = GetClientResolutions(&num_res); 3107 if (num_res) 3108 { 3109 srreq.reqType = FS_SetResolution; 3110 srreq.num_resolutions = num_res; 3111 srreq.length = (SIZEOF(fsSetResolutionReq) + 3112 (num_res * SIZEOF(fsResolution)) + 3) >> 2; 3113 3114 _fs_add_req_log(conn, FS_SetResolution); 3115 if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY) 3116 return FSIO_ERROR; 3117 if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY) 3118 return FSIO_ERROR; 3119 } 3120 3121 catalogues = 0; 3122 if (conn->alternate != 0) 3123 catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name); 3124 if (!catalogues) 3125 catalogues = _fs_catalog_name (conn->servername); 3126 3127 if (!catalogues) 3128 { 3129 conn->has_catalogues = FALSE; 3130 return FSIO_READY; 3131 } 3132 conn->has_catalogues = TRUE; 3133 3134 /* turn cats into counted list */ 3135 catalogues++; 3136 3137 cat = catalogues; 3138 num_cats = 0; 3139 clen = 0; 3140 while (*cat) 3141 { 3142 num_cats++; 3143 end = strchr(cat, CATALOGUE_SEP); 3144 if (!end) 3145 end = cat + strlen (cat); 3146 clen += (end - cat) + 1; /* length byte + string */ 3147 cat = end; 3148 } 3149 3150 screq.reqType = FS_SetCatalogues; 3151 screq.num_catalogues = num_cats; 3152 screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2; 3153 3154 _fs_add_req_log(conn, FS_SetCatalogues); 3155 if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY) 3156 return FSIO_ERROR; 3157 3158 while (*cat) 3159 { 3160 num_cats++; 3161 end = strchr(cat, CATALOGUE_SEP); 3162 if (!end) 3163 end = cat + strlen (cat); 3164 len = end - cat; 3165 if (_fs_write (conn, &len, 1) != FSIO_READY) 3166 return FSIO_ERROR; 3167 if (_fs_write (conn, cat, (int) len) != FSIO_READY) 3168 return FSIO_ERROR; 3169 cat = end; 3170 } 3171 3172 if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY) 3173 return FSIO_ERROR; 3174 3175 return FSIO_READY; 3176} 3177 3178static int 3179_fs_send_cat_sync (FSFpePtr conn) 3180{ 3181 fsListCataloguesReq lcreq; 3182 3183 /* 3184 * now sync up with the font server, to see if an error was generated 3185 * by a bogus catalogue 3186 */ 3187 lcreq.reqType = FS_ListCatalogues; 3188 lcreq.data = 0; 3189 lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2; 3190 lcreq.maxNames = 0; 3191 lcreq.nbytes = 0; 3192 lcreq.pad2 = 0; 3193 _fs_add_req_log(conn, FS_SetCatalogues); 3194 if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY) 3195 return FSIO_ERROR; 3196 conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout; 3197 return FSIO_READY; 3198} 3199 3200static int 3201_fs_recv_cat_sync (FSFpePtr conn) 3202{ 3203 fsGenericReply *reply; 3204 fsError *error; 3205 int err; 3206 int ret; 3207 3208 reply = fs_get_reply (conn, &err); 3209 if (!reply) 3210 return err; 3211 3212 ret = FSIO_READY; 3213 if (reply->type == FS_Error) 3214 { 3215 error = (fsError *) reply; 3216 if (error->major_opcode == FS_SetCatalogues) 3217 ret = FSIO_ERROR; 3218 } 3219 _fs_done_read (conn, reply->length << 2); 3220 return ret; 3221} 3222 3223static void 3224_fs_close_server (FSFpePtr conn) 3225{ 3226 _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION); 3227 if (conn->trans_conn) 3228 { 3229 _FontTransClose (conn->trans_conn); 3230 conn->trans_conn = 0; 3231 _fs_io_reinit (conn); 3232 } 3233 if (conn->fs_fd >= 0) 3234 { 3235 conn_stop_listening(conn); 3236 conn->fs_fd = -1; 3237 } 3238 conn->fs_conn_state = FS_CONN_UNCONNECTED; 3239} 3240 3241static int 3242_fs_do_setup_connection (FSFpePtr conn) 3243{ 3244 int ret; 3245 3246 do 3247 { 3248#ifdef DEBUG 3249 fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state); 3250#endif 3251 switch (conn->fs_conn_state) { 3252 case FS_CONN_UNCONNECTED: 3253 ret = _fs_open_server (conn); 3254 if (ret == FSIO_BLOCK) 3255 conn->fs_conn_state = FS_CONN_CONNECTING; 3256 break; 3257 case FS_CONN_CONNECTING: 3258 ret = _fs_check_connect (conn); 3259 break; 3260 case FS_CONN_CONNECTED: 3261 ret = _fs_send_conn_client_prefix (conn); 3262 break; 3263 case FS_CONN_SENT_PREFIX: 3264 ret = _fs_recv_conn_setup (conn); 3265 break; 3266 case FS_CONN_RECV_INIT: 3267 ret = _fs_send_init_packets (conn); 3268 if (conn->has_catalogues) 3269 ret = _fs_send_cat_sync (conn); 3270 break; 3271 case FS_CONN_SENT_CAT: 3272 if (conn->has_catalogues) 3273 ret = _fs_recv_cat_sync (conn); 3274 else 3275 ret = FSIO_READY; 3276 break; 3277 default: 3278 ret = FSIO_READY; 3279 break; 3280 } 3281 switch (ret) { 3282 case FSIO_READY: 3283 if (conn->fs_conn_state < FS_CONN_RUNNING) 3284 conn->fs_conn_state++; 3285 break; 3286 case FSIO_BLOCK: 3287 if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime)) 3288 break; 3289 ret = FSIO_ERROR; 3290 /* fall through... */ 3291 case FSIO_ERROR: 3292 _fs_close_server (conn); 3293 /* 3294 * Try the next alternate 3295 */ 3296 if (conn->alternate < conn->numAlts) 3297 { 3298 conn->alternate++; 3299 ret = FSIO_READY; 3300 } 3301 else 3302 conn->alternate = 0; 3303 break; 3304 } 3305 } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY); 3306 if (ret == FSIO_READY) 3307 conn->generation = ++generationCount; 3308 return ret; 3309} 3310 3311static int 3312_fs_wait_connect (FSFpePtr conn) 3313{ 3314 int ret; 3315 3316 for (;;) 3317 { 3318 ret = _fs_do_setup_connection (conn); 3319 if (ret != FSIO_BLOCK) 3320 break; 3321 if (conn->fs_conn_state <= FS_CONN_CONNECTING) 3322 ret = _fs_poll_connect (conn->trans_conn, 1000); 3323 else 3324 ret = _fs_wait_for_readable (conn, 1000); 3325 if (ret == FSIO_ERROR) 3326 break; 3327 } 3328 return ret; 3329} 3330 3331/* 3332 * Poll a connection in the process of reconnecting 3333 */ 3334static void 3335_fs_check_reconnect (FSFpePtr conn) 3336{ 3337 int ret; 3338 3339 ret = _fs_do_setup_connection (conn); 3340 switch (ret) { 3341 case FSIO_READY: 3342 _fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP); 3343 _fs_restart_connection (conn); 3344 break; 3345 case FSIO_BLOCK: 3346 break; 3347 case FSIO_ERROR: 3348 conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL; 3349 break; 3350 } 3351} 3352 3353/* 3354 * Start the reconnection process 3355 */ 3356static void 3357_fs_start_reconnect (FSFpePtr conn) 3358{ 3359 if (conn->blockState & FS_RECONNECTING) 3360 return; 3361 conn->alternate = 0; 3362 _fs_mark_block (conn, FS_RECONNECTING); 3363 _fs_unmark_block (conn, FS_BROKEN_CONNECTION); 3364 _fs_check_reconnect (conn); 3365} 3366 3367 3368static FSFpePtr 3369_fs_init_conn (const char *servername, FontPathElementPtr fpe) 3370{ 3371 FSFpePtr conn; 3372 3373 conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1); 3374 if (!conn) 3375 return 0; 3376 if (!_fs_io_init (conn)) 3377 { 3378 free (conn); 3379 return 0; 3380 } 3381 conn->servername = (char *) (conn + 1); 3382 conn->fs_conn_state = FS_CONN_UNCONNECTED; 3383 conn->fs_fd = -1; 3384 conn->fpe = fpe; 3385 strcpy (conn->servername, servername); 3386 return conn; 3387} 3388 3389static void 3390_fs_free_conn (FSFpePtr conn) 3391{ 3392 _fs_close_server (conn); 3393 _fs_io_fini (conn); 3394 if (conn->alts) 3395 free (conn->alts); 3396 free (conn); 3397} 3398 3399/* 3400 * called at server init time 3401 */ 3402 3403static const xfont2_fpe_funcs_rec fs_fpe_funcs = { 3404 .version = XFONT2_FPE_FUNCS_VERSION, 3405 .name_check = fs_name_check, 3406 .init_fpe = fs_init_fpe, 3407 .free_fpe = fs_free_fpe, 3408 .reset_fpe = fs_reset_fpe, 3409 .open_font = fs_open_font, 3410 .close_font = fs_close_font, 3411 .list_fonts = fs_list_fonts, 3412 .start_list_fonts_with_info = fs_start_list_with_info, 3413 .list_next_font_with_info = fs_next_list_with_info, 3414 .wakeup_fpe = fs_wakeup, 3415 .client_died = fs_client_died, 3416 .load_glyphs = _fs_load_glyphs, 3417 .start_list_fonts_and_aliases = (StartLaFunc) 0, 3418 .list_next_font_or_alias = (NextLaFunc) 0, 3419 .set_path_hook = (SetPathFunc) 0 3420}; 3421 3422void 3423fs_register_fpe_functions(void) 3424{ 3425 register_fpe_funcs(&fs_fpe_funcs); 3426} 3427