1/*********************************************************** 2 3Copyright 1987, 1989, 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 25Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 44 45******************************************************************/ 46/***************************************************************** 47 * i/o functions 48 * 49 * WriteToClient, ReadRequestFromClient 50 * InsertFakeRequest, ResetCurrentRequest 51 * 52 *****************************************************************/ 53 54#include <X11/Xpoll.h> 55 56#ifdef HAVE_DIX_CONFIG_H 57#include <dix-config.h> 58#endif 59 60#undef DEBUG_COMMUNICATION 61 62#ifdef WIN32 63#include <X11/Xwinsock.h> 64#endif 65#include <stdio.h> 66#define XSERV_t 67#define TRANS_SERVER 68#define TRANS_REOPEN 69#include <X11/Xtrans/Xtrans.h> 70#include <X11/Xmd.h> 71#include <errno.h> 72#if !defined(WIN32) 73#include <sys/uio.h> 74#endif 75#include <X11/X.h> 76#include <X11/Xproto.h> 77#include "os.h" 78#include "osdep.h" 79#include "opaque.h" 80#include "dixstruct.h" 81#include "misc.h" 82 83CallbackListPtr ReplyCallback; 84CallbackListPtr FlushCallback; 85 86typedef struct _connectionInput { 87 struct _connectionInput *next; 88 char *buffer; /* contains current client input */ 89 char *bufptr; /* pointer to current start of data */ 90 int bufcnt; /* count of bytes in buffer */ 91 int lenLastReq; 92 int size; 93 unsigned int ignoreBytes; /* bytes to ignore before the next request */ 94} ConnectionInput; 95 96typedef struct _connectionOutput { 97 struct _connectionOutput *next; 98 unsigned char *buf; 99 int size; 100 int count; 101} ConnectionOutput; 102 103static ConnectionInputPtr AllocateInputBuffer(void); 104static ConnectionOutputPtr AllocateOutputBuffer(void); 105 106static Bool CriticalOutputPending; 107static int timesThisConnection = 0; 108static ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL; 109static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL; 110static OsCommPtr AvailableInput = (OsCommPtr) NULL; 111 112#define get_req_len(req,cli) ((cli)->swapped ? \ 113 bswap_16((req)->length) : (req)->length) 114 115#include <X11/extensions/bigreqsproto.h> 116 117#define get_big_req_len(req,cli) ((cli)->swapped ? \ 118 bswap_32(((xBigReq *)(req))->length) : \ 119 ((xBigReq *)(req))->length) 120 121#define BUFSIZE 16384 122#define BUFWATERMARK 32768 123 124/* 125 * A lot of the code in this file manipulates a ConnectionInputPtr: 126 * 127 * ----------------------------------------------- 128 * |------- bufcnt ------->| | | 129 * | |- gotnow ->| | | 130 * | |-------- needed ------>| | 131 * |-----------+--------- size --------+---------->| 132 * ----------------------------------------------- 133 * ^ ^ 134 * | | 135 * buffer bufptr 136 * 137 * buffer is a pointer to the start of the buffer. 138 * bufptr points to the start of the current request. 139 * bufcnt counts how many bytes are in the buffer. 140 * size is the size of the buffer in bytes. 141 * 142 * In several of the functions, gotnow and needed are local variables 143 * that do the following: 144 * 145 * gotnow is the number of bytes of the request that we're 146 * trying to read that are currently in the buffer. 147 * Typically, gotnow = (buffer + bufcnt) - bufptr 148 * 149 * needed = the length of the request that we're trying to 150 * read. Watch out: needed sometimes counts bytes and sometimes 151 * counts CARD32's. 152 */ 153 154/***************************************************************** 155 * ReadRequestFromClient 156 * Returns one request in client->requestBuffer. The request 157 * length will be in client->req_len. Return status is: 158 * 159 * > 0 if successful, specifies length in bytes of the request 160 * = 0 if entire request is not yet available 161 * < 0 if client should be terminated 162 * 163 * The request returned must be contiguous so that it can be 164 * cast in the dispatcher to the correct request type. Because requests 165 * are variable length, ReadRequestFromClient() must look at the first 4 166 * or 8 bytes of a request to determine the length (the request length is 167 * in the 3rd and 4th bytes of the request unless it is a Big Request 168 * (see the Big Request Extension), in which case the 3rd and 4th bytes 169 * are zero and the following 4 bytes are the request length. 170 * 171 * Note: in order to make the server scheduler (WaitForSomething()) 172 * "fair", the ClientsWithInput mask is used. This mask tells which 173 * clients have FULL requests left in their buffers. Clients with 174 * partial requests require a read. Basically, client buffers 175 * are drained before select() is called again. But, we can't keep 176 * reading from a client that is sending buckets of data (or has 177 * a partial request) because others clients need to be scheduled. 178 *****************************************************************/ 179 180static void 181YieldControl(void) 182{ 183 isItTimeToYield = TRUE; 184 timesThisConnection = 0; 185} 186 187static void 188YieldControlNoInput(ClientPtr client) 189{ 190 OsCommPtr oc = client->osPrivate; 191 YieldControl(); 192 if (oc->trans_conn) 193 ospoll_reset_events(server_poll, oc->fd); 194} 195 196static void 197YieldControlDeath(void) 198{ 199 timesThisConnection = 0; 200} 201 202/* If an input buffer was empty, either free it if it is too big or link it 203 * into our list of free input buffers. This means that different clients can 204 * share the same input buffer (at different times). This was done to save 205 * memory. 206 */ 207static void 208NextAvailableInput(OsCommPtr oc) 209{ 210 if (AvailableInput) { 211 if (AvailableInput != oc) { 212 ConnectionInputPtr aci = AvailableInput->input; 213 214 if (aci->size > BUFWATERMARK) { 215 free(aci->buffer); 216 free(aci); 217 } 218 else { 219 aci->next = FreeInputs; 220 FreeInputs = aci; 221 } 222 AvailableInput->input = NULL; 223 } 224 AvailableInput = NULL; 225 } 226} 227 228int 229ReadRequestFromClient(ClientPtr client) 230{ 231 OsCommPtr oc = (OsCommPtr) client->osPrivate; 232 ConnectionInputPtr oci = oc->input; 233 unsigned int gotnow, needed; 234 int result; 235 register xReq *request; 236 Bool need_header; 237 Bool move_header; 238 239 NextAvailableInput(oc); 240 241 /* make sure we have an input buffer */ 242 243 if (!oci) { 244 if ((oci = FreeInputs)) { 245 FreeInputs = oci->next; 246 } 247 else if (!(oci = AllocateInputBuffer())) { 248 YieldControlDeath(); 249 return -1; 250 } 251 oc->input = oci; 252 } 253 254#if XTRANS_SEND_FDS 255 /* Discard any unused file descriptors */ 256 while (client->req_fds > 0) { 257 int req_fd = ReadFdFromClient(client); 258 if (req_fd >= 0) 259 close(req_fd); 260 } 261#endif 262 /* advance to start of next request */ 263 264 oci->bufptr += oci->lenLastReq; 265 266 need_header = FALSE; 267 move_header = FALSE; 268 gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 269 270 if (oci->ignoreBytes > 0) { 271 if (oci->ignoreBytes > oci->size) 272 needed = oci->size; 273 else 274 needed = oci->ignoreBytes; 275 } 276 else if (gotnow < sizeof(xReq)) { 277 /* We don't have an entire xReq yet. Can't tell how big 278 * the request will be until we get the whole xReq. 279 */ 280 needed = sizeof(xReq); 281 need_header = TRUE; 282 } 283 else { 284 /* We have a whole xReq. We can tell how big the whole 285 * request will be unless it is a Big Request. 286 */ 287 request = (xReq *) oci->bufptr; 288 needed = get_req_len(request, client); 289 if (!needed && client->big_requests) { 290 /* It's a Big Request. */ 291 move_header = TRUE; 292 if (gotnow < sizeof(xBigReq)) { 293 /* Still need more data to tell just how big. */ 294 needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */ 295 need_header = TRUE; 296 } 297 else 298 needed = get_big_req_len(request, client); 299 } 300 client->req_len = needed; 301 if (needed > MAXINT >> 2) { 302 /* Check for potential integer overflow */ 303 return -(BadLength); 304 } 305 needed <<= 2; /* needed is in bytes now */ 306 } 307 if (gotnow < needed) { 308 /* Need to read more data, either so that we can get a 309 * complete xReq (if need_header is TRUE), a complete 310 * xBigReq (if move_header is TRUE), or the rest of the 311 * request (if need_header and move_header are both FALSE). 312 */ 313 314 oci->lenLastReq = 0; 315 if (needed > maxBigRequestSize << 2) { 316 /* request is too big for us to handle */ 317 /* 318 * Mark the rest of it as needing to be ignored, and then return 319 * the full size. Dispatch() will turn it into a BadLength error. 320 */ 321 oci->ignoreBytes = needed - gotnow; 322 oci->lenLastReq = gotnow; 323 return needed; 324 } 325 if ((gotnow == 0) || ((oci->bufptr - oci->buffer + needed) > oci->size)) { 326 /* no data, or the request is too big to fit in the buffer */ 327 328 if ((gotnow > 0) && (oci->bufptr != oci->buffer)) 329 /* save the data we've already read */ 330 memmove(oci->buffer, oci->bufptr, gotnow); 331 if (needed > oci->size) { 332 /* make buffer bigger to accommodate request */ 333 char *ibuf; 334 335 ibuf = (char *) realloc(oci->buffer, needed); 336 if (!ibuf) { 337 YieldControlDeath(); 338 return -1; 339 } 340 oci->size = needed; 341 oci->buffer = ibuf; 342 } 343 oci->bufptr = oci->buffer; 344 oci->bufcnt = gotnow; 345 } 346 /* XXX this is a workaround. This function is sometimes called 347 * after the trans_conn has been freed. In this case trans_conn 348 * will be null. Really ought to restructure things so that we 349 * never get here in those circumstances. 350 */ 351 if (!oc->trans_conn) { 352 /* treat as if an error occurred on the read, which is what 353 * used to happen 354 */ 355 YieldControlDeath(); 356 return -1; 357 } 358 result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, 359 oci->size - oci->bufcnt); 360 if (result <= 0) { 361 if ((result < 0) && ETEST(errno)) { 362 mark_client_not_ready(client); 363#if defined(SVR4) && defined(__i386__) && !defined(__sun) 364 if (0) 365#endif 366 { 367 YieldControlNoInput(client); 368 return 0; 369 } 370 } 371 YieldControlDeath(); 372 return -1; 373 } 374 oci->bufcnt += result; 375 gotnow += result; 376 /* free up some space after huge requests */ 377 if ((oci->size > BUFWATERMARK) && 378 (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) { 379 char *ibuf; 380 381 ibuf = (char *) realloc(oci->buffer, BUFSIZE); 382 if (ibuf) { 383 oci->size = BUFSIZE; 384 oci->buffer = ibuf; 385 oci->bufptr = ibuf + oci->bufcnt - gotnow; 386 } 387 } 388 if (need_header && gotnow >= needed) { 389 /* We wanted an xReq, now we've gotten it. */ 390 request = (xReq *) oci->bufptr; 391 needed = get_req_len(request, client); 392 if (!needed && client->big_requests) { 393 move_header = TRUE; 394 if (gotnow < sizeof(xBigReq)) 395 needed = bytes_to_int32(sizeof(xBigReq)); 396 else 397 needed = get_big_req_len(request, client); 398 } 399 client->req_len = needed; 400 if (needed > MAXINT >> 2) 401 return -(BadLength); 402 needed <<= 2; 403 } 404 if (gotnow < needed) { 405 /* Still don't have enough; punt. */ 406 YieldControlNoInput(client); 407 return 0; 408 } 409 } 410 if (needed == 0) { 411 if (client->big_requests) 412 needed = sizeof(xBigReq); 413 else 414 needed = sizeof(xReq); 415 } 416 417 /* If there are bytes to ignore, ignore them now. */ 418 419 if (oci->ignoreBytes > 0) { 420 assert(needed == oci->ignoreBytes || needed == oci->size); 421 /* 422 * The _XSERVTransRead call above may return more or fewer bytes than we 423 * want to ignore. Ignore the smaller of the two sizes. 424 */ 425 if (gotnow < needed) { 426 oci->ignoreBytes -= gotnow; 427 oci->bufptr += gotnow; 428 gotnow = 0; 429 } 430 else { 431 oci->ignoreBytes -= needed; 432 oci->bufptr += needed; 433 gotnow -= needed; 434 } 435 needed = 0; 436 } 437 438 oci->lenLastReq = needed; 439 440 /* 441 * Check to see if client has at least one whole request in the 442 * buffer beyond the request we're returning to the caller. 443 * If there is only a partial request, treat like buffer 444 * is empty so that select() will be called again and other clients 445 * can get into the queue. 446 */ 447 448 gotnow -= needed; 449 if (!gotnow && !oci->ignoreBytes) 450 AvailableInput = oc; 451 if (move_header) { 452 if (client->req_len < bytes_to_int32(sizeof(xBigReq) - sizeof(xReq))) { 453 YieldControlDeath(); 454 return -1; 455 } 456 457 request = (xReq *) oci->bufptr; 458 oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); 459 *(xReq *) oci->bufptr = *request; 460 oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); 461 client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq)); 462 } 463 client->requestBuffer = (void *) oci->bufptr; 464#ifdef DEBUG_COMMUNICATION 465 { 466 xReq *req = client->requestBuffer; 467 468 ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", 469 client->index, req->reqType, req->data, req->length); 470 } 471#endif 472 return needed; 473} 474 475int 476ReadFdFromClient(ClientPtr client) 477{ 478 int fd = -1; 479 480#if XTRANS_SEND_FDS 481 if (client->req_fds > 0) { 482 OsCommPtr oc = (OsCommPtr) client->osPrivate; 483 484 --client->req_fds; 485 fd = _XSERVTransRecvFd(oc->trans_conn); 486 } else 487 LogMessage(X_ERROR, "Request asks for FD without setting req_fds\n"); 488#endif 489 490 return fd; 491} 492 493int 494WriteFdToClient(ClientPtr client, int fd, Bool do_close) 495{ 496#if XTRANS_SEND_FDS 497 OsCommPtr oc = (OsCommPtr) client->osPrivate; 498 499 return _XSERVTransSendFd(oc->trans_conn, fd, do_close); 500#else 501 return -1; 502#endif 503} 504 505/***************************************************************** 506 * InsertFakeRequest 507 * Splice a consed up (possibly partial) request in as the next request. 508 * 509 **********************/ 510 511Bool 512InsertFakeRequest(ClientPtr client, char *data, int count) 513{ 514 OsCommPtr oc = (OsCommPtr) client->osPrivate; 515 ConnectionInputPtr oci = oc->input; 516 int gotnow, moveup; 517 518 NextAvailableInput(oc); 519 520 if (!oci) { 521 if ((oci = FreeInputs)) 522 FreeInputs = oci->next; 523 else if (!(oci = AllocateInputBuffer())) 524 return FALSE; 525 oc->input = oci; 526 } 527 oci->bufptr += oci->lenLastReq; 528 oci->lenLastReq = 0; 529 gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 530 if ((gotnow + count) > oci->size) { 531 char *ibuf; 532 533 ibuf = (char *) realloc(oci->buffer, gotnow + count); 534 if (!ibuf) 535 return FALSE; 536 oci->size = gotnow + count; 537 oci->buffer = ibuf; 538 oci->bufptr = ibuf + oci->bufcnt - gotnow; 539 } 540 moveup = count - (oci->bufptr - oci->buffer); 541 if (moveup > 0) { 542 if (gotnow > 0) 543 memmove(oci->bufptr + moveup, oci->bufptr, gotnow); 544 oci->bufptr += moveup; 545 oci->bufcnt += moveup; 546 } 547 memmove(oci->bufptr - count, data, count); 548 oci->bufptr -= count; 549 gotnow += count; 550 if ((gotnow >= sizeof(xReq)) && 551 (gotnow >= (int) (get_req_len((xReq *) oci->bufptr, client) << 2))) 552 mark_client_ready(client); 553 else 554 YieldControlNoInput(client); 555 return TRUE; 556} 557 558/***************************************************************** 559 * ResetRequestFromClient 560 * Reset to reexecute the current request, and yield. 561 * 562 **********************/ 563 564void 565ResetCurrentRequest(ClientPtr client) 566{ 567 OsCommPtr oc = (OsCommPtr) client->osPrivate; 568 569 /* ignore dying clients */ 570 if (!oc) 571 return; 572 573 register ConnectionInputPtr oci = oc->input; 574 register xReq *request; 575 int gotnow, needed; 576 577 if (AvailableInput == oc) 578 AvailableInput = (OsCommPtr) NULL; 579 oci->lenLastReq = 0; 580 gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 581 if (gotnow < sizeof(xReq)) { 582 YieldControlNoInput(client); 583 } 584 else { 585 request = (xReq *) oci->bufptr; 586 needed = get_req_len(request, client); 587 if (!needed && client->big_requests) { 588 oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); 589 *(xReq *) oci->bufptr = *request; 590 ((xBigReq *) oci->bufptr)->length = client->req_len; 591 if (client->swapped) { 592 swapl(&((xBigReq *) oci->bufptr)->length); 593 } 594 } 595 if (gotnow >= (needed << 2)) { 596 if (listen_to_client(client)) 597 mark_client_ready(client); 598 YieldControl(); 599 } 600 else 601 YieldControlNoInput(client); 602 } 603} 604 605 /******************** 606 * FlushAllOutput() 607 * Flush all clients with output. However, if some client still 608 * has input in the queue (more requests), then don't flush. This 609 * will prevent the output queue from being flushed every time around 610 * the round robin queue. Now, some say that it SHOULD be flushed 611 * every time around, but... 612 * 613 **********************/ 614 615void 616FlushAllOutput(void) 617{ 618 OsCommPtr oc; 619 register ClientPtr client, tmp; 620 Bool newoutput = NewOutputPending; 621 622 if (!newoutput) 623 return; 624 625 /* 626 * It may be that some client still has critical output pending, 627 * but he is not yet ready to receive it anyway, so we will 628 * simply wait for the select to tell us when he's ready to receive. 629 */ 630 CriticalOutputPending = FALSE; 631 NewOutputPending = FALSE; 632 633 xorg_list_for_each_entry_safe(client, tmp, &output_pending_clients, output_pending) { 634 if (client->clientGone) 635 continue; 636 if (!client_is_ready(client)) { 637 oc = (OsCommPtr) client->osPrivate; 638 (void) FlushClient(client, oc, (char *) NULL, 0); 639 } else 640 NewOutputPending = TRUE; 641 } 642} 643 644void 645FlushIfCriticalOutputPending(void) 646{ 647 if (CriticalOutputPending) 648 FlushAllOutput(); 649} 650 651void 652SetCriticalOutputPending(void) 653{ 654 CriticalOutputPending = TRUE; 655} 656 657/***************** 658 * AbortClient: 659 * When a write error occurs to a client, close 660 * the connection and clean things up. Mark 661 * the client as 'ready' so that the server will 662 * try to read from it again, notice that the fd is 663 * closed and clean up from there. 664 *****************/ 665 666static void 667AbortClient(ClientPtr client) 668{ 669 OsCommPtr oc = client->osPrivate; 670 671 if (oc->trans_conn) { 672 CloseDownFileDescriptor(oc); 673 mark_client_ready(client); 674 } 675} 676 677/***************** 678 * WriteToClient 679 * Copies buf into ClientPtr.buf if it fits (with padding), else 680 * flushes ClientPtr.buf and buf to client. As of this writing, 681 * every use of WriteToClient is cast to void, and the result 682 * is ignored. Potentially, this could be used by requests 683 * that are sending several chunks of data and want to break 684 * out of a loop on error. Thus, we will leave the type of 685 * this routine as int. 686 *****************/ 687 688int 689WriteToClient(ClientPtr who, int count, const void *__buf) 690{ 691 OsCommPtr oc; 692 ConnectionOutputPtr oco; 693 int padBytes; 694 const char *buf = __buf; 695 696 BUG_RETURN_VAL_MSG(in_input_thread(), 0, 697 "******** %s called from input thread *********\n", __func__); 698 699#ifdef DEBUG_COMMUNICATION 700 Bool multicount = FALSE; 701#endif 702 if (!count || !who || who == serverClient || who->clientGone) 703 return 0; 704 oc = who->osPrivate; 705 oco = oc->output; 706#ifdef DEBUG_COMMUNICATION 707 { 708 char info[128]; 709 xError *err; 710 xGenericReply *rep; 711 xEvent *ev; 712 713 if (!who->replyBytesRemaining) { 714 switch (buf[0]) { 715 case X_Reply: 716 rep = (xGenericReply *) buf; 717 if (rep->sequenceNumber == who->sequence) { 718 snprintf(info, 127, "Xreply: type: 0x%x data: 0x%x " 719 "len: %i seq#: 0x%x", rep->type, rep->data1, 720 rep->length, rep->sequenceNumber); 721 multicount = TRUE; 722 } 723 break; 724 case X_Error: 725 err = (xError *) buf; 726 snprintf(info, 127, "Xerror: Code: 0x%x resID: 0x%x maj: 0x%x " 727 "min: %x", err->errorCode, err->resourceID, 728 err->minorCode, err->majorCode); 729 break; 730 default: 731 if ((buf[0] & 0x7f) == KeymapNotify) 732 snprintf(info, 127, "KeymapNotifyEvent: %i", buf[0]); 733 else { 734 ev = (xEvent *) buf; 735 snprintf(info, 127, "XEvent: type: 0x%x detail: 0x%x " 736 "seq#: 0x%x", ev->u.u.type, ev->u.u.detail, 737 ev->u.u.sequenceNumber); 738 } 739 } 740 ErrorF("REPLY: ClientIDX: %i %s\n", who->index, info); 741 } 742 else 743 multicount = TRUE; 744 } 745#endif 746 747 if (!oco) { 748 if ((oco = FreeOutputs)) { 749 FreeOutputs = oco->next; 750 } 751 else if (!(oco = AllocateOutputBuffer())) { 752 AbortClient(who); 753 MarkClientException(who); 754 return -1; 755 } 756 oc->output = oco; 757 } 758 759 padBytes = padding_for_int32(count); 760 761 if (ReplyCallback) { 762 ReplyInfoRec replyinfo; 763 764 replyinfo.client = who; 765 replyinfo.replyData = buf; 766 replyinfo.dataLenBytes = count + padBytes; 767 replyinfo.padBytes = padBytes; 768 if (who->replyBytesRemaining) { /* still sending data of an earlier reply */ 769 who->replyBytesRemaining -= count + padBytes; 770 replyinfo.startOfReply = FALSE; 771 replyinfo.bytesRemaining = who->replyBytesRemaining; 772 CallCallbacks((&ReplyCallback), (void *) &replyinfo); 773 } 774 else if (who->clientState == ClientStateRunning && buf[0] == X_Reply) { /* start of new reply */ 775 CARD32 replylen; 776 unsigned long bytesleft; 777 778 replylen = ((const xGenericReply *) buf)->length; 779 if (who->swapped) 780 swapl(&replylen); 781 bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; 782 replyinfo.startOfReply = TRUE; 783 replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; 784 CallCallbacks((&ReplyCallback), (void *) &replyinfo); 785 } 786 } 787#ifdef DEBUG_COMMUNICATION 788 else if (multicount) { 789 if (who->replyBytesRemaining) { 790 who->replyBytesRemaining -= (count + padBytes); 791 } 792 else { 793 CARD32 replylen; 794 795 replylen = ((xGenericReply *) buf)->length; 796 who->replyBytesRemaining = 797 (replylen * 4) + SIZEOF(xReply) - count - padBytes; 798 } 799 } 800#endif 801 if (oco->count == 0 || oco->count + count + padBytes > oco->size) { 802 output_pending_clear(who); 803 if (!any_output_pending()) { 804 CriticalOutputPending = FALSE; 805 NewOutputPending = FALSE; 806 } 807 808 return FlushClient(who, oc, buf, count); 809 } 810 811 NewOutputPending = TRUE; 812 output_pending_mark(who); 813 memmove((char *) oco->buf + oco->count, buf, count); 814 oco->count += count; 815 if (padBytes) { 816 memset(oco->buf + oco->count, '\0', padBytes); 817 oco->count += padBytes; 818 } 819 return count; 820} 821 822 /******************** 823 * FlushClient() 824 * If the client isn't keeping up with us, then we try to continue 825 * buffering the data and set the appropriate bit in ClientsWritable 826 * (which is used by WaitFor in the select). If the connection yields 827 * a permanent error, or we can't allocate any more space, we then 828 * close the connection. 829 * 830 **********************/ 831 832int 833FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) 834{ 835 ConnectionOutputPtr oco = oc->output; 836 XtransConnInfo trans_conn = oc->trans_conn; 837 struct iovec iov[3]; 838 static char padBuffer[3]; 839 const char *extraBuf = __extraBuf; 840 long written; 841 long padsize; 842 long notWritten; 843 long todo; 844 845 if (!oco) 846 return 0; 847 written = 0; 848 padsize = padding_for_int32(extraCount); 849 notWritten = oco->count + extraCount + padsize; 850 if (!notWritten) 851 return 0; 852 853 if (FlushCallback) 854 CallCallbacks(&FlushCallback, who); 855 856 todo = notWritten; 857 while (notWritten) { 858 long before = written; /* amount of whole thing written */ 859 long remain = todo; /* amount to try this time, <= notWritten */ 860 int i = 0; 861 long len; 862 863 /* You could be very general here and have "in" and "out" iovecs 864 * and write a loop without using a macro, but what the heck. This 865 * translates to: 866 * 867 * how much of this piece is new? 868 * if more new then we are trying this time, clamp 869 * if nothing new 870 * then bump down amount already written, for next piece 871 * else put new stuff in iovec, will need all of next piece 872 * 873 * Note that todo had better be at least 1 or else we'll end up 874 * writing 0 iovecs. 875 */ 876#define InsertIOV(pointer, length) \ 877 len = (length) - before; \ 878 if (len > remain) \ 879 len = remain; \ 880 if (len <= 0) { \ 881 before = (-len); \ 882 } else { \ 883 iov[i].iov_len = len; \ 884 iov[i].iov_base = (pointer) + before; \ 885 i++; \ 886 remain -= len; \ 887 before = 0; \ 888 } 889 890 InsertIOV((char *) oco->buf, oco->count) 891 InsertIOV((char *) extraBuf, extraCount) 892 InsertIOV(padBuffer, padsize) 893 894 errno = 0; 895 if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) { 896 written += len; 897 notWritten -= len; 898 todo = notWritten; 899 } 900 else if (ETEST(errno) 901#ifdef SUNSYSV /* check for another brain-damaged OS bug */ 902 || (errno == 0) 903#endif 904#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ 905 || ((errno == EMSGSIZE) && (todo == 1)) 906#endif 907 ) { 908 /* If we've arrived here, then the client is stuffed to the gills 909 and not ready to accept more. Make a note of it and buffer 910 the rest. */ 911 output_pending_mark(who); 912 913 if (written < oco->count) { 914 if (written > 0) { 915 oco->count -= written; 916 memmove((char *) oco->buf, 917 (char *) oco->buf + written, oco->count); 918 written = 0; 919 } 920 } 921 else { 922 written -= oco->count; 923 oco->count = 0; 924 } 925 926 if (notWritten > oco->size) { 927 unsigned char *obuf = NULL; 928 929 if (notWritten + BUFSIZE <= INT_MAX) { 930 obuf = realloc(oco->buf, notWritten + BUFSIZE); 931 } 932 if (!obuf) { 933 AbortClient(who); 934 MarkClientException(who); 935 oco->count = 0; 936 return -1; 937 } 938 oco->size = notWritten + BUFSIZE; 939 oco->buf = obuf; 940 } 941 942 /* If the amount written extended into the padBuffer, then the 943 difference "extraCount - written" may be less than 0 */ 944 if ((len = extraCount - written) > 0) 945 memmove((char *) oco->buf + oco->count, 946 extraBuf + written, len); 947 948 oco->count = notWritten; /* this will include the pad */ 949 ospoll_listen(server_poll, oc->fd, X_NOTIFY_WRITE); 950 951 /* return only the amount explicitly requested */ 952 return extraCount; 953 } 954#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ 955 else if (errno == EMSGSIZE) { 956 todo >>= 1; 957 } 958#endif 959 else { 960 AbortClient(who); 961 MarkClientException(who); 962 oco->count = 0; 963 return -1; 964 } 965 } 966 967 /* everything was flushed out */ 968 oco->count = 0; 969 output_pending_clear(who); 970 971 if (oco->size > BUFWATERMARK) { 972 free(oco->buf); 973 free(oco); 974 } 975 else { 976 oco->next = FreeOutputs; 977 FreeOutputs = oco; 978 } 979 oc->output = (ConnectionOutputPtr) NULL; 980 return extraCount; /* return only the amount explicitly requested */ 981} 982 983static ConnectionInputPtr 984AllocateInputBuffer(void) 985{ 986 ConnectionInputPtr oci; 987 988 oci = malloc(sizeof(ConnectionInput)); 989 if (!oci) 990 return NULL; 991 oci->buffer = malloc(BUFSIZE); 992 if (!oci->buffer) { 993 free(oci); 994 return NULL; 995 } 996 oci->size = BUFSIZE; 997 oci->bufptr = oci->buffer; 998 oci->bufcnt = 0; 999 oci->lenLastReq = 0; 1000 oci->ignoreBytes = 0; 1001 return oci; 1002} 1003 1004static ConnectionOutputPtr 1005AllocateOutputBuffer(void) 1006{ 1007 ConnectionOutputPtr oco; 1008 1009 oco = malloc(sizeof(ConnectionOutput)); 1010 if (!oco) 1011 return NULL; 1012 oco->buf = calloc(1, BUFSIZE); 1013 if (!oco->buf) { 1014 free(oco); 1015 return NULL; 1016 } 1017 oco->size = BUFSIZE; 1018 oco->count = 0; 1019 return oco; 1020} 1021 1022void 1023FreeOsBuffers(OsCommPtr oc) 1024{ 1025 ConnectionInputPtr oci; 1026 ConnectionOutputPtr oco; 1027 1028 if (AvailableInput == oc) 1029 AvailableInput = (OsCommPtr) NULL; 1030 if ((oci = oc->input)) { 1031 if (FreeInputs) { 1032 free(oci->buffer); 1033 free(oci); 1034 } 1035 else { 1036 FreeInputs = oci; 1037 oci->next = (ConnectionInputPtr) NULL; 1038 oci->bufptr = oci->buffer; 1039 oci->bufcnt = 0; 1040 oci->lenLastReq = 0; 1041 oci->ignoreBytes = 0; 1042 } 1043 } 1044 if ((oco = oc->output)) { 1045 if (FreeOutputs) { 1046 free(oco->buf); 1047 free(oco); 1048 } 1049 else { 1050 FreeOutputs = oco; 1051 oco->next = (ConnectionOutputPtr) NULL; 1052 oco->count = 0; 1053 } 1054 } 1055} 1056 1057void 1058ResetOsBuffers(void) 1059{ 1060 ConnectionInputPtr oci; 1061 ConnectionOutputPtr oco; 1062 1063 while ((oci = FreeInputs)) { 1064 FreeInputs = oci->next; 1065 free(oci->buffer); 1066 free(oci); 1067 } 1068 while ((oco = FreeOutputs)) { 1069 FreeOutputs = oco->next; 1070 free(oco->buf); 1071 free(oco); 1072 } 1073} 1074