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