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 typedef struct _connectionInput {
86 struct _connectionInput *next;
87 char *buffer; /* contains current client input */
88 char *bufptr; /* pointer to current start of data */
89 int bufcnt; /* count of bytes in buffer */
92 unsigned int ignoreBytes; /* bytes to ignore before the next request */
95 typedef struct _connectionOutput {
96 struct _connectionOutput *next;
102 static ConnectionInputPtr AllocateInputBuffer(void);
103 static ConnectionOutputPtr AllocateOutputBuffer(void);
105 /* If EAGAIN and EWOULDBLOCK are distinct errno values, then we check errno
106 * for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
107 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
110 # if (EAGAIN != EWOULDBLOCK)
111 # define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
113 # define ETEST(err) (err == EAGAIN)
115 #else /* WIN32 The socket errorcodes differ from the normal errors */
116 #define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
119 static Bool CriticalOutputPending;
120 static int timesThisConnection = 0;
121 static ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL;
122 static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL;
123 static OsCommPtr AvailableInput = (OsCommPtr) NULL;
125 #define get_req_len(req,cli) ((cli)->swapped ? \
126 lswaps((req)->length) : (req)->length)
128 #include <X11/extensions/bigreqsproto.h>
130 #define get_big_req_len(req,cli) ((cli)->swapped ? \
131 lswapl(((xBigReq *)(req))->length) : \
132 ((xBigReq *)(req))->length)
134 #define MAX_TIMES_PER 10
136 #define BUFWATERMARK 8192
139 * A lot of the code in this file manipulates a ConnectionInputPtr:
141 * -----------------------------------------------
142 * |------- bufcnt ------->| | |
143 * | |- gotnow ->| | |
144 * | |-------- needed ------>| |
145 * |-----------+--------- size --------+---------->|
146 * -----------------------------------------------
151 * buffer is a pointer to the start of the buffer.
152 * bufptr points to the start of the current request.
153 * bufcnt counts how many bytes are in the buffer.
154 * size is the size of the buffer in bytes.
156 * In several of the functions, gotnow and needed are local variables
157 * that do the following:
159 * gotnow is the number of bytes of the request that we're
160 * trying to read that are currently in the buffer.
161 * Typically, gotnow = (buffer + bufcnt) - bufptr
163 * needed = the length of the request that we're trying to
164 * read. Watch out: needed sometimes counts bytes and sometimes
168 /*****************************************************************
169 * ReadRequestFromClient
170 * Returns one request in client->requestBuffer. The request
171 * length will be in client->req_len. Return status is:
173 * > 0 if successful, specifies length in bytes of the request
174 * = 0 if entire request is not yet available
175 * < 0 if client should be terminated
177 * The request returned must be contiguous so that it can be
178 * cast in the dispatcher to the correct request type. Because requests
179 * are variable length, ReadRequestFromClient() must look at the first 4
180 * or 8 bytes of a request to determine the length (the request length is
181 * in the 3rd and 4th bytes of the request unless it is a Big Request
182 * (see the Big Request Extension), in which case the 3rd and 4th bytes
183 * are zero and the following 4 bytes are the request length.
185 * Note: in order to make the server scheduler (WaitForSomething())
186 * "fair", the ClientsWithInput mask is used. This mask tells which
187 * clients have FULL requests left in their buffers. Clients with
188 * partial requests require a read. Basically, client buffers
189 * are drained before select() is called again. But, we can't keep
190 * reading from a client that is sending buckets of data (or has
191 * a partial request) because others clients need to be scheduled.
192 *****************************************************************/
197 isItTimeToYield = TRUE;
198 timesThisConnection = 0;
202 YieldControlNoInput(int fd)
205 FD_CLR(fd, &ClientsWithInput);
209 YieldControlDeath(void)
211 timesThisConnection = 0;
214 /* If an input buffer was empty, either free it if it is too big or link it
215 * into our list of free input buffers. This means that different clients can
216 * share the same input buffer (at different times). This was done to save
220 NextAvailableInput(OsCommPtr oc)
222 if (AvailableInput) {
223 if (AvailableInput != oc) {
224 ConnectionInputPtr aci = AvailableInput->input;
226 if (aci->size > BUFWATERMARK) {
231 aci->next = FreeInputs;
234 AvailableInput->input = NULL;
236 AvailableInput = NULL;
241 ReadRequestFromClient(ClientPtr client)
243 OsCommPtr oc = (OsCommPtr) client->osPrivate;
244 ConnectionInputPtr oci = oc->input;
246 unsigned int gotnow, needed;
248 register xReq *request;
252 NextAvailableInput(oc);
254 /* make sure we have an input buffer */
257 if ((oci = FreeInputs)) {
258 FreeInputs = oci->next;
260 else if (!(oci = AllocateInputBuffer())) {
268 /* Discard any unused file descriptors */
269 while (client->req_fds > 0) {
270 int req_fd = ReadFdFromClient(client);
275 /* advance to start of next request */
277 oci->bufptr += oci->lenLastReq;
281 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
283 if (oci->ignoreBytes > 0) {
284 if (oci->ignoreBytes > oci->size)
287 needed = oci->ignoreBytes;
289 else if (gotnow < sizeof(xReq)) {
290 /* We don't have an entire xReq yet. Can't tell how big
291 * the request will be until we get the whole xReq.
293 needed = sizeof(xReq);
297 /* We have a whole xReq. We can tell how big the whole
298 * request will be unless it is a Big Request.
300 request = (xReq *) oci->bufptr;
301 needed = get_req_len(request, client);
302 if (!needed && client->big_requests) {
303 /* It's a Big Request. */
305 if (gotnow < sizeof(xBigReq)) {
306 /* Still need more data to tell just how big. */
307 needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */
311 needed = get_big_req_len(request, client);
313 client->req_len = needed;
314 needed <<= 2; /* needed is in bytes now */
316 if (gotnow < needed) {
317 /* Need to read more data, either so that we can get a
318 * complete xReq (if need_header is TRUE), a complete
319 * xBigReq (if move_header is TRUE), or the rest of the
320 * request (if need_header and move_header are both FALSE).
324 if (needed > maxBigRequestSize << 2) {
325 /* request is too big for us to handle */
327 * Mark the rest of it as needing to be ignored, and then return
328 * the full size. Dispatch() will turn it into a BadLength error.
330 oci->ignoreBytes = needed - gotnow;
331 oci->lenLastReq = gotnow;
334 if ((gotnow == 0) || ((oci->bufptr - oci->buffer + needed) > oci->size)) {
335 /* no data, or the request is too big to fit in the buffer */
337 if ((gotnow > 0) && (oci->bufptr != oci->buffer))
338 /* save the data we've already read */
339 memmove(oci->buffer, oci->bufptr, gotnow);
340 if (needed > oci->size) {
341 /* make buffer bigger to accomodate request */
344 ibuf = (char *) realloc(oci->buffer, needed);
352 oci->bufptr = oci->buffer;
353 oci->bufcnt = gotnow;
355 /* XXX this is a workaround. This function is sometimes called
356 * after the trans_conn has been freed. In this case trans_conn
357 * will be null. Really ought to restructure things so that we
358 * never get here in those circumstances.
360 if (!oc->trans_conn) {
361 /* treat as if an error occured on the read, which is what
367 result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
368 oci->size - oci->bufcnt);
370 if ((result < 0) && ETEST(errno)) {
371 #if defined(SVR4) && defined(__i386__) && !defined(sun)
375 YieldControlNoInput(fd);
382 oci->bufcnt += result;
384 /* free up some space after huge requests */
385 if ((oci->size > BUFWATERMARK) &&
386 (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) {
389 ibuf = (char *) realloc(oci->buffer, BUFSIZE);
393 oci->bufptr = ibuf + oci->bufcnt - gotnow;
396 if (need_header && gotnow >= needed) {
397 /* We wanted an xReq, now we've gotten it. */
398 request = (xReq *) oci->bufptr;
399 needed = get_req_len(request, client);
400 if (!needed && client->big_requests) {
402 if (gotnow < sizeof(xBigReq))
403 needed = bytes_to_int32(sizeof(xBigReq));
405 needed = get_big_req_len(request, client);
407 client->req_len = needed;
410 if (gotnow < needed) {
411 /* Still don't have enough; punt. */
412 YieldControlNoInput(fd);
417 if (client->big_requests)
418 needed = sizeof(xBigReq);
420 needed = sizeof(xReq);
423 /* If there are bytes to ignore, ignore them now. */
425 if (oci->ignoreBytes > 0) {
426 assert(needed == oci->ignoreBytes || needed == oci->size);
428 * The _XSERVTransRead call above may return more or fewer bytes than we
429 * want to ignore. Ignore the smaller of the two sizes.
431 if (gotnow < needed) {
432 oci->ignoreBytes -= gotnow;
433 oci->bufptr += gotnow;
437 oci->ignoreBytes -= needed;
438 oci->bufptr += needed;
444 oci->lenLastReq = needed;
447 * Check to see if client has at least one whole request in the
448 * buffer beyond the request we're returning to the caller.
449 * If there is only a partial request, treat like buffer
450 * is empty so that select() will be called again and other clients
451 * can get into the queue.
455 if (gotnow >= sizeof(xReq)) {
456 request = (xReq *) (oci->bufptr + needed);
457 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))))
463 FD_SET(fd, &ClientsWithInput);
465 if (!SmartScheduleDisable)
466 FD_CLR(fd, &ClientsWithInput);
468 YieldControlNoInput(fd);
474 if (!SmartScheduleDisable)
475 FD_CLR(fd, &ClientsWithInput);
477 YieldControlNoInput(fd);
479 if (SmartScheduleDisable)
480 if (++timesThisConnection >= MAX_TIMES_PER)
483 request = (xReq *) oci->bufptr;
484 oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
485 *(xReq *) oci->bufptr = *request;
486 oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
487 client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq));
489 client->requestBuffer = (void *) oci->bufptr;
490 #ifdef DEBUG_COMMUNICATION
492 xReq *req = client->requestBuffer;
494 ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
495 client->index, req->reqType, req->data, req->length);
503 ReadFdFromClient(ClientPtr client)
507 if (client->req_fds > 0) {
508 OsCommPtr oc = (OsCommPtr) client->osPrivate;
511 fd = _XSERVTransRecvFd(oc->trans_conn);
513 LogMessage(X_ERROR, "Request asks for FD without setting req_fds\n");
518 WriteFdToClient(ClientPtr client, int fd, Bool do_close)
520 OsCommPtr oc = (OsCommPtr) client->osPrivate;
522 return _XSERVTransSendFd(oc->trans_conn, fd, do_close);
526 /*****************************************************************
528 * Splice a consed up (possibly partial) request in as the next request.
530 **********************/
533 InsertFakeRequest(ClientPtr client, char *data, int count)
535 OsCommPtr oc = (OsCommPtr) client->osPrivate;
536 ConnectionInputPtr oci = oc->input;
540 NextAvailableInput(oc);
543 if ((oci = FreeInputs))
544 FreeInputs = oci->next;
545 else if (!(oci = AllocateInputBuffer()))
549 oci->bufptr += oci->lenLastReq;
551 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
552 if ((gotnow + count) > oci->size) {
555 ibuf = (char *) realloc(oci->buffer, gotnow + count);
558 oci->size = gotnow + count;
560 oci->bufptr = ibuf + oci->bufcnt - gotnow;
562 moveup = count - (oci->bufptr - oci->buffer);
565 memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
566 oci->bufptr += moveup;
567 oci->bufcnt += moveup;
569 memmove(oci->bufptr - count, data, count);
570 oci->bufptr -= count;
572 if ((gotnow >= sizeof(xReq)) &&
573 (gotnow >= (int) (get_req_len((xReq *) oci->bufptr, client) << 2)))
574 FD_SET(fd, &ClientsWithInput);
576 YieldControlNoInput(fd);
580 /*****************************************************************
581 * ResetRequestFromClient
582 * Reset to reexecute the current request, and yield.
584 **********************/
587 ResetCurrentRequest(ClientPtr client)
589 OsCommPtr oc = (OsCommPtr) client->osPrivate;
590 register ConnectionInputPtr oci = oc->input;
592 register xReq *request;
595 if (AvailableInput == oc)
596 AvailableInput = (OsCommPtr) NULL;
598 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
599 if (gotnow < sizeof(xReq)) {
600 YieldControlNoInput(fd);
603 request = (xReq *) oci->bufptr;
604 needed = get_req_len(request, client);
605 if (!needed && client->big_requests) {
606 oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
607 *(xReq *) oci->bufptr = *request;
608 ((xBigReq *) oci->bufptr)->length = client->req_len;
609 if (client->swapped) {
610 swapl(&((xBigReq *) oci->bufptr)->length);
613 if (gotnow >= (needed << 2)) {
614 if (FD_ISSET(fd, &AllClients)) {
615 FD_SET(fd, &ClientsWithInput);
618 FD_SET(fd, &IgnoredClientsWithInput);
623 YieldControlNoInput(fd);
627 /********************
629 * Flush all clients with output. However, if some client still
630 * has input in the queue (more requests), then don't flush. This
631 * will prevent the output queue from being flushed every time around
632 * the round robin queue. Now, some say that it SHOULD be flushed
633 * every time around, but...
635 **********************/
640 register int index, base;
641 register fd_mask mask; /* raphael */
643 register ClientPtr client;
644 Bool newoutput = NewOutputPending;
647 fd_set newOutputPending;
651 CallCallbacks(&FlushCallback, NULL);
657 * It may be that some client still has critical output pending,
658 * but he is not yet ready to receive it anyway, so we will
659 * simply wait for the select to tell us when he's ready to receive.
661 CriticalOutputPending = FALSE;
662 NewOutputPending = FALSE;
665 for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) {
666 mask = OutputPending.fds_bits[base];
667 OutputPending.fds_bits[base] = 0;
669 index = ffs(mask) - 1;
670 mask &= ~lowbit(mask);
672 ConnectionTranslation[(base * (sizeof(fd_mask) * 8)) +
675 client = clients[index];
676 if (client->clientGone)
678 oc = (OsCommPtr) client->osPrivate;
679 if (FD_ISSET(oc->fd, &ClientsWithInput)) {
680 FD_SET(oc->fd, &OutputPending); /* set the bit again */
681 NewOutputPending = TRUE;
684 (void) FlushClient(client, oc, (char *) NULL, 0);
688 FD_ZERO(&newOutputPending);
689 for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) {
690 index = XFD_FD(&OutputPending, base);
691 if ((index = GetConnectionTranslation(index)) == 0)
693 client = clients[index];
694 if (client->clientGone)
696 oc = (OsCommPtr) client->osPrivate;
697 if (FD_ISSET(oc->fd, &ClientsWithInput)) {
698 FD_SET(oc->fd, &newOutputPending); /* set the bit again */
699 NewOutputPending = TRUE;
702 (void) FlushClient(client, oc, (char *) NULL, 0);
704 XFD_COPYSET(&newOutputPending, &OutputPending);
709 FlushIfCriticalOutputPending(void)
711 if (CriticalOutputPending)
716 SetCriticalOutputPending(void)
718 CriticalOutputPending = TRUE;
723 * Copies buf into ClientPtr.buf if it fits (with padding), else
724 * flushes ClientPtr.buf and buf to client. As of this writing,
725 * every use of WriteToClient is cast to void, and the result
726 * is ignored. Potentially, this could be used by requests
727 * that are sending several chunks of data and want to break
728 * out of a loop on error. Thus, we will leave the type of
729 * this routine as int.
733 WriteToClient(ClientPtr who, int count, const void *__buf)
736 ConnectionOutputPtr oco;
738 const char *buf = __buf;
740 #ifdef DEBUG_COMMUNICATION
741 Bool multicount = FALSE;
743 if (!count || !who || who == serverClient || who->clientGone)
747 #ifdef DEBUG_COMMUNICATION
754 if (!who->replyBytesRemaining) {
757 rep = (xGenericReply *) buf;
758 if (rep->sequenceNumber == who->sequence) {
759 snprintf(info, 127, "Xreply: type: 0x%x data: 0x%x "
760 "len: %i seq#: 0x%x", rep->type, rep->data1,
761 rep->length, rep->sequenceNumber);
766 err = (xError *) buf;
767 snprintf(info, 127, "Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
768 "min: %x", err->errorCode, err->resourceID,
769 err->minorCode, err->majorCode);
772 if ((buf[0] & 0x7f) == KeymapNotify)
773 snprintf(info, 127, "KeymapNotifyEvent: %i", buf[0]);
776 snprintf(info, 127, "XEvent: type: 0x%x detail: 0x%x "
777 "seq#: 0x%x", ev->u.u.type, ev->u.u.detail,
778 ev->u.u.sequenceNumber);
781 ErrorF("REPLY: ClientIDX: %i %s\n", who->index, info);
789 if ((oco = FreeOutputs)) {
790 FreeOutputs = oco->next;
792 else if (!(oco = AllocateOutputBuffer())) {
793 if (oc->trans_conn) {
794 _XSERVTransDisconnect(oc->trans_conn);
795 _XSERVTransClose(oc->trans_conn);
796 oc->trans_conn = NULL;
798 MarkClientException(who);
804 padBytes = padding_for_int32(count);
807 ReplyInfoRec replyinfo;
809 replyinfo.client = who;
810 replyinfo.replyData = buf;
811 replyinfo.dataLenBytes = count + padBytes;
812 replyinfo.padBytes = padBytes;
813 if (who->replyBytesRemaining) { /* still sending data of an earlier reply */
814 who->replyBytesRemaining -= count + padBytes;
815 replyinfo.startOfReply = FALSE;
816 replyinfo.bytesRemaining = who->replyBytesRemaining;
817 CallCallbacks((&ReplyCallback), (void *) &replyinfo);
819 else if (who->clientState == ClientStateRunning && buf[0] == X_Reply) { /* start of new reply */
821 unsigned long bytesleft;
823 replylen = ((const xGenericReply *) buf)->length;
826 bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
827 replyinfo.startOfReply = TRUE;
828 replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
829 CallCallbacks((&ReplyCallback), (void *) &replyinfo);
832 #ifdef DEBUG_COMMUNICATION
833 else if (multicount) {
834 if (who->replyBytesRemaining) {
835 who->replyBytesRemaining -= (count + padBytes);
840 replylen = ((xGenericReply *) buf)->length;
841 who->replyBytesRemaining =
842 (replylen * 4) + SIZEOF(xReply) - count - padBytes;
846 if (oco->count == 0 || oco->count + count + padBytes > oco->size) {
847 FD_CLR(oc->fd, &OutputPending);
848 if (!XFD_ANYSET(&OutputPending)) {
849 CriticalOutputPending = FALSE;
850 NewOutputPending = FALSE;
854 CallCallbacks(&FlushCallback, NULL);
856 return FlushClient(who, oc, buf, count);
859 NewOutputPending = TRUE;
860 FD_SET(oc->fd, &OutputPending);
861 memmove((char *) oco->buf + oco->count, buf, count);
864 memset(oco->buf + oco->count, '\0', padBytes);
865 oco->count += padBytes;
870 /********************
872 * If the client isn't keeping up with us, then we try to continue
873 * buffering the data and set the apropriate bit in ClientsWritable
874 * (which is used by WaitFor in the select). If the connection yields
875 * a permanent error, or we can't allocate any more space, we then
876 * close the connection.
878 **********************/
881 FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
883 ConnectionOutputPtr oco = oc->output;
884 int connection = oc->fd;
885 XtransConnInfo trans_conn = oc->trans_conn;
887 static char padBuffer[3];
888 const char *extraBuf = __extraBuf;
897 padsize = padding_for_int32(extraCount);
898 notWritten = oco->count + extraCount + padsize;
904 long before = written; /* amount of whole thing written */
905 long remain = todo; /* amount to try this time, <= notWritten */
909 /* You could be very general here and have "in" and "out" iovecs
910 * and write a loop without using a macro, but what the heck. This
913 * how much of this piece is new?
914 * if more new then we are trying this time, clamp
916 * then bump down amount already written, for next piece
917 * else put new stuff in iovec, will need all of next piece
919 * Note that todo had better be at least 1 or else we'll end up
922 #define InsertIOV(pointer, length) \
923 len = (length) - before; \
929 iov[i].iov_len = len; \
930 iov[i].iov_base = (pointer) + before; \
936 InsertIOV((char *) oco->buf, oco->count)
937 InsertIOV((char *) extraBuf, extraCount)
938 InsertIOV(padBuffer, padsize)
941 if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) {
946 else if (ETEST(errno)
947 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
950 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
951 || ((errno == EMSGSIZE) && (todo == 1))
954 /* If we've arrived here, then the client is stuffed to the gills
955 and not ready to accept more. Make a note of it and buffer
957 FD_SET(connection, &ClientsWriteBlocked);
958 AnyClientsWriteBlocked = TRUE;
960 if (written < oco->count) {
962 oco->count -= written;
963 memmove((char *) oco->buf,
964 (char *) oco->buf + written, oco->count);
969 written -= oco->count;
973 if (notWritten > oco->size) {
976 obuf = (unsigned char *) realloc(oco->buf,
977 notWritten + BUFSIZE);
979 _XSERVTransDisconnect(oc->trans_conn);
980 _XSERVTransClose(oc->trans_conn);
981 oc->trans_conn = NULL;
982 MarkClientException(who);
986 oco->size = notWritten + BUFSIZE;
990 /* If the amount written extended into the padBuffer, then the
991 difference "extraCount - written" may be less than 0 */
992 if ((len = extraCount - written) > 0)
993 memmove((char *) oco->buf + oco->count,
994 extraBuf + written, len);
996 oco->count = notWritten; /* this will include the pad */
997 /* return only the amount explicitly requested */
1000 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
1001 else if (errno == EMSGSIZE) {
1006 if (oc->trans_conn) {
1007 _XSERVTransDisconnect(oc->trans_conn);
1008 _XSERVTransClose(oc->trans_conn);
1009 oc->trans_conn = NULL;
1011 MarkClientException(who);
1017 /* everything was flushed out */
1019 /* check to see if this client was write blocked */
1020 if (AnyClientsWriteBlocked) {
1021 FD_CLR(oc->fd, &ClientsWriteBlocked);
1022 if (!XFD_ANYSET(&ClientsWriteBlocked))
1023 AnyClientsWriteBlocked = FALSE;
1025 if (oco->size > BUFWATERMARK) {
1030 oco->next = FreeOutputs;
1033 oc->output = (ConnectionOutputPtr) NULL;
1034 return extraCount; /* return only the amount explicitly requested */
1037 static ConnectionInputPtr
1038 AllocateInputBuffer(void)
1040 ConnectionInputPtr oci;
1042 oci = malloc(sizeof(ConnectionInput));
1045 oci->buffer = malloc(BUFSIZE);
1050 oci->size = BUFSIZE;
1051 oci->bufptr = oci->buffer;
1053 oci->lenLastReq = 0;
1054 oci->ignoreBytes = 0;
1058 static ConnectionOutputPtr
1059 AllocateOutputBuffer(void)
1061 ConnectionOutputPtr oco;
1063 oco = malloc(sizeof(ConnectionOutput));
1066 oco->buf = calloc(1, BUFSIZE);
1071 oco->size = BUFSIZE;
1077 FreeOsBuffers(OsCommPtr oc)
1079 ConnectionInputPtr oci;
1080 ConnectionOutputPtr oco;
1082 if (AvailableInput == oc)
1083 AvailableInput = (OsCommPtr) NULL;
1084 if ((oci = oc->input)) {
1091 oci->next = (ConnectionInputPtr) NULL;
1092 oci->bufptr = oci->buffer;
1094 oci->lenLastReq = 0;
1095 oci->ignoreBytes = 0;
1098 if ((oco = oc->output)) {
1105 oco->next = (ConnectionOutputPtr) NULL;
1112 ResetOsBuffers(void)
1114 ConnectionInputPtr oci;
1115 ConnectionOutputPtr oco;
1117 while ((oci = FreeInputs)) {
1118 FreeInputs = oci->next;
1122 while ((oco = FreeOutputs)) {
1123 FreeOutputs = oco->next;