1 /***********************************************************
3 Copyright (c) 1987, 1989 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
27 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 ******************************************************************/
48 /* $XConsortium: io.c /main/72 1996/12/27 15:40:56 rws $ */
49 /* $XFree86: xc/programs/Xserver/os/io.c,v 3.15 1997/01/18 06:58:00 dawes Exp $ */
50 /*****************************************************************
53 * WriteToClient, ReadRequestFromClient
54 * InsertFakeRequest, ResetCurrentRequest
56 *****************************************************************/
59 #include <X11/Xwinsock.h>
62 #include <X11/Xtrans.h>
68 #if !defined(AMOEBA) && !defined(MINIX) && !defined(__EMX__) && !defined(WIN32)
82 #include "dixstruct.h"
88 CallbackListPtr ReplyCallback;
89 CallbackListPtr FlushCallback;
91 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
92 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
95 #if defined(EAGAIN) && defined(EWOULDBLOCK)
96 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
99 #define ETEST(err) (err == EAGAIN)
101 #define ETEST(err) (err == EWOULDBLOCK)
104 #else /* __EMX__ Writing to full pipes may return ENOSPC */
105 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK || err == ENOSPC)
108 extern fd_set ClientsWithInput, IgnoredClientsWithInput, AllClients;
109 extern fd_set ClientsWriteBlocked;
110 extern fd_set OutputPending;
111 extern int ConnectionTranslation[];
112 extern Bool NewOutputPending;
113 extern Bool AnyClientsWriteBlocked;
115 Bool CriticalOutputPending;
116 int timesThisConnection = 0;
117 ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
118 ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
119 OsCommPtr AvailableInput = (OsCommPtr)NULL;
121 #define get_req_len(req,cli) ((cli)->swapped ? \
122 lswaps((req)->length) : (req)->length)
125 #include "bigreqstr.h"
127 #define get_big_req_len(req,cli) ((cli)->swapped ? \
128 lswapl(((xBigReq *)(req))->length) : \
129 ((xBigReq *)(req))->length)
132 #define MAX_TIMES_PER 10
135 * A lot of the code in this file manipulates a ConnectionInputPtr:
137 * -----------------------------------------------
138 * |------- bufcnt ------->| | |
139 * | |- gotnow ->| | |
140 * | |-------- needed ------>| |
141 * |-----------+--------- size --------+---------->|
142 * -----------------------------------------------
147 * buffer is a pointer to the start of the buffer.
148 * bufptr points to the start of the current request.
149 * bufcnt counts how many bytes are in the buffer.
150 * size is the size of the buffer in bytes.
152 * In several of the functions, gotnow and needed are local variables
153 * that do the following:
155 * gotnow is the number of bytes of the request that we're
156 * trying to read that are currently in the buffer.
157 * Typically, gotnow = (buffer + bufcnt) - bufptr
159 * needed = the length of the request that we're trying to
160 * read. Watch out: needed sometimes counts bytes and sometimes
165 /*****************************************************************
166 * ReadRequestFromClient
167 * Returns one request in client->requestBuffer. The request
168 * length will be in client->req_len. Return status is:
170 * > 0 if successful, specifies length in bytes of the request
171 * = 0 if entire request is not yet available
172 * < 0 if client should be terminated
174 * The request returned must be contiguous so that it can be
175 * cast in the dispatcher to the correct request type. Because requests
176 * are variable length, ReadRequestFromClient() must look at the first 4
177 * or 8 bytes of a request to determine the length (the request length is
178 * in the 3rd and 4th bytes of the request unless it is a Big Request
179 * (see the Big Request Extension), in which case the 3rd and 4th bytes
180 * are zero and the following 4 bytes are the request length.
182 * Note: in order to make the server scheduler (WaitForSomething())
183 * "fair", the ClientsWithInput mask is used. This mask tells which
184 * clients have FULL requests left in their buffers. Clients with
185 * partial requests require a read. Basically, client buffers
186 * are drained before select() is called again. But, we can't keep
187 * reading from a client that is sending buckets of data (or has
188 * a partial request) because others clients need to be scheduled.
189 *****************************************************************/
191 #define YieldControl() \
192 { isItTimeToYield = TRUE; \
193 timesThisConnection = 0; }
194 #define YieldControlNoInput() \
196 FD_CLR(fd, &ClientsWithInput); }
197 #define YieldControlDeath() \
198 { timesThisConnection = 0; }
200 #if defined(LBX) || defined(LBX_COMPAT)
202 StandardReadRequestFromClient(client)
206 ReadRequestFromClient(client)
210 OsCommPtr oc = (OsCommPtr)client->osPrivate;
211 register ConnectionInputPtr oci = oc->input;
213 register int gotnow, needed;
215 register xReq *request;
221 /* If an input buffer was empty, either free it if it is too big
222 * or link it into our list of free input buffers. This means that
223 * different clients can share the same input buffer (at different
224 * times). This was done to save memory.
229 if (AvailableInput != oc)
231 register ConnectionInputPtr aci = AvailableInput->input;
232 if (aci->size > BUFWATERMARK)
239 aci->next = FreeInputs;
242 AvailableInput->input = (ConnectionInputPtr)NULL;
244 AvailableInput = (OsCommPtr)NULL;
247 /* make sure we have an input buffer */
251 if (oci = FreeInputs)
253 FreeInputs = oci->next;
255 else if (!(oci = AllocateInputBuffer()))
263 /* advance to start of next request */
265 oci->bufptr += oci->lenLastReq;
271 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
272 if (gotnow < sizeof(xReq))
274 /* We don't have an entire xReq yet. Can't tell how big
275 * the request will be until we get the whole xReq.
277 needed = sizeof(xReq);
282 /* We have a whole xReq. We can tell how big the whole
283 * request will be unless it is a Big Request.
285 request = (xReq *)oci->bufptr;
286 needed = get_req_len(request, client);
288 if (!needed && client->big_requests)
290 /* It's a Big Request. */
292 if (gotnow < sizeof(xBigReq))
294 /* Still need more data to tell just how big. */
295 needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */
299 needed = get_big_req_len(request, client);
302 client->req_len = needed;
303 needed <<= 2; /* needed is in bytes now */
307 /* Need to read more data, either so that we can get a
308 * complete xReq (if need_header is TRUE), a complete
309 * xBigReq (if move_header is TRUE), or the rest of the
310 * request (if need_header and move_header are both FALSE).
314 if (needed > MAXBUFSIZE)
316 /* request is too big for us to handle */
321 ((oci->bufptr - oci->buffer + needed) > oci->size))
323 /* no data, or the request is too big to fit in the buffer */
325 if ((gotnow > 0) && (oci->bufptr != oci->buffer))
326 /* save the data we've already read */
327 memmove(oci->buffer, oci->bufptr, gotnow);
328 if (needed > oci->size)
330 /* make buffer bigger to accomodate request */
333 ibuf = (char *)xrealloc(oci->buffer, needed);
342 oci->bufptr = oci->buffer;
343 oci->bufcnt = gotnow;
345 /* XXX this is a workaround. This function is sometimes called
346 * after the trans_conn has been freed. In this case trans_conn
347 * will be null. Really ought to restructure things so that we
348 * never get here in those circumstances.
352 /* treat as if an error occured on the read, which is what
359 if (oc->proxy && oc->proxy->compHandle)
360 result = (*oc->proxy->streamOpts.streamCompRead)(fd,
361 (unsigned char *)oci->buffer + oci->bufcnt,
362 oci->size - oci->bufcnt);
365 result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
366 oci->size - oci->bufcnt);
369 if ((result < 0) && ETEST(errno))
371 #if defined(SVR4) && defined(i386) && !defined(sun)
372 #if defined(LBX) && 0
374 * For LBX connections, we can get a valid EWOULDBLOCK
375 * There is probably a better way of distinguishing LBX
376 * connections, but this works. (DHD)
378 extern int LbxRead();
379 if (oc->Read == LbxRead)
385 YieldControlNoInput();
392 oci->bufcnt += result;
394 /* free up some space after huge requests */
395 if ((oci->size > BUFWATERMARK) &&
396 (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
400 ibuf = (char *)xrealloc(oci->buffer, BUFSIZE);
405 oci->bufptr = ibuf + oci->bufcnt - gotnow;
408 if (need_header && gotnow >= needed)
410 /* We wanted an xReq, now we've gotten it. */
411 request = (xReq *)oci->bufptr;
412 needed = get_req_len(request, client);
414 if (!needed && client->big_requests)
417 if (gotnow < sizeof(xBigReq))
418 needed = sizeof(xBigReq) >> 2;
420 needed = get_big_req_len(request, client);
423 client->req_len = needed;
428 /* Still don't have enough; punt. */
429 YieldControlNoInput();
436 if (client->big_requests)
437 needed = sizeof(xBigReq);
440 needed = sizeof(xReq);
442 oci->lenLastReq = needed;
445 * Check to see if client has at least one whole request in the
446 * buffer beyond the request we're returning to the caller.
447 * If there is only a partial request, treat like buffer
448 * is empty so that select() will be called again and other clients
449 * can get into the queue.
453 if (gotnow >= sizeof(xReq))
455 request = (xReq *)(oci->bufptr + needed);
456 if (gotnow >= (result = (get_req_len(request, client) << 2))
459 (client->big_requests &&
460 (gotnow >= sizeof(xBigReq) &&
461 gotnow >= (get_big_req_len(request, client) << 2))))
464 FD_SET(fd, &ClientsWithInput);
466 YieldControlNoInput();
472 YieldControlNoInput();
474 if (++timesThisConnection >= MAX_TIMES_PER)
479 request = (xReq *)oci->bufptr;
480 oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
481 *(xReq *)oci->bufptr = *request;
482 oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
483 client->req_len -= (sizeof(xBigReq) - sizeof(xReq)) >> 2;
486 client->requestBuffer = (pointer)oci->bufptr;
490 /*****************************************************************
492 * Splice a consed up (possibly partial) request in as the next request.
494 **********************/
497 InsertFakeRequest(client, data, count)
502 OsCommPtr oc = (OsCommPtr)client->osPrivate;
503 register ConnectionInputPtr oci = oc->input;
505 register int gotnow, moveup;
509 if (AvailableInput != oc)
511 register ConnectionInputPtr aci = AvailableInput->input;
512 if (aci->size > BUFWATERMARK)
519 aci->next = FreeInputs;
522 AvailableInput->input = (ConnectionInputPtr)NULL;
524 AvailableInput = (OsCommPtr)NULL;
528 if (oci = FreeInputs)
529 FreeInputs = oci->next;
530 else if (!(oci = AllocateInputBuffer()))
534 oci->bufptr += oci->lenLastReq;
536 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
537 if ((gotnow + count) > oci->size)
541 ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
544 oci->size = gotnow + count;
546 oci->bufptr = ibuf + oci->bufcnt - gotnow;
548 moveup = count - (oci->bufptr - oci->buffer);
552 memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
553 oci->bufptr += moveup;
554 oci->bufcnt += moveup;
556 memmove(oci->bufptr - count, data, count);
557 oci->bufptr -= count;
559 if ((gotnow >= sizeof(xReq)) &&
560 (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
561 FD_SET(fd, &ClientsWithInput);
563 YieldControlNoInput();
567 /*****************************************************************
568 * ResetRequestFromClient
569 * Reset to reexecute the current request, and yield.
571 **********************/
573 ResetCurrentRequest(client)
576 OsCommPtr oc = (OsCommPtr)client->osPrivate;
577 register ConnectionInputPtr oci = oc->input;
579 register xReq *request;
583 LbxClientPtr lbxClient = LbxClient(client);
586 LbxSetForBlock(lbxClient);
588 AppendFakeRequest(client,
589 client->requestBuffer, client->req_len << 2);
594 if (AvailableInput == oc)
595 AvailableInput = (OsCommPtr)NULL;
597 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
598 if (gotnow < sizeof(xReq))
600 YieldControlNoInput();
604 request = (xReq *)oci->bufptr;
605 needed = get_req_len(request, client);
607 if (!needed && client->big_requests)
609 oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
610 *(xReq *)oci->bufptr = *request;
611 ((xBigReq *)oci->bufptr)->length = client->req_len;
615 swapl(&((xBigReq *)oci->bufptr)->length, n);
619 if (gotnow >= (needed << 2))
621 if (FD_ISSET(fd, &AllClients))
623 FD_SET(fd, &ClientsWithInput);
627 FD_SET(fd, &IgnoredClientsWithInput);
632 YieldControlNoInput();
638 /*****************************************************************
639 * PeekNextRequest and SkipRequests were implemented to support DBE
640 * idioms, but can certainly be used outside of DBE. There are two
641 * related macros in os.h, ReqLen and CastxReq. See the porting
642 * layer document for more details.
644 **********************/
647 /*****************************************************************
649 * lets you look ahead at the unexecuted requests in a
650 * client's request buffer.
652 * Note: this implementation of PeekNextRequest ignores the
653 * readmore parameter.
655 **********************/
658 PeekNextRequest(req, client, readmore)
659 xReqPtr req; /* request we're starting from */
660 ClientPtr client; /* client whose requests we're skipping */
661 Bool readmore; /* attempt to read more if next request isn't there? */
663 register ConnectionInputPtr oci = ((OsCommPtr)client->osPrivate)->input;
665 int needed, gotnow, reqlen;
667 if (!oci) return NULL;
671 /* caller wants the request after the one currently being executed */
673 (((CARD32 *)client->requestBuffer) + client->req_len);
677 /* caller wants the request after the one specified by req */
678 reqlen = get_req_len(req, client);
680 if (!reqlen) reqlen = get_big_req_len(req, client);
682 pnextreq = (xReqPtr)(((char *)req) + (reqlen << 2));
685 /* see how much of the next request we have available */
687 gotnow = oci->bufcnt - (((char *)pnextreq) - oci->buffer);
689 if (gotnow < sizeof(xReq))
692 needed = get_req_len(pnextreq, client) << 2;
696 /* it's a big request */
697 if (gotnow < sizeof(xBigReq))
699 needed = get_big_req_len(pnextreq, client) << 2;
703 /* if we have less than we need, return NULL */
705 return (gotnow < needed) ? NULL : pnextreq;
708 /*****************************************************************
710 * lets you skip over some of the requests in a client's
711 * request buffer. Presumably the caller has used PeekNextRequest
712 * to examine the requests being skipped and has performed whatever
713 * actions they dictate.
715 **********************/
717 CallbackListPtr SkippedRequestsCallback = NULL;
720 SkipRequests(req, client, numskipped)
721 xReqPtr req; /* last request being skipped */
722 ClientPtr client; /* client whose requests we're skipping */
723 int numskipped; /* how many requests we're skipping */
725 OsCommPtr oc = (OsCommPtr)client->osPrivate;
726 register ConnectionInputPtr oci = oc->input;
729 /* see if anyone wants to snoop the skipped requests */
731 if (SkippedRequestsCallback)
733 SkippedRequestInfoRec skipinfo;
735 skipinfo.client = client;
736 skipinfo.numskipped = numskipped;
737 CallCallbacks(&SkippedRequestsCallback, &skipinfo);
740 /* adjust the sequence number */
741 client->sequence += numskipped;
743 /* twiddle the oci to skip over the requests */
745 reqlen = get_req_len(req, client);
747 if (!reqlen) reqlen = get_big_req_len(req, client);
750 oci->bufptr = (char *)req;
751 oci->lenLastReq = reqlen;
753 /* see if any requests left in the buffer */
755 if ( ((char *)req + reqlen) == (oci->buffer + oci->bufcnt) )
757 /* no requests; mark input buffer as available and client
762 YieldControlNoInput();
767 /* lookup table for adding padding bytes to data that is read from
768 or written to the X socket. */
769 static int padlength[4] = {0, 3, 2, 1};
771 /********************
773 * If the client isn't keeping up with us, then we try to continue
774 * buffering the data and set the apropriate bit in ClientsWritable
775 * (which is used by WaitFor in the select). If the connection yields
776 * a permanent error, or we can't allocate any more space, we then
777 * close the connection.
779 **********************/
783 StandardFlushClient(who, oc, extraBuf, extraCount)
785 FlushClient(who, oc, extraBuf, extraCount)
790 int extraCount; /* do not modify... returned below */
792 register ConnectionOutputPtr oco = oc->output;
793 int connection = oc->fd;
794 XtransConnInfo trans_conn = oc->trans_conn;
796 static char padBuffer[3];
805 padsize = padlength[extraCount & 3];
806 notWritten = oco->count + extraCount + padsize;
809 long before = written; /* amount of whole thing written */
810 long remain = todo; /* amount to try this time, <= notWritten */
814 /* You could be very general here and have "in" and "out" iovecs
815 * and write a loop without using a macro, but what the heck. This
818 * how much of this piece is new?
819 * if more new then we are trying this time, clamp
821 * then bump down amount already written, for next piece
822 * else put new stuff in iovec, will need all of next piece
824 * Note that todo had better be at least 1 or else we'll end up
827 #define InsertIOV(pointer, length) \
828 len = (length) - before; \
834 iov[i].iov_len = len; \
835 iov[i].iov_base = (pointer) + before; \
841 InsertIOV ((char *)oco->buf, oco->count)
842 InsertIOV (extraBuf, extraCount)
843 InsertIOV (padBuffer, padsize)
846 if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
852 else if (ETEST(errno)
853 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
856 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
857 || ((errno == EMSGSIZE) && (todo == 1))
861 /* If we've arrived here, then the client is stuffed to the gills
862 and not ready to accept more. Make a note of it and buffer
864 FD_SET(connection, &ClientsWriteBlocked);
865 AnyClientsWriteBlocked = TRUE;
867 if (written < oco->count)
871 oco->count -= written;
872 memmove((char *)oco->buf,
873 (char *)oco->buf + written,
880 written -= oco->count;
884 if (notWritten > oco->size)
888 obuf = (unsigned char *)xrealloc(oco->buf,
889 notWritten + BUFSIZE);
892 _XSERVTransDisconnect(oc->trans_conn);
893 _XSERVTransClose(oc->trans_conn);
894 oc->trans_conn = NULL;
895 MarkClientException(who);
899 oco->size = notWritten + BUFSIZE;
903 /* If the amount written extended into the padBuffer, then the
904 difference "extraCount - written" may be less than 0 */
905 if ((len = extraCount - written) > 0)
906 memmove ((char *)oco->buf + oco->count,
910 oco->count = notWritten; /* this will include the pad */
911 /* return only the amount explicitly requested */
914 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
915 else if (errno == EMSGSIZE)
924 _XSERVTransDisconnect(oc->trans_conn);
925 _XSERVTransClose(oc->trans_conn);
926 oc->trans_conn = NULL;
928 MarkClientException(who);
934 /* everything was flushed out */
936 /* check to see if this client was write blocked */
937 if (AnyClientsWriteBlocked)
939 FD_CLR(oc->fd, &ClientsWriteBlocked);
940 if (! XFD_ANYSET(&ClientsWriteBlocked))
941 AnyClientsWriteBlocked = FALSE;
943 if (oco->size > BUFWATERMARK)
950 oco->next = FreeOutputs;
953 oc->output = (ConnectionOutputPtr)NULL;
954 return extraCount; /* return only the amount explicitly requested */
957 /********************
959 * Flush all clients with output. However, if some client still
960 * has input in the queue (more requests), then don't flush. This
961 * will prevent the output queue from being flushed every time around
962 * the round robin queue. Now, some say that it SHOULD be flushed
963 * every time around, but...
965 **********************/
970 register int index, base, mask;
972 register ClientPtr client;
973 Bool newoutput = NewOutputPending;
975 fd_set newOutputPending;
979 CallCallbacks(&FlushCallback, NULL);
985 * It may be that some client still has critical output pending,
986 * but he is not yet ready to receive it anyway, so we will
987 * simply wait for the select to tell us when he's ready to receive.
989 CriticalOutputPending = FALSE;
990 NewOutputPending = FALSE;
993 for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
995 mask = OutputPending.fds_bits[ base ];
996 OutputPending.fds_bits[ base ] = 0;
999 index = ffs(mask) - 1;
1000 mask &= ~lowbit(mask);
1001 if ((index = ConnectionTranslation[(base << 5) + index]) == 0)
1003 client = clients[index];
1004 if (client->clientGone)
1006 oc = (OsCommPtr)client->osPrivate;
1011 FD_ISSET(oc->fd, &ClientsWithInput))
1013 FD_SET(oc->fd, &OutputPending); /* set the bit again */
1014 NewOutputPending = TRUE;
1017 (void)FlushClient(client, oc, (char *)NULL, 0);
1021 FD_ZERO(&newOutputPending);
1022 for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
1024 index = XFD_FD(&OutputPending, base);
1025 if ((index = ConnectionTranslation[index]) == 0)
1027 client = clients[index];
1028 if (client->clientGone)
1030 oc = (OsCommPtr)client->osPrivate;
1035 FD_ISSET(oc->fd, &ClientsWithInput))
1037 FD_SET(oc->fd, &newOutputPending); /* set the bit again */
1038 NewOutputPending = TRUE;
1041 (void)FlushClient(client, oc, (char *)NULL, 0);
1043 XFD_COPYSET(&newOutputPending, &OutputPending);
1048 FlushIfCriticalOutputPending()
1050 if (CriticalOutputPending)
1055 SetCriticalOutputPending()
1057 CriticalOutputPending = TRUE;
1062 * Copies buf into ClientPtr.buf if it fits (with padding), else
1063 * flushes ClientPtr.buf and buf to client. As of this writing,
1064 * every use of WriteToClient is cast to void, and the result
1065 * is ignored. Potentially, this could be used by requests
1066 * that are sending several chunks of data and want to break
1067 * out of a loop on error. Thus, we will leave the type of
1068 * this routine as int.
1072 WriteToClient (who, count, buf)
1077 OsCommPtr oc = (OsCommPtr)who->osPrivate;
1078 register ConnectionOutputPtr oco = oc->output;
1086 if (oco = FreeOutputs)
1088 FreeOutputs = oco->next;
1090 else if (!(oco = AllocateOutputBuffer()))
1092 if (oc->trans_conn) {
1093 _XSERVTransDisconnect(oc->trans_conn);
1094 _XSERVTransClose(oc->trans_conn);
1095 oc->trans_conn = NULL;
1097 MarkClientException(who);
1103 padBytes = padlength[count & 3];
1107 ReplyInfoRec replyinfo;
1109 replyinfo.client = who;
1110 replyinfo.replyData = buf;
1111 replyinfo.dataLenBytes = count + padBytes;
1112 if (who->replyBytesRemaining)
1113 { /* still sending data of an earlier reply */
1114 who->replyBytesRemaining -= count + padBytes;
1115 replyinfo.startOfReply = FALSE;
1116 replyinfo.bytesRemaining = who->replyBytesRemaining;
1117 CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
1119 else if (who->clientState == ClientStateRunning
1120 && buf[0] == X_Reply)
1121 { /* start of new reply */
1123 unsigned long bytesleft;
1126 replylen = ((xGenericReply *)buf)->length;
1128 swapl(&replylen, n);
1129 bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
1130 replyinfo.startOfReply = TRUE;
1131 replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
1132 CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
1136 if (oco->count + count + padBytes > oco->size)
1138 FD_CLR(oc->fd, &OutputPending);
1139 CriticalOutputPending = FALSE;
1140 NewOutputPending = FALSE;
1141 return FlushClient(who, oc, buf, count);
1144 NewOutputPending = TRUE;
1145 FD_SET(oc->fd, &OutputPending);
1146 memmove((char *)oco->buf + oco->count, buf, count);
1147 oco->count += count + padBytes;
1152 AllocateInputBuffer()
1154 register ConnectionInputPtr oci;
1156 oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
1158 return (ConnectionInputPtr)NULL;
1159 oci->buffer = (char *)xalloc(BUFSIZE);
1163 return (ConnectionInputPtr)NULL;
1165 oci->size = BUFSIZE;
1166 oci->bufptr = oci->buffer;
1168 oci->lenLastReq = 0;
1173 AllocateOutputBuffer()
1175 register ConnectionOutputPtr oco;
1177 oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
1179 return (ConnectionOutputPtr)NULL;
1180 oco->buf = (unsigned char *) xalloc(BUFSIZE);
1184 return (ConnectionOutputPtr)NULL;
1186 oco->size = BUFSIZE;
1189 oco->nocompress = FALSE;
1198 register ConnectionInputPtr oci;
1199 register ConnectionOutputPtr oco;
1201 if (AvailableInput == oc)
1202 AvailableInput = (OsCommPtr)NULL;
1203 if (oci = oc->input)
1213 oci->next = (ConnectionInputPtr)NULL;
1214 oci->bufptr = oci->buffer;
1216 oci->lenLastReq = 0;
1219 if (oco = oc->output)
1229 oco->next = (ConnectionOutputPtr)NULL;
1234 if (oci = oc->largereq) {
1244 register ConnectionInputPtr oci;
1245 register ConnectionOutputPtr oco;
1247 while (oci = FreeInputs)
1249 FreeInputs = oci->next;
1253 while (oco = FreeOutputs)
1255 FreeOutputs = oco->next;