|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, ! 3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts. ! 4: ! 5: All Rights Reserved ! 6: ! 7: Permission to use, copy, modify, and distribute this software and its ! 8: documentation for any purpose and without fee is hereby granted, ! 9: provided that the above copyright notice appear in all copies and that ! 10: both that copyright notice and this permission notice appear in ! 11: supporting documentation, and that the names of Digital or MIT not be ! 12: used in advertising or publicity pertaining to distribution of the ! 13: software without specific, written prior permission. ! 14: ! 15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 21: SOFTWARE. ! 22: ! 23: ******************************************************************/ ! 24: /* $XConsortium: io.c,v 1.49 88/09/06 15:50:44 jim Exp $ */ ! 25: /***************************************************************** ! 26: * i/o functions ! 27: * ! 28: * WriteToClient, ReadRequestFromClient ! 29: * ! 30: *****************************************************************/ ! 31: ! 32: #include <stdio.h> ! 33: #include "Xos.h" ! 34: #include "Xmd.h" ! 35: #include <errno.h> ! 36: #include <sys/param.h> ! 37: #include <sys/types.h> ! 38: #include <sys/uio.h> ! 39: #include "X.h" ! 40: #include "Xproto.h" ! 41: #include "os.h" ! 42: #include "osdep.h" ! 43: #include "opaque.h" ! 44: #include "dixstruct.h" ! 45: #include "misc.h" ! 46: ! 47: #ifdef ISOCONN ! 48: #include <isode/tsap.h> ! 49: #endif /* ISOCONN */ ! 50: ! 51: extern long ClientsWithInput[]; ! 52: extern long ClientsWriteBlocked[]; ! 53: extern long OutputPending[]; ! 54: extern long OutputBufferSize; ! 55: extern ClientPtr ConnectionTranslation[]; ! 56: extern Bool NewOutputPending; ! 57: extern Bool AnyClientsWriteBlocked; ! 58: static Bool CriticalOutputPending; ! 59: static int timesThisConnection = 0; ! 60: ! 61: extern int errno; ! 62: ! 63: #define request_length(req, cli) ((cli->swapped ? \ ! 64: lswaps((req)->length) : (req)->length) << 2) ! 65: #define MAX_TIMES_PER 10 ! 66: ! 67: #ifdef ISOCONN ! 68: /* ! 69: * Convenience Routines ! 70: */ ! 71: TWriteToClient(sd, buf, len) ! 72: int sd, len; ! 73: char *buf; ! 74: { ! 75: struct TSAPdisconnect tds; ! 76: struct TSAPdisconnect *td = &tds; ! 77: ! 78: if (TDataRequest(sd, buf, len, td) == NOTOK){ ! 79: if (errno != EWOULDBLOCK) ! 80: fprintf(stderr, "TWriteToClient: %s\n", td->td_reason); ! 81: } ! 82: } ! 83: /* ! 84: * sd = transport descriptor ! 85: * iov is iovec of iovcnt buffers ! 86: */ ! 87: TWritevToClient(sd, iov, iovcnt) ! 88: int sd, iovcnt; ! 89: struct iovec *iov; ! 90: { ! 91: int i, ret, tot = 0; ! 92: struct udvec uv[64], *uvp = uv; ! 93: struct TSAPdisconnect tds; ! 94: struct TSAPdisconnect *td = &tds; ! 95: ! 96: /* ! 97: * Grotty hack ! 98: */ ! 99: if (iovcnt >= 64) { ! 100: fprintf(stderr, "Oh Spaghettio\n"); ! 101: return -1; ! 102: } ! 103: for(i=0; i<iovcnt; i++, uvp++, iov++) { ! 104: uvp->uv_base = iov->iov_base; ! 105: uvp->uv_len = iov->iov_len; ! 106: tot += iov->iov_len; ! 107: } ! 108: uvp->uv_base = NULL; ! 109: uvp->uv_len = 0; ! 110: ! 111: ret = TWriteRequest (sd, uv, td); ! 112: if (ret == NOTOK) { ! 113: #ifdef ISODEBUG ! 114: if (errno != EWOULDBLOCK) ! 115: if (isodexbug) ! 116: fprintf(stderr, "TWritevToCl: %s\n", TErrString(td->td_reason)); ! 117: #endif /* ISODEBUG */ ! 118: return ret; ! 119: } else { ! 120: #ifdef ISODEBUG ! 121: if (isodexbug) ! 122: fprintf(stderr, "TWritevToCl to %d: %d\n", sd, tot); ! 123: #endif /* ISODEBUG */ ! 124: return tot; ! 125: } ! 126: } ! 127: ! 128: TAcceptFromClient(fd, vecp, vec) ! 129: int fd; ! 130: int vecp; ! 131: char **vec; ! 132: { ! 133: struct TSAPdisconnect tds; ! 134: struct TSAPdisconnect *td = &tds; ! 135: struct TSAPstart tsts; ! 136: struct TSAPstart *tst = &tsts; ! 137: ! 138: if (TInit(vecp, vec, tst, td) == NOTOK) { ! 139: Error(TErrString(td->td_reason)); ! 140: Error("TInit"); ! 141: return -1; ! 142: } ! 143: ! 144: if (TConnResponse(tst->ts_sd, NULLTA, tst->ts_expedited, NULL, 0, ! 145: &(tst->ts_qos), td) == NOTOK) { ! 146: Error(TErrString(td->td_reason)); ! 147: Error("TConnResponse"); ! 148: return -1; ! 149: } ! 150: return tst->ts_sd; ! 151: } ! 152: ! 153: TDiscFromClient(fd) ! 154: int fd; ! 155: { ! 156: struct TSAPdisconnect tds; ! 157: ! 158: if (TDiscRequest(fd, NULLCP, 0, &tds)==NOTOK) ! 159: fprintf(stderr, "TDisc Failed %s\n", ! 160: TErrString(tds.td_reason)); ! 161: } ! 162: #endif /* ISOCONN */ ! 163: ! 164: /***************************************************************** ! 165: * ReadRequestFromClient ! 166: * Returns one request from client. If the client misbehaves, ! 167: * returns NULL. The dispatcher closes down all misbehaving clients. ! 168: * ! 169: * client: index into bit array returned from WaitForSomething() ! 170: * ! 171: * status: status is set to ! 172: * > 0 the number of bytes in the request if the read is sucessful ! 173: * = 0 if action would block (entire request not ready) ! 174: * < 0 indicates an error (probably client died) ! 175: * ! 176: * oldbuf: ! 177: * To facilitate buffer management (e.g. on multi-processor ! 178: * systems), the diX layer must tell the OS layer when it is ! 179: * done with a request, so the parameter oldbuf is a pointer ! 180: * to a request that diX is finished with. In the ! 181: * sample implementation, which is single threaded, ! 182: * oldbuf is ignored. We assume that when diX calls ! 183: * ReadRequestFromClient(), the previous buffer is finished with. ! 184: * ! 185: * The returned string returned must be contiguous so that it can be ! 186: * cast in the dispatcher to the correct request type. Because requests ! 187: * are variable length, ReadRequestFromClient() must look at the first 4 ! 188: * bytes of a request to determine the length (the request length is ! 189: * always the 3rd byte in the request). ! 190: * ! 191: * Note: in order to make the server scheduler (WaitForSomething()) ! 192: * "fair", the ClientsWithInput mask is used. This mask tells which ! 193: * clients have FULL requests left in their buffers. Clients with ! 194: * partial requests require a read. Basically, client buffers ! 195: * are drained before select() is called again. But, we can't keep ! 196: * reading from a client that is sending buckets of data (or has ! 197: * a partial request) because others clients need to be scheduled. ! 198: *****************************************************************/ ! 199: ! 200: ConnectionInput inputBuffers[MAXSOCKS]; /* buffers for clients */ ! 201: ! 202: /*ARGSUSED*/ ! 203: char * ! 204: ReadRequestFromClient(who, status, oldbuf) ! 205: ClientPtr who; ! 206: int *status; /* read at least n from client */ ! 207: char *oldbuf; ! 208: { ! 209: #define YieldControl() \ ! 210: { isItTimeToYield = TRUE; \ ! 211: timesThisConnection = 0; } ! 212: #define YieldControlNoInput() \ ! 213: { YieldControl(); \ ! 214: BITCLEAR(ClientsWithInput, client); } ! 215: #define YieldControlAndReturnNull() \ ! 216: { YieldControlNoInput(); \ ! 217: return((char *) NULL ); } ! 218: ! 219: OsCommPtr oc = (OsCommPtr)who->osPrivate; ! 220: int client = oc->fd; ! 221: int result, gotnow, needed; ! 222: register ConnectionInput *pBuff; ! 223: register xReq *request; ! 224: ! 225: /* ignore oldbuf, just assume we're done with prev. buffer */ ! 226: ! 227: if (client == -1) ! 228: { ! 229: ErrorF( "OH NO, %d translates to -1\n", who); ! 230: return((char *)NULL); ! 231: } ! 232: ! 233: pBuff = &inputBuffers[client]; ! 234: pBuff->bufptr += pBuff->lenLastReq; ! 235: pBuff->lenLastReq = 0; ! 236: ! 237: /* handle buffer empty or full case first */ ! 238: ! 239: if ((pBuff->bufptr - pBuff->buffer) >= pBuff->bufcnt) ! 240: { ! 241: #ifdef ISOCONN ! 242: result = SRead(client, pBuff->buffer, pBuff->size, OK); ! 243: #else /* ISOCONN */ ! 244: result = read(client, pBuff->buffer, pBuff->size); ! 245: #endif /* ISOCONN */ ! 246: if (result < 0) ! 247: { ! 248: if (errno == EWOULDBLOCK) ! 249: *status = 0; ! 250: else ! 251: *status = -1; ! 252: YieldControlAndReturnNull(); ! 253: } ! 254: else if (result == 0) ! 255: { ! 256: *status = -1; ! 257: YieldControlAndReturnNull(); ! 258: } ! 259: else ! 260: { ! 261: pBuff->bufcnt = result; ! 262: /* free up some space after huge requests */ ! 263: if ((pBuff->size > BUFWATERMARK) && (result < BUFSIZE)) ! 264: { ! 265: pBuff->size = BUFSIZE; ! 266: pBuff->buffer = (char *)xrealloc(pBuff->buffer, pBuff->size); ! 267: } ! 268: pBuff->bufptr = pBuff->buffer; ! 269: } ! 270: } ! 271: /* now look if there is enough in the buffer */ ! 272: ! 273: request = (xReq *)pBuff->bufptr; ! 274: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr; ! 275: ! 276: if (gotnow < sizeof(xReq)) ! 277: needed = sizeof(xReq) - gotnow; ! 278: else ! 279: { ! 280: needed = request_length(request, who); ! 281: if (needed > MAXBUFSIZE) ! 282: { ! 283: *status = -1; ! 284: YieldControlAndReturnNull(); ! 285: } ! 286: if (needed <= 0) ! 287: needed = sizeof(xReq); ! 288: } ! 289: /* if the needed amount won't fit in what's remaining, ! 290: move everything to the front of the buffer. If the ! 291: entire header isn't available, move what's there too */ ! 292: if ((pBuff->bufptr + needed - pBuff->buffer > pBuff->size) || ! 293: (gotnow < sizeof(xReq))) ! 294: { ! 295: bcopy(pBuff->bufptr, pBuff->buffer, gotnow); ! 296: pBuff->bufcnt = gotnow; ! 297: if (needed > pBuff->size) ! 298: { ! 299: pBuff->size = needed; ! 300: pBuff->buffer = (char *)xrealloc(pBuff->buffer, needed); ! 301: } ! 302: pBuff->bufptr = pBuff->buffer; ! 303: } ! 304: /* don't have a full header */ ! 305: if (gotnow < sizeof(xReq)) ! 306: { ! 307: while (pBuff->bufcnt + pBuff->buffer - pBuff->bufptr < sizeof(xReq)) ! 308: { ! 309: #ifdef ISOCONN ! 310: result = SRead(client, ! 311: pBuff->buffer + pBuff->bufcnt, ! 312: pBuff->size - pBuff->bufcnt, ! 313: OK); ! 314: #else /* ISOCONN */ ! 315: result = read(client, pBuff->buffer + pBuff->bufcnt, ! 316: pBuff->size - pBuff->bufcnt); ! 317: #endif /* ISOCONN */ ! 318: if (result < 0) ! 319: { ! 320: if (errno == EWOULDBLOCK) ! 321: *status = 0; ! 322: else ! 323: *status = -1; ! 324: YieldControlAndReturnNull(); ! 325: } ! 326: if (result == 0) ! 327: { ! 328: *status = -1; ! 329: YieldControlAndReturnNull(); ! 330: } ! 331: pBuff->bufcnt += result; ! 332: } ! 333: request = (xReq *)pBuff->bufptr; ! 334: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr; ! 335: needed = request_length(request, who); ! 336: if (needed <= 0) ! 337: needed = sizeof(xReq); ! 338: if (needed > pBuff->size) ! 339: { ! 340: pBuff->size = needed; ! 341: pBuff->buffer = (char *)xrealloc(pBuff->buffer, needed); ! 342: } ! 343: pBuff->bufptr = pBuff->buffer; ! 344: } ! 345: ! 346: if (gotnow < needed ) ! 347: { ! 348: int i, wanted; ! 349: ! 350: wanted = needed - gotnow; ! 351: i = 0; ! 352: while (i < wanted) ! 353: { ! 354: #ifdef ISOCONN ! 355: result = SRead(client, ! 356: pBuff->buffer + pBuff->bufcnt, ! 357: pBuff->size - pBuff->bufcnt, ! 358: OK); ! 359: #else /* ISOCONN */ ! 360: result = read(client, pBuff->buffer + pBuff->bufcnt, ! 361: pBuff->size - pBuff->bufcnt); ! 362: #endif /* ISOCONN */ ! 363: if (result < 0) ! 364: { ! 365: if (errno == EWOULDBLOCK) ! 366: *status = 0; ! 367: else ! 368: *status = -1; ! 369: YieldControlAndReturnNull(); ! 370: } ! 371: else if (result == 0) ! 372: { ! 373: *status = -1; ! 374: YieldControlAndReturnNull(); ! 375: } ! 376: i += result; ! 377: pBuff->bufcnt += result; ! 378: } ! 379: } ! 380: *status = needed; ! 381: pBuff->lenLastReq = needed; ! 382: ! 383: /* ! 384: * Check to see if client has at least one whole request in the ! 385: * buffer. If there is only a partial request, treat like buffer ! 386: * is empty so that select() will be called again and other clients ! 387: * can get into the queue. ! 388: */ ! 389: ! 390: timesThisConnection++; ! 391: if (pBuff->bufcnt + pBuff->buffer >= pBuff->bufptr + needed + sizeof(xReq)) ! 392: { ! 393: request = (xReq *)(pBuff->bufptr + needed); ! 394: if ((pBuff->bufcnt + pBuff->buffer) >= ! 395: ((char *)request + request_length(request, who))) ! 396: BITSET(ClientsWithInput, client); ! 397: else ! 398: YieldControlNoInput(); ! 399: } ! 400: else ! 401: YieldControlNoInput(); ! 402: if (timesThisConnection == MAX_TIMES_PER) ! 403: YieldControl(); ! 404: ! 405: return((char *)pBuff->bufptr); ! 406: ! 407: #undef YieldControlAndReturnNull ! 408: #undef YieldControlNoInput ! 409: #undef YieldControl ! 410: } ! 411: ! 412: ! 413: /* lookup table for adding padding bytes to data that is read from ! 414: or written to the X socket. */ ! 415: static int padlength[4] = {0, 3, 2, 1}; ! 416: ! 417: /******************** ! 418: * FlushClient() ! 419: * If the client isn't keeping up with us, then we try to continue ! 420: * buffering the data and set the apropriate bit in ClientsWritable ! 421: * (which is used by WaitFor in the select). If the connection yields ! 422: * a permanent error, or we can't allocate any more space, we then ! 423: * close the connection. ! 424: * ! 425: **********************/ ! 426: ! 427: static int ! 428: FlushClient(who, oc, extraBuf, extraCount) ! 429: ClientPtr who; ! 430: OsCommPtr oc; ! 431: char *extraBuf; ! 432: int extraCount; /* do not modify... returned below */ ! 433: { ! 434: int connection = oc->fd, ! 435: total, n, i, notWritten, written, ! 436: iovCnt = 0; ! 437: struct iovec iov[3]; ! 438: char padBuffer[3]; ! 439: #ifdef ISOCONN ! 440: struct TSAPdisconnect tds; ! 441: #endif /* ISOCONN */ ! 442: ! 443: total = 0; ! 444: if (oc->count) ! 445: { ! 446: total += iov[iovCnt].iov_len = oc->count; ! 447: iov[iovCnt++].iov_base = (caddr_t)oc->buf; ! 448: /* Notice that padding isn't needed for oc->buf since ! 449: it is alreay padded by WriteToClient */ ! 450: } ! 451: if (extraCount) ! 452: { ! 453: total += iov[iovCnt].iov_len = extraCount; ! 454: iov[iovCnt++].iov_base = extraBuf; ! 455: if (extraCount & 3) ! 456: { ! 457: total += iov[iovCnt].iov_len = padlength[extraCount & 3]; ! 458: iov[iovCnt++].iov_base = padBuffer; ! 459: } ! 460: } ! 461: ! 462: notWritten = total; ! 463: ! 464: #ifdef ISOCONN ! 465: while ((n = SWritev (connection, iov, iovCnt)) != notWritten) ! 466: #else /* ISOCONN */ ! 467: while ((n = writev (connection, iov, iovCnt)) != notWritten) ! 468: #endif /* ISOCONN */ ! 469: { ! 470: #ifdef hpux ! 471: if (n == -1 && errno == EMSGSIZE) ! 472: n = swWritev (connection, iov, 2); ! 473: #endif ! 474: if (n > 0) ! 475: { ! 476: notWritten -= n; ! 477: for (i = 0; i < iovCnt; i++) ! 478: { ! 479: if (n > iov[i].iov_len) ! 480: { ! 481: n -= iov[i].iov_len; ! 482: iov[i].iov_len = 0; ! 483: } ! 484: else ! 485: { ! 486: iov[i].iov_len -= n; ! 487: iov[i].iov_base += n; ! 488: break; ! 489: } ! 490: } ! 491: continue; ! 492: } ! 493: else if (errno != EWOULDBLOCK) ! 494: { ! 495: #ifdef notdef ! 496: if (errno != EBADF) ! 497: ErrorF("Closing connection %d because write failed\n", ! 498: connection); ! 499: /* this close will cause the select in WaitForSomething ! 500: to return that the connection is dead, so we can actually ! 501: clean up after the client. We can't clean up here, ! 502: because the we're in the middle of doing something ! 503: and will probably screw up some data strucutres */ ! 504: #endif ! 505: #ifdef ISOCONN ! 506: SClose(connection); ! 507: #else /* ISOCONN */ ! 508: close(connection); ! 509: #endif /* ISOCONN */ ! 510: MarkClientException(who); ! 511: return(-1); ! 512: } ! 513: ! 514: /* If we've arrived here, then the client is stuffed to the gills ! 515: and not ready to accept more. Make a note of it and buffer ! 516: the rest. */ ! 517: BITSET(ClientsWriteBlocked, connection); ! 518: AnyClientsWriteBlocked = TRUE; ! 519: ! 520: written = total - notWritten; ! 521: if (written < oc->count) ! 522: { ! 523: if (written > 0) ! 524: { ! 525: oc->count -= written; ! 526: bcopy((char *)oc->buf + written, (char *)oc->buf, oc->count); ! 527: written = 0; ! 528: } ! 529: } ! 530: else ! 531: { ! 532: written -= oc->count; ! 533: oc->count = 0; ! 534: } ! 535: ! 536: if (notWritten > oc->bufsize) ! 537: { ! 538: /* allocate at least enough to contain it plus one ! 539: OutputBufferSize */ ! 540: oc->bufsize = notWritten + OutputBufferSize; ! 541: oc->buf = (unsigned char *)xrealloc(oc->buf, oc->bufsize); ! 542: if (oc->buf == NULL) ! 543: { ! 544: outOfMem: ! 545: #ifdef notdef ! 546: ErrorF("Closing connection %d because out of memory\n", ! 547: connection); ! 548: /* this close will cause the select in WaitForSomething ! 549: to return that the connection is dead, so we can actually ! 550: clean up after the client. We can't clean up here, ! 551: because the we're in the middle of doing something ! 552: and will probably screw up some data strucutres */ ! 553: #endif ! 554: #ifdef ISOCONN ! 555: #ifdef ISODEBUG ! 556: fprintf(stderr, "out of mem: closing connection %d\n", ! 557: connection); ! 558: #endif /* ISODEBUG */ ! 559: SClose(connection); ! 560: #else /* ISOCONN */ ! 561: close(connection); ! 562: #endif /* ISOCONN */ ! 563: MarkClientException(who); ! 564: oc->count = 0; ! 565: oc->bufsize = 0; ! 566: return(-1); ! 567: } ! 568: } ! 569: ! 570: /* If the amount written extended into the padBuffer, then the ! 571: difference "extraCount - written" may be less than 0 */ ! 572: if ((n = extraCount - written) > 0) ! 573: bcopy (extraBuf + written, (char *)oc->buf + oc->count, n); ! 574: ! 575: oc->count = notWritten; /* this will include the pad */ ! 576: ! 577: return extraCount; /* return only the amount explicitly requested */ ! 578: } ! 579: ! 580: /* everything was flushed out */ ! 581: oc->count = 0; ! 582: if (oc->bufsize > OutputBufferSize) ! 583: { ! 584: oc->bufsize = OutputBufferSize; ! 585: oc->buf = (unsigned char *)xrealloc(oc->buf, OutputBufferSize); ! 586: if (oc->buf == NULL) /* nearly impossible */ ! 587: goto outOfMem; ! 588: } ! 589: return extraCount; /* return only the amount explicitly requested */ ! 590: } ! 591: ! 592: /******************** ! 593: * FlushAllOutput() ! 594: * Flush all clients with output. However, if some client still ! 595: * has input in the queue (more requests), then don't flush. This ! 596: * will prevent the output queue from being flushed every time around ! 597: * the round robin queue. Now, some say that it SHOULD be flushed ! 598: * every time around, but... ! 599: * ! 600: **********************/ ! 601: ! 602: void ! 603: FlushAllOutput() ! 604: { ! 605: register int index, base, mask; ! 606: OsCommPtr oc; ! 607: register ClientPtr client; ! 608: ! 609: if (! NewOutputPending) ! 610: return; ! 611: ! 612: /* ! 613: * It may be that some client still has critical output pending, ! 614: * but he is not yet ready to receive it anyway, so we will ! 615: * simply wait for the select to tell us when he's ready to receive. ! 616: */ ! 617: CriticalOutputPending = FALSE; ! 618: NewOutputPending = FALSE; ! 619: ! 620: for (base = 0; base < mskcnt; base++) ! 621: { ! 622: mask = OutputPending[ base ]; ! 623: OutputPending[ base ] = 0; ! 624: while (mask) ! 625: { ! 626: index = ffs(mask) - 1; ! 627: mask &= ~lowbit(mask); ! 628: if ((client = ConnectionTranslation[(32 * base) + index ]) == NULL) ! 629: continue; ! 630: if (client->clientGone) ! 631: continue; ! 632: oc = (OsCommPtr)client->osPrivate; ! 633: if (GETBIT(ClientsWithInput, client->index)) ! 634: { ! 635: BITSET(OutputPending, oc->fd); /* set the bit again */ ! 636: NewOutputPending = TRUE; ! 637: } ! 638: else ! 639: FlushClient(client, oc, (char *)NULL, 0); ! 640: } ! 641: } ! 642: ! 643: } ! 644: ! 645: void ! 646: FlushIfCriticalOutputPending() ! 647: { ! 648: if (CriticalOutputPending) ! 649: FlushAllOutput(); ! 650: } ! 651: ! 652: void ! 653: SetCriticalOutputPending() ! 654: { ! 655: CriticalOutputPending = TRUE; ! 656: } ! 657: ! 658: /***************** ! 659: * WriteToClient ! 660: * Copies buf into ClientPtr.buf if it fits (with padding), else ! 661: * flushes ClientPtr.buf and buf to client. As of this writing, ! 662: * every use of WriteToClient is cast to void, and the result ! 663: * is ignored. Potentially, this could be used by requests ! 664: * that are sending several chunks of data and want to break ! 665: * out of a loop on error. Thus, we will leave the type of ! 666: * this routine as int. ! 667: *****************/ ! 668: ! 669: int ! 670: WriteToClient (who, count, buf) ! 671: ClientPtr who; ! 672: char *buf; ! 673: int count; ! 674: { ! 675: OsCommPtr oc = (OsCommPtr)who->osPrivate; ! 676: int padBytes; ! 677: ! 678: if (oc->fd == -1) ! 679: { ! 680: ErrorF( "OH NO, %d translates to -1\n", oc->fd); ! 681: return(-1); ! 682: } ! 683: ! 684: if (oc->fd == -2) ! 685: { ! 686: #ifdef notdef ! 687: ErrorF( "CONNECTION %d ON ITS WAY OUT\n", oc->fd); ! 688: #endif ! 689: return(-1); ! 690: } ! 691: ! 692: padBytes = padlength[count & 3]; ! 693: ! 694: if (oc->count + count + padBytes > oc->bufsize) ! 695: { ! 696: BITCLEAR(OutputPending, oc->fd); ! 697: CriticalOutputPending = FALSE; ! 698: NewOutputPending = FALSE; ! 699: return FlushClient(who, oc, buf, count); ! 700: } ! 701: ! 702: NewOutputPending = TRUE; ! 703: BITSET(OutputPending, oc->fd); ! 704: bcopy(buf, (char *)oc->buf + oc->count, count); ! 705: oc->count += count + padBytes; ! 706: ! 707: return(count); ! 708: } ! 709:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.