1 /***********************************************************
3 Copyright 1987, 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 ******************************************************************/
46 /*****************************************************************
49 * WriteToClient, ReadRequestFromClient
50 * InsertFakeRequest, ResetCurrentRequest
52 *****************************************************************/
54 #ifdef HAVE_DIX_CONFIG_H
55 #include <dix-config.h>
58 #undef DEBUG_COMMUNICATION
61 #include <X11/Xwinsock.h>
67 #include <X11/Xtrans/Xtrans.h>
74 #include <X11/Xproto.h>
77 #include <X11/Xpoll.h>
79 #include "dixstruct.h"
82 CallbackListPtr ReplyCallback;
83 CallbackListPtr FlushCallback;
85 static ConnectionInputPtr AllocateInputBuffer(void);
86 static ConnectionOutputPtr AllocateOutputBuffer(void);
88 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
89 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
92 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
93 #else /* WIN32 The socket errorcodes differ from the normal errors */
94 #define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
97 static Bool CriticalOutputPending;
98 static int timesThisConnection = 0;
99 static ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL;
100 static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL;
101 static OsCommPtr AvailableInput = (OsCommPtr) NULL;
103 #define get_req_len(req,cli) ((cli)->swapped ? \
104 lswaps((req)->length) : (req)->length)
106 #include <X11/extensions/bigreqsproto.h>
108 #define get_big_req_len(req,cli) ((cli)->swapped ? \
109 lswapl(((xBigReq *)(req))->length) : \
110 ((xBigReq *)(req))->length)
112 #define MAX_TIMES_PER 10
114 #define BUFWATERMARK 8192
117 * A lot of the code in this file manipulates a ConnectionInputPtr:
119 * -----------------------------------------------
120 * |------- bufcnt ------->| | |
121 * | |- gotnow ->| | |
122 * | |-------- needed ------>| |
123 * |-----------+--------- size --------+---------->|
124 * -----------------------------------------------
129 * buffer is a pointer to the start of the buffer.
130 * bufptr points to the start of the current request.
131 * bufcnt counts how many bytes are in the buffer.
132 * size is the size of the buffer in bytes.
134 * In several of the functions, gotnow and needed are local variables
135 * that do the following:
137 * gotnow is the number of bytes of the request that we're
138 * trying to read that are currently in the buffer.
139 * Typically, gotnow = (buffer + bufcnt) - bufptr
141 * needed = the length of the request that we're trying to
142 * read. Watch out: needed sometimes counts bytes and sometimes
146 /*****************************************************************
147 * ReadRequestFromClient
148 * Returns one request in client->requestBuffer. The request
149 * length will be in client->req_len. Return status is:
151 * > 0 if successful, specifies length in bytes of the request
152 * = 0 if entire request is not yet available
153 * < 0 if client should be terminated
155 * The request returned must be contiguous so that it can be
156 * cast in the dispatcher to the correct request type. Because requests
157 * are variable length, ReadRequestFromClient() must look at the first 4
158 * or 8 bytes of a request to determine the length (the request length is
159 * in the 3rd and 4th bytes of the request unless it is a Big Request
160 * (see the Big Request Extension), in which case the 3rd and 4th bytes
161 * are zero and the following 4 bytes are the request length.
163 * Note: in order to make the server scheduler (WaitForSomething())
164 * "fair", the ClientsWithInput mask is used. This mask tells which
165 * clients have FULL requests left in their buffers. Clients with
166 * partial requests require a read. Basically, client buffers
167 * are drained before select() is called again. But, we can't keep
168 * reading from a client that is sending buckets of data (or has
169 * a partial request) because others clients need to be scheduled.
170 *****************************************************************/
175 isItTimeToYield = TRUE;
176 timesThisConnection = 0;
180 YieldControlNoInput(int fd)
183 FD_CLR(fd, &ClientsWithInput);
187 YieldControlDeath(void)
189 timesThisConnection = 0;
193 ReadRequestFromClient(ClientPtr client)
195 OsCommPtr oc = (OsCommPtr) client->osPrivate;
196 ConnectionInputPtr oci = oc->input;
198 unsigned int gotnow, needed;
200 register xReq *request;
204 /* If an input buffer was empty, either free it if it is too big
205 * or link it into our list of free input buffers. This means that
206 * different clients can share the same input buffer (at different
207 * times). This was done to save memory.
210 if (AvailableInput) {
211 if (AvailableInput != oc) {
212 register ConnectionInputPtr aci = AvailableInput->input;
214 if (aci->size > BUFWATERMARK) {
219 aci->next = FreeInputs;
222 AvailableInput->input = (ConnectionInputPtr) NULL;
224 AvailableInput = (OsCommPtr) NULL;
227 /* make sure we have an input buffer */
230 if ((oci = FreeInputs)) {
231 FreeInputs = oci->next;
233 else if (!(oci = AllocateInputBuffer())) {
240 /* advance to start of next request */
242 oci->bufptr += oci->lenLastReq;
246 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
248 if (oci->ignoreBytes > 0) {
249 if (oci->ignoreBytes > oci->size)
252 needed = oci->ignoreBytes;
254 else if (gotnow < sizeof(xReq)) {
255 /* We don't have an entire xReq yet. Can't tell how big
256 * the request will be until we get the whole xReq.
258 needed = sizeof(xReq);
262 /* We have a whole xReq. We can tell how big the whole
263 * request will be unless it is a Big Request.
265 request = (xReq *) oci->bufptr;
266 needed = get_req_len(request, client);
267 if (!needed && client->big_requests) {
268 /* It's a Big Request. */
270 if (gotnow < sizeof(xBigReq)) {
271 /* Still need more data to tell just how big. */
272 needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */
276 needed = get_big_req_len(request, client);
278 client->req_len = needed;
279 needed <<= 2; /* needed is in bytes now */
281 if (gotnow < needed) {
282 /* Need to read more data, either so that we can get a
283 * complete xReq (if need_header is TRUE), a complete
284 * xBigReq (if move_header is TRUE), or the rest of the
285 * request (if need_header and move_header are both FALSE).
289 if (needed > maxBigRequestSize << 2) {
290 /* request is too big for us to handle */
292 * Mark the rest of it as needing to be ignored, and then return
293 * the full size. Dispatch() will turn it into a BadLength error.
295 oci->ignoreBytes = needed - gotnow;
296 oci->lenLastReq = gotnow;
299 if ((gotnow == 0) || ((oci->bufptr - oci->buffer + needed) > oci->size)) {
300 /* no data, or the request is too big to fit in the buffer */
302 if ((gotnow > 0) && (oci->bufptr != oci->buffer))
303 /* save the data we've already read */
304 memmove(oci->buffer, oci->bufptr, gotnow);
305 if (needed > oci->size) {
306 /* make buffer bigger to accomodate request */
309 ibuf = (char *) realloc(oci->buffer, needed);
317 oci->bufptr = oci->buffer;
318 oci->bufcnt = gotnow;
320 /* XXX this is a workaround. This function is sometimes called
321 * after the trans_conn has been freed. In this case trans_conn
322 * will be null. Really ought to restructure things so that we
323 * never get here in those circumstances.
325 if (!oc->trans_conn) {
326 /* treat as if an error occured on the read, which is what
332 result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
333 oci->size - oci->bufcnt);
335 if ((result < 0) && ETEST(errno)) {
336 #if defined(SVR4) && defined(__i386__) && !defined(sun)
340 YieldControlNoInput(fd);
347 oci->bufcnt += result;
349 /* free up some space after huge requests */
350 if ((oci->size > BUFWATERMARK) &&
351 (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) {
354 ibuf = (char *) realloc(oci->buffer, BUFSIZE);
358 oci->bufptr = ibuf + oci->bufcnt - gotnow;
361 if (need_header && gotnow >= needed) {
362 /* We wanted an xReq, now we've gotten it. */
363 request = (xReq *) oci->bufptr;
364 needed = get_req_len(request, client);
365 if (!needed && client->big_requests) {
367 if (gotnow < sizeof(xBigReq))
368 needed = bytes_to_int32(sizeof(xBigReq));
370 needed = get_big_req_len(request, client);
372 client->req_len = needed;
375 if (gotnow < needed) {
376 /* Still don't have enough; punt. */
377 YieldControlNoInput(fd);
382 if (client->big_requests)
383 needed = sizeof(xBigReq);
385 needed = sizeof(xReq);
388 /* If there are bytes to ignore, ignore them now. */
390 if (oci->ignoreBytes > 0) {
391 assert(needed == oci->ignoreBytes || needed == oci->size);
393 * The _XSERVTransRead call above may return more or fewer bytes than we
394 * want to ignore. Ignore the smaller of the two sizes.
396 if (gotnow < needed) {
397 oci->ignoreBytes -= gotnow;
398 oci->bufptr += gotnow;
402 oci->ignoreBytes -= needed;
403 oci->bufptr += needed;
409 oci->lenLastReq = needed;
412 * Check to see if client has at least one whole request in the
413 * buffer beyond the request we're returning to the caller.
414 * If there is only a partial request, treat like buffer
415 * is empty so that select() will be called again and other clients
416 * can get into the queue.
420 if (gotnow >= sizeof(xReq)) {
421 request = (xReq *) (oci->bufptr + needed);
422 if (gotnow >= (result = (get_req_len(request, client) << 2))
424 (client->big_requests &&
425 (gotnow >= sizeof(xBigReq) &&
426 gotnow >= (get_big_req_len(request, client) << 2))))
428 FD_SET(fd, &ClientsWithInput);
430 if (!SmartScheduleDisable)
431 FD_CLR(fd, &ClientsWithInput);
433 YieldControlNoInput(fd);
439 if (!SmartScheduleDisable)
440 FD_CLR(fd, &ClientsWithInput);
442 YieldControlNoInput(fd);
444 if (SmartScheduleDisable)
445 if (++timesThisConnection >= MAX_TIMES_PER)
448 request = (xReq *) oci->bufptr;
449 oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
450 *(xReq *) oci->bufptr = *request;
451 oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
452 client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq));
454 client->requestBuffer = (pointer) oci->bufptr;
455 #ifdef DEBUG_COMMUNICATION
457 xReq *req = client->requestBuffer;
459 ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
460 client->index, req->reqType, req->data, req->length);
466 /*****************************************************************
468 * Splice a consed up (possibly partial) request in as the next request.
470 **********************/
473 InsertFakeRequest(ClientPtr client, char *data, int count)
475 OsCommPtr oc = (OsCommPtr) client->osPrivate;
476 ConnectionInputPtr oci = oc->input;
480 if (AvailableInput) {
481 if (AvailableInput != oc) {
482 ConnectionInputPtr aci = AvailableInput->input;
484 if (aci->size > BUFWATERMARK) {
489 aci->next = FreeInputs;
492 AvailableInput->input = (ConnectionInputPtr) NULL;
494 AvailableInput = (OsCommPtr) NULL;
497 if ((oci = FreeInputs))
498 FreeInputs = oci->next;
499 else if (!(oci = AllocateInputBuffer()))
503 oci->bufptr += oci->lenLastReq;
505 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
506 if ((gotnow + count) > oci->size) {
509 ibuf = (char *) realloc(oci->buffer, gotnow + count);
512 oci->size = gotnow + count;
514 oci->bufptr = ibuf + oci->bufcnt - gotnow;
516 moveup = count - (oci->bufptr - oci->buffer);
519 memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
520 oci->bufptr += moveup;
521 oci->bufcnt += moveup;
523 memmove(oci->bufptr - count, data, count);
524 oci->bufptr -= count;
526 if ((gotnow >= sizeof(xReq)) &&
527 (gotnow >= (int) (get_req_len((xReq *) oci->bufptr, client) << 2)))
528 FD_SET(fd, &ClientsWithInput);
530 YieldControlNoInput(fd);
534 /*****************************************************************
535 * ResetRequestFromClient
536 * Reset to reexecute the current request, and yield.
538 **********************/
541 ResetCurrentRequest(ClientPtr client)
543 OsCommPtr oc = (OsCommPtr) client->osPrivate;
544 register ConnectionInputPtr oci = oc->input;
546 register xReq *request;
549 if (AvailableInput == oc)
550 AvailableInput = (OsCommPtr) NULL;
552 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
553 if (gotnow < sizeof(xReq)) {
554 YieldControlNoInput(fd);
557 request = (xReq *) oci->bufptr;
558 needed = get_req_len(request, client);
559 if (!needed && client->big_requests) {
560 oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
561 *(xReq *) oci->bufptr = *request;
562 ((xBigReq *) oci->bufptr)->length = client->req_len;
563 if (client->swapped) {
564 swapl(&((xBigReq *) oci->bufptr)->length);
567 if (gotnow >= (needed << 2)) {
568 if (FD_ISSET(fd, &AllClients)) {
569 FD_SET(fd, &ClientsWithInput);
572 FD_SET(fd, &IgnoredClientsWithInput);
577 YieldControlNoInput(fd);
581 /********************
583 * Flush all clients with output. However, if some client still
584 * has input in the queue (more requests), then don't flush. This
585 * will prevent the output queue from being flushed every time around
586 * the round robin queue. Now, some say that it SHOULD be flushed
587 * every time around, but...
589 **********************/
594 register int index, base;
595 register fd_mask mask; /* raphael */
597 register ClientPtr client;
598 Bool newoutput = NewOutputPending;
601 fd_set newOutputPending;
605 CallCallbacks(&FlushCallback, NULL);
611 * It may be that some client still has critical output pending,
612 * but he is not yet ready to receive it anyway, so we will
613 * simply wait for the select to tell us when he's ready to receive.
615 CriticalOutputPending = FALSE;
616 NewOutputPending = FALSE;
619 for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) {
620 mask = OutputPending.fds_bits[base];
621 OutputPending.fds_bits[base] = 0;
623 index = ffs(mask) - 1;
624 mask &= ~lowbit(mask);
626 ConnectionTranslation[(base * (sizeof(fd_mask) * 8)) +
629 client = clients[index];
630 if (client->clientGone)
632 oc = (OsCommPtr) client->osPrivate;
633 if (FD_ISSET(oc->fd, &ClientsWithInput)) {
634 FD_SET(oc->fd, &OutputPending); /* set the bit again */
635 NewOutputPending = TRUE;
638 (void) FlushClient(client, oc, (char *) NULL, 0);
642 FD_ZERO(&newOutputPending);
643 for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) {
644 index = XFD_FD(&OutputPending, base);
645 if ((index = GetConnectionTranslation(index)) == 0)
647 client = clients[index];
648 if (client->clientGone)
650 oc = (OsCommPtr) client->osPrivate;
651 if (FD_ISSET(oc->fd, &ClientsWithInput)) {
652 FD_SET(oc->fd, &newOutputPending); /* set the bit again */
653 NewOutputPending = TRUE;
656 (void) FlushClient(client, oc, (char *) NULL, 0);
658 XFD_COPYSET(&newOutputPending, &OutputPending);
663 FlushIfCriticalOutputPending(void)
665 if (CriticalOutputPending)
670 SetCriticalOutputPending(void)
672 CriticalOutputPending = TRUE;
677 * Copies buf into ClientPtr.buf if it fits (with padding), else
678 * flushes ClientPtr.buf and buf to client. As of this writing,
679 * every use of WriteToClient is cast to void, and the result
680 * is ignored. Potentially, this could be used by requests
681 * that are sending several chunks of data and want to break
682 * out of a loop on error. Thus, we will leave the type of
683 * this routine as int.
687 WriteToClient(ClientPtr who, int count, const void *__buf)
690 ConnectionOutputPtr oco;
692 const char *buf = __buf;
694 #ifdef DEBUG_COMMUNICATION
695 Bool multicount = FALSE;
697 if (!count || !who || who == serverClient || who->clientGone)
701 #ifdef DEBUG_COMMUNICATION
708 if (!who->replyBytesRemaining) {
711 rep = (xGenericReply *) buf;
712 if (rep->sequenceNumber == who->sequence) {
713 snprintf(info, 127, "Xreply: type: 0x%x data: 0x%x "
714 "len: %i seq#: 0x%x", rep->type, rep->data1,
715 rep->length, rep->sequenceNumber);
720 err = (xError *) buf;
721 snprintf(info, 127, "Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
722 "min: %x", err->errorCode, err->resourceID,
723 err->minorCode, err->majorCode);
726 if ((buf[0] & 0x7f) == KeymapNotify)
727 snprintf(info, 127, "KeymapNotifyEvent: %i", buf[0]);
730 snprintf(info, 127, "XEvent: type: 0x%x detail: 0x%x "
731 "seq#: 0x%x", ev->u.u.type, ev->u.u.detail,
732 ev->u.u.sequenceNumber);
735 ErrorF("REPLY: ClientIDX: %i %s\n", who->index, info);
743 if ((oco = FreeOutputs)) {
744 FreeOutputs = oco->next;
746 else if (!(oco = AllocateOutputBuffer())) {
747 if (oc->trans_conn) {
748 _XSERVTransDisconnect(oc->trans_conn);
749 _XSERVTransClose(oc->trans_conn);
750 oc->trans_conn = NULL;
752 MarkClientException(who);
758 padBytes = padding_for_int32(count);
761 ReplyInfoRec replyinfo;
763 replyinfo.client = who;
764 replyinfo.replyData = buf;
765 replyinfo.dataLenBytes = count + padBytes;
766 replyinfo.padBytes = padBytes;
767 if (who->replyBytesRemaining) { /* still sending data of an earlier reply */
768 who->replyBytesRemaining -= count + padBytes;
769 replyinfo.startOfReply = FALSE;
770 replyinfo.bytesRemaining = who->replyBytesRemaining;
771 CallCallbacks((&ReplyCallback), (pointer) &replyinfo);
773 else if (who->clientState == ClientStateRunning && buf[0] == X_Reply) { /* start of new reply */
775 unsigned long bytesleft;
777 replylen = ((const xGenericReply *) buf)->length;
780 bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
781 replyinfo.startOfReply = TRUE;
782 replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
783 CallCallbacks((&ReplyCallback), (pointer) &replyinfo);
786 #ifdef DEBUG_COMMUNICATION
787 else if (multicount) {
788 if (who->replyBytesRemaining) {
789 who->replyBytesRemaining -= (count + padBytes);
794 replylen = ((xGenericReply *) buf)->length;
795 who->replyBytesRemaining =
796 (replylen * 4) + SIZEOF(xReply) - count - padBytes;
800 if (oco->count + count + padBytes > oco->size) {
801 FD_CLR(oc->fd, &OutputPending);
802 if (!XFD_ANYSET(&OutputPending)) {
803 CriticalOutputPending = FALSE;
804 NewOutputPending = FALSE;
808 CallCallbacks(&FlushCallback, NULL);
810 return FlushClient(who, oc, buf, count);
813 NewOutputPending = TRUE;
814 FD_SET(oc->fd, &OutputPending);
815 memmove((char *) oco->buf + oco->count, buf, count);
818 memset(oco->buf + oco->count, '\0', padBytes);
819 oco->count += padBytes;
824 /********************
826 * If the client isn't keeping up with us, then we try to continue
827 * buffering the data and set the apropriate bit in ClientsWritable
828 * (which is used by WaitFor in the select). If the connection yields
829 * a permanent error, or we can't allocate any more space, we then
830 * close the connection.
832 **********************/
835 FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
837 ConnectionOutputPtr oco = oc->output;
838 int connection = oc->fd;
839 XtransConnInfo trans_conn = oc->trans_conn;
841 static char padBuffer[3];
842 const char *extraBuf = __extraBuf;
851 padsize = padding_for_int32(extraCount);
852 notWritten = oco->count + extraCount + padsize;
855 long before = written; /* amount of whole thing written */
856 long remain = todo; /* amount to try this time, <= notWritten */
860 /* You could be very general here and have "in" and "out" iovecs
861 * and write a loop without using a macro, but what the heck. This
864 * how much of this piece is new?
865 * if more new then we are trying this time, clamp
867 * then bump down amount already written, for next piece
868 * else put new stuff in iovec, will need all of next piece
870 * Note that todo had better be at least 1 or else we'll end up
873 #define InsertIOV(pointer, length) \
874 len = (length) - before; \
880 iov[i].iov_len = len; \
881 iov[i].iov_base = (pointer) + before; \
887 InsertIOV((char *) oco->buf, oco->count)
888 InsertIOV((char *) extraBuf, extraCount)
889 InsertIOV(padBuffer, padsize)
892 if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) {
897 else if (ETEST(errno)
898 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
901 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
902 || ((errno == EMSGSIZE) && (todo == 1))
905 /* If we've arrived here, then the client is stuffed to the gills
906 and not ready to accept more. Make a note of it and buffer
908 FD_SET(connection, &ClientsWriteBlocked);
909 AnyClientsWriteBlocked = TRUE;
911 if (written < oco->count) {
913 oco->count -= written;
914 memmove((char *) oco->buf,
915 (char *) oco->buf + written, oco->count);
920 written -= oco->count;
924 if (notWritten > oco->size) {
927 obuf = (unsigned char *) realloc(oco->buf,
928 notWritten + BUFSIZE);
930 _XSERVTransDisconnect(oc->trans_conn);
931 _XSERVTransClose(oc->trans_conn);
932 oc->trans_conn = NULL;
933 MarkClientException(who);
937 oco->size = notWritten + BUFSIZE;
941 /* If the amount written extended into the padBuffer, then the
942 difference "extraCount - written" may be less than 0 */
943 if ((len = extraCount - written) > 0)
944 memmove((char *) oco->buf + oco->count,
945 extraBuf + written, len);
947 oco->count = notWritten; /* this will include the pad */
948 /* return only the amount explicitly requested */
951 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
952 else if (errno == EMSGSIZE) {
957 if (oc->trans_conn) {
958 _XSERVTransDisconnect(oc->trans_conn);
959 _XSERVTransClose(oc->trans_conn);
960 oc->trans_conn = NULL;
962 MarkClientException(who);
968 /* everything was flushed out */
970 /* check to see if this client was write blocked */
971 if (AnyClientsWriteBlocked) {
972 FD_CLR(oc->fd, &ClientsWriteBlocked);
973 if (!XFD_ANYSET(&ClientsWriteBlocked))
974 AnyClientsWriteBlocked = FALSE;
976 if (oco->size > BUFWATERMARK) {
981 oco->next = FreeOutputs;
984 oc->output = (ConnectionOutputPtr) NULL;
985 return extraCount; /* return only the amount explicitly requested */
988 static ConnectionInputPtr
989 AllocateInputBuffer(void)
991 ConnectionInputPtr oci;
993 oci = malloc(sizeof(ConnectionInput));
996 oci->buffer = malloc(BUFSIZE);
1001 oci->size = BUFSIZE;
1002 oci->bufptr = oci->buffer;
1004 oci->lenLastReq = 0;
1005 oci->ignoreBytes = 0;
1009 static ConnectionOutputPtr
1010 AllocateOutputBuffer(void)
1012 ConnectionOutputPtr oco;
1014 oco = malloc(sizeof(ConnectionOutput));
1017 oco->buf = calloc(1, BUFSIZE);
1022 oco->size = BUFSIZE;
1028 FreeOsBuffers(OsCommPtr oc)
1030 ConnectionInputPtr oci;
1031 ConnectionOutputPtr oco;
1033 if (AvailableInput == oc)
1034 AvailableInput = (OsCommPtr) NULL;
1035 if ((oci = oc->input)) {
1042 oci->next = (ConnectionInputPtr) NULL;
1043 oci->bufptr = oci->buffer;
1045 oci->lenLastReq = 0;
1048 if ((oco = oc->output)) {
1055 oco->next = (ConnectionOutputPtr) NULL;
1062 ResetOsBuffers(void)
1064 ConnectionInputPtr oci;
1065 ConnectionOutputPtr oco;
1067 while ((oci = FreeInputs)) {
1068 FreeInputs = oci->next;
1072 while ((oco = FreeOutputs)) {
1073 FreeOutputs = oco->next;