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 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
106 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
109 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
110 #else /* WIN32 The socket errorcodes differ from the normal errors */
111 #define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
114 static Bool CriticalOutputPending
;
115 static int timesThisConnection
= 0;
116 static ConnectionInputPtr FreeInputs
= (ConnectionInputPtr
) NULL
;
117 static ConnectionOutputPtr FreeOutputs
= (ConnectionOutputPtr
) NULL
;
118 static OsCommPtr AvailableInput
= (OsCommPtr
) NULL
;
120 #define get_req_len(req,cli) ((cli)->swapped ? \
121 lswaps((req)->length) : (req)->length)
123 #include <X11/extensions/bigreqsproto.h>
125 #define get_big_req_len(req,cli) ((cli)->swapped ? \
126 lswapl(((xBigReq *)(req))->length) : \
127 ((xBigReq *)(req))->length)
129 #define MAX_TIMES_PER 10
131 #define BUFWATERMARK 8192
134 * A lot of the code in this file manipulates a ConnectionInputPtr:
136 * -----------------------------------------------
137 * |------- bufcnt ------->| | |
138 * | |- gotnow ->| | |
139 * | |-------- needed ------>| |
140 * |-----------+--------- size --------+---------->|
141 * -----------------------------------------------
146 * buffer is a pointer to the start of the buffer.
147 * bufptr points to the start of the current request.
148 * bufcnt counts how many bytes are in the buffer.
149 * size is the size of the buffer in bytes.
151 * In several of the functions, gotnow and needed are local variables
152 * that do the following:
154 * gotnow is the number of bytes of the request that we're
155 * trying to read that are currently in the buffer.
156 * Typically, gotnow = (buffer + bufcnt) - bufptr
158 * needed = the length of the request that we're trying to
159 * read. Watch out: needed sometimes counts bytes and sometimes
163 /*****************************************************************
164 * ReadRequestFromClient
165 * Returns one request in client->requestBuffer. The request
166 * length will be in client->req_len. Return status is:
168 * > 0 if successful, specifies length in bytes of the request
169 * = 0 if entire request is not yet available
170 * < 0 if client should be terminated
172 * The request returned must be contiguous so that it can be
173 * cast in the dispatcher to the correct request type. Because requests
174 * are variable length, ReadRequestFromClient() must look at the first 4
175 * or 8 bytes of a request to determine the length (the request length is
176 * in the 3rd and 4th bytes of the request unless it is a Big Request
177 * (see the Big Request Extension), in which case the 3rd and 4th bytes
178 * are zero and the following 4 bytes are the request length.
180 * Note: in order to make the server scheduler (WaitForSomething())
181 * "fair", the ClientsWithInput mask is used. This mask tells which
182 * clients have FULL requests left in their buffers. Clients with
183 * partial requests require a read. Basically, client buffers
184 * are drained before select() is called again. But, we can't keep
185 * reading from a client that is sending buckets of data (or has
186 * a partial request) because others clients need to be scheduled.
187 *****************************************************************/
192 isItTimeToYield
= TRUE
;
193 timesThisConnection
= 0;
197 YieldControlNoInput(int fd
)
200 FD_CLR(fd
, &ClientsWithInput
);
204 YieldControlDeath(void)
206 timesThisConnection
= 0;
209 /* If an input buffer was empty, either free it if it is too big or link it
210 * into our list of free input buffers. This means that different clients can
211 * share the same input buffer (at different times). This was done to save
215 NextAvailableInput(OsCommPtr oc
)
217 if (AvailableInput
) {
218 if (AvailableInput
!= oc
) {
219 ConnectionInputPtr aci
= AvailableInput
->input
;
221 if (aci
->size
> BUFWATERMARK
) {
226 aci
->next
= FreeInputs
;
229 AvailableInput
->input
= NULL
;
231 AvailableInput
= NULL
;
236 ReadRequestFromClient(ClientPtr client
)
238 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
239 ConnectionInputPtr oci
= oc
->input
;
241 unsigned int gotnow
, needed
;
243 register xReq
*request
;
247 NextAvailableInput(oc
);
249 /* make sure we have an input buffer */
252 if ((oci
= FreeInputs
)) {
253 FreeInputs
= oci
->next
;
255 else if (!(oci
= AllocateInputBuffer())) {
263 /* Discard any unused file descriptors */
264 while (client
->req_fds
> 0) {
265 int req_fd
= ReadFdFromClient(client
);
270 /* advance to start of next request */
272 oci
->bufptr
+= oci
->lenLastReq
;
276 gotnow
= oci
->bufcnt
+ oci
->buffer
- oci
->bufptr
;
278 if (oci
->ignoreBytes
> 0) {
279 if (oci
->ignoreBytes
> oci
->size
)
282 needed
= oci
->ignoreBytes
;
284 else if (gotnow
< sizeof(xReq
)) {
285 /* We don't have an entire xReq yet. Can't tell how big
286 * the request will be until we get the whole xReq.
288 needed
= sizeof(xReq
);
292 /* We have a whole xReq. We can tell how big the whole
293 * request will be unless it is a Big Request.
295 request
= (xReq
*) oci
->bufptr
;
296 needed
= get_req_len(request
, client
);
297 if (!needed
&& client
->big_requests
) {
298 /* It's a Big Request. */
300 if (gotnow
< sizeof(xBigReq
)) {
301 /* Still need more data to tell just how big. */
302 needed
= bytes_to_int32(sizeof(xBigReq
)); /* needed is in CARD32s now */
306 needed
= get_big_req_len(request
, client
);
308 client
->req_len
= needed
;
309 needed
<<= 2; /* needed is in bytes now */
311 if (gotnow
< needed
) {
312 /* Need to read more data, either so that we can get a
313 * complete xReq (if need_header is TRUE), a complete
314 * xBigReq (if move_header is TRUE), or the rest of the
315 * request (if need_header and move_header are both FALSE).
319 if (needed
> maxBigRequestSize
<< 2) {
320 /* request is too big for us to handle */
322 * Mark the rest of it as needing to be ignored, and then return
323 * the full size. Dispatch() will turn it into a BadLength error.
325 oci
->ignoreBytes
= needed
- gotnow
;
326 oci
->lenLastReq
= gotnow
;
329 if ((gotnow
== 0) || ((oci
->bufptr
- oci
->buffer
+ needed
) > oci
->size
)) {
330 /* no data, or the request is too big to fit in the buffer */
332 if ((gotnow
> 0) && (oci
->bufptr
!= oci
->buffer
))
333 /* save the data we've already read */
334 memmove(oci
->buffer
, oci
->bufptr
, gotnow
);
335 if (needed
> oci
->size
) {
336 /* make buffer bigger to accomodate request */
339 ibuf
= (char *) realloc(oci
->buffer
, needed
);
347 oci
->bufptr
= oci
->buffer
;
348 oci
->bufcnt
= gotnow
;
350 /* XXX this is a workaround. This function is sometimes called
351 * after the trans_conn has been freed. In this case trans_conn
352 * will be null. Really ought to restructure things so that we
353 * never get here in those circumstances.
355 if (!oc
->trans_conn
) {
356 /* treat as if an error occured on the read, which is what
362 result
= _XSERVTransRead(oc
->trans_conn
, oci
->buffer
+ oci
->bufcnt
,
363 oci
->size
- oci
->bufcnt
);
365 if ((result
< 0) && ETEST(errno
)) {
366 #if defined(SVR4) && defined(__i386__) && !defined(sun)
370 YieldControlNoInput(fd
);
377 oci
->bufcnt
+= result
;
379 /* free up some space after huge requests */
380 if ((oci
->size
> BUFWATERMARK
) &&
381 (oci
->bufcnt
< BUFSIZE
) && (needed
< BUFSIZE
)) {
384 ibuf
= (char *) realloc(oci
->buffer
, BUFSIZE
);
388 oci
->bufptr
= ibuf
+ oci
->bufcnt
- gotnow
;
391 if (need_header
&& gotnow
>= needed
) {
392 /* We wanted an xReq, now we've gotten it. */
393 request
= (xReq
*) oci
->bufptr
;
394 needed
= get_req_len(request
, client
);
395 if (!needed
&& client
->big_requests
) {
397 if (gotnow
< sizeof(xBigReq
))
398 needed
= bytes_to_int32(sizeof(xBigReq
));
400 needed
= get_big_req_len(request
, client
);
402 client
->req_len
= needed
;
405 if (gotnow
< needed
) {
406 /* Still don't have enough; punt. */
407 YieldControlNoInput(fd
);
412 if (client
->big_requests
)
413 needed
= sizeof(xBigReq
);
415 needed
= sizeof(xReq
);
418 /* If there are bytes to ignore, ignore them now. */
420 if (oci
->ignoreBytes
> 0) {
421 assert(needed
== oci
->ignoreBytes
|| needed
== oci
->size
);
423 * The _XSERVTransRead call above may return more or fewer bytes than we
424 * want to ignore. Ignore the smaller of the two sizes.
426 if (gotnow
< needed
) {
427 oci
->ignoreBytes
-= gotnow
;
428 oci
->bufptr
+= gotnow
;
432 oci
->ignoreBytes
-= needed
;
433 oci
->bufptr
+= needed
;
439 oci
->lenLastReq
= needed
;
442 * Check to see if client has at least one whole request in the
443 * buffer beyond the request we're returning to the caller.
444 * If there is only a partial request, treat like buffer
445 * is empty so that select() will be called again and other clients
446 * can get into the queue.
450 if (gotnow
>= sizeof(xReq
)) {
451 request
= (xReq
*) (oci
->bufptr
+ needed
);
452 if (gotnow
>= (result
= (get_req_len(request
, client
) << 2))
454 (client
->big_requests
&&
455 (gotnow
>= sizeof(xBigReq
) &&
456 gotnow
>= (get_big_req_len(request
, client
) << 2))))
458 FD_SET(fd
, &ClientsWithInput
);
460 if (!SmartScheduleDisable
)
461 FD_CLR(fd
, &ClientsWithInput
);
463 YieldControlNoInput(fd
);
469 if (!SmartScheduleDisable
)
470 FD_CLR(fd
, &ClientsWithInput
);
472 YieldControlNoInput(fd
);
474 if (SmartScheduleDisable
)
475 if (++timesThisConnection
>= MAX_TIMES_PER
)
478 request
= (xReq
*) oci
->bufptr
;
479 oci
->bufptr
+= (sizeof(xBigReq
) - sizeof(xReq
));
480 *(xReq
*) oci
->bufptr
= *request
;
481 oci
->lenLastReq
-= (sizeof(xBigReq
) - sizeof(xReq
));
482 client
->req_len
-= bytes_to_int32(sizeof(xBigReq
) - sizeof(xReq
));
484 client
->requestBuffer
= (pointer
) oci
->bufptr
;
485 #ifdef DEBUG_COMMUNICATION
487 xReq
*req
= client
->requestBuffer
;
489 ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
490 client
->index
, req
->reqType
, req
->data
, req
->length
);
498 ReadFdFromClient(ClientPtr client
)
502 if (client
->req_fds
> 0) {
503 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
506 fd
= _XSERVTransRecvFd(oc
->trans_conn
);
508 LogMessage(X_ERROR
, "Request asks for FD without setting req_fds\n");
513 WriteFdToClient(ClientPtr client
, int fd
, Bool do_close
)
515 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
517 return _XSERVTransSendFd(oc
->trans_conn
, fd
, do_close
);
521 /*****************************************************************
523 * Splice a consed up (possibly partial) request in as the next request.
525 **********************/
528 InsertFakeRequest(ClientPtr client
, char *data
, int count
)
530 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
531 ConnectionInputPtr oci
= oc
->input
;
535 NextAvailableInput(oc
);
538 if ((oci
= FreeInputs
))
539 FreeInputs
= oci
->next
;
540 else if (!(oci
= AllocateInputBuffer()))
544 oci
->bufptr
+= oci
->lenLastReq
;
546 gotnow
= oci
->bufcnt
+ oci
->buffer
- oci
->bufptr
;
547 if ((gotnow
+ count
) > oci
->size
) {
550 ibuf
= (char *) realloc(oci
->buffer
, gotnow
+ count
);
553 oci
->size
= gotnow
+ count
;
555 oci
->bufptr
= ibuf
+ oci
->bufcnt
- gotnow
;
557 moveup
= count
- (oci
->bufptr
- oci
->buffer
);
560 memmove(oci
->bufptr
+ moveup
, oci
->bufptr
, gotnow
);
561 oci
->bufptr
+= moveup
;
562 oci
->bufcnt
+= moveup
;
564 memmove(oci
->bufptr
- count
, data
, count
);
565 oci
->bufptr
-= count
;
567 if ((gotnow
>= sizeof(xReq
)) &&
568 (gotnow
>= (int) (get_req_len((xReq
*) oci
->bufptr
, client
) << 2)))
569 FD_SET(fd
, &ClientsWithInput
);
571 YieldControlNoInput(fd
);
575 /*****************************************************************
576 * ResetRequestFromClient
577 * Reset to reexecute the current request, and yield.
579 **********************/
582 ResetCurrentRequest(ClientPtr client
)
584 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
585 register ConnectionInputPtr oci
= oc
->input
;
587 register xReq
*request
;
590 if (AvailableInput
== oc
)
591 AvailableInput
= (OsCommPtr
) NULL
;
593 gotnow
= oci
->bufcnt
+ oci
->buffer
- oci
->bufptr
;
594 if (gotnow
< sizeof(xReq
)) {
595 YieldControlNoInput(fd
);
598 request
= (xReq
*) oci
->bufptr
;
599 needed
= get_req_len(request
, client
);
600 if (!needed
&& client
->big_requests
) {
601 oci
->bufptr
-= sizeof(xBigReq
) - sizeof(xReq
);
602 *(xReq
*) oci
->bufptr
= *request
;
603 ((xBigReq
*) oci
->bufptr
)->length
= client
->req_len
;
604 if (client
->swapped
) {
605 swapl(&((xBigReq
*) oci
->bufptr
)->length
);
608 if (gotnow
>= (needed
<< 2)) {
609 if (FD_ISSET(fd
, &AllClients
)) {
610 FD_SET(fd
, &ClientsWithInput
);
613 FD_SET(fd
, &IgnoredClientsWithInput
);
618 YieldControlNoInput(fd
);
622 /********************
624 * Flush all clients with output. However, if some client still
625 * has input in the queue (more requests), then don't flush. This
626 * will prevent the output queue from being flushed every time around
627 * the round robin queue. Now, some say that it SHOULD be flushed
628 * every time around, but...
630 **********************/
635 register int index
, base
;
636 register fd_mask mask
; /* raphael */
638 register ClientPtr client
;
639 Bool newoutput
= NewOutputPending
;
642 fd_set newOutputPending
;
646 CallCallbacks(&FlushCallback
, NULL
);
652 * It may be that some client still has critical output pending,
653 * but he is not yet ready to receive it anyway, so we will
654 * simply wait for the select to tell us when he's ready to receive.
656 CriticalOutputPending
= FALSE
;
657 NewOutputPending
= FALSE
;
660 for (base
= 0; base
< howmany(XFD_SETSIZE
, NFDBITS
); base
++) {
661 mask
= OutputPending
.fds_bits
[base
];
662 OutputPending
.fds_bits
[base
] = 0;
664 index
= ffs(mask
) - 1;
665 mask
&= ~lowbit(mask
);
667 ConnectionTranslation
[(base
* (sizeof(fd_mask
) * 8)) +
670 client
= clients
[index
];
671 if (client
->clientGone
)
673 oc
= (OsCommPtr
) client
->osPrivate
;
674 if (FD_ISSET(oc
->fd
, &ClientsWithInput
)) {
675 FD_SET(oc
->fd
, &OutputPending
); /* set the bit again */
676 NewOutputPending
= TRUE
;
679 (void) FlushClient(client
, oc
, (char *) NULL
, 0);
683 FD_ZERO(&newOutputPending
);
684 for (base
= 0; base
< XFD_SETCOUNT(&OutputPending
); base
++) {
685 index
= XFD_FD(&OutputPending
, base
);
686 if ((index
= GetConnectionTranslation(index
)) == 0)
688 client
= clients
[index
];
689 if (client
->clientGone
)
691 oc
= (OsCommPtr
) client
->osPrivate
;
692 if (FD_ISSET(oc
->fd
, &ClientsWithInput
)) {
693 FD_SET(oc
->fd
, &newOutputPending
); /* set the bit again */
694 NewOutputPending
= TRUE
;
697 (void) FlushClient(client
, oc
, (char *) NULL
, 0);
699 XFD_COPYSET(&newOutputPending
, &OutputPending
);
704 FlushIfCriticalOutputPending(void)
706 if (CriticalOutputPending
)
711 SetCriticalOutputPending(void)
713 CriticalOutputPending
= TRUE
;
718 * Copies buf into ClientPtr.buf if it fits (with padding), else
719 * flushes ClientPtr.buf and buf to client. As of this writing,
720 * every use of WriteToClient is cast to void, and the result
721 * is ignored. Potentially, this could be used by requests
722 * that are sending several chunks of data and want to break
723 * out of a loop on error. Thus, we will leave the type of
724 * this routine as int.
728 WriteToClient(ClientPtr who
, int count
, const void *__buf
)
731 ConnectionOutputPtr oco
;
733 const char *buf
= __buf
;
735 #ifdef DEBUG_COMMUNICATION
736 Bool multicount
= FALSE
;
738 if (!count
|| !who
|| who
== serverClient
|| who
->clientGone
)
742 #ifdef DEBUG_COMMUNICATION
749 if (!who
->replyBytesRemaining
) {
752 rep
= (xGenericReply
*) buf
;
753 if (rep
->sequenceNumber
== who
->sequence
) {
754 snprintf(info
, 127, "Xreply: type: 0x%x data: 0x%x "
755 "len: %i seq#: 0x%x", rep
->type
, rep
->data1
,
756 rep
->length
, rep
->sequenceNumber
);
761 err
= (xError
*) buf
;
762 snprintf(info
, 127, "Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
763 "min: %x", err
->errorCode
, err
->resourceID
,
764 err
->minorCode
, err
->majorCode
);
767 if ((buf
[0] & 0x7f) == KeymapNotify
)
768 snprintf(info
, 127, "KeymapNotifyEvent: %i", buf
[0]);
771 snprintf(info
, 127, "XEvent: type: 0x%x detail: 0x%x "
772 "seq#: 0x%x", ev
->u
.u
.type
, ev
->u
.u
.detail
,
773 ev
->u
.u
.sequenceNumber
);
776 ErrorF("REPLY: ClientIDX: %i %s\n", who
->index
, info
);
784 if ((oco
= FreeOutputs
)) {
785 FreeOutputs
= oco
->next
;
787 else if (!(oco
= AllocateOutputBuffer())) {
788 if (oc
->trans_conn
) {
789 _XSERVTransDisconnect(oc
->trans_conn
);
790 _XSERVTransClose(oc
->trans_conn
);
791 oc
->trans_conn
= NULL
;
793 MarkClientException(who
);
799 padBytes
= padding_for_int32(count
);
802 ReplyInfoRec replyinfo
;
804 replyinfo
.client
= who
;
805 replyinfo
.replyData
= buf
;
806 replyinfo
.dataLenBytes
= count
+ padBytes
;
807 replyinfo
.padBytes
= padBytes
;
808 if (who
->replyBytesRemaining
) { /* still sending data of an earlier reply */
809 who
->replyBytesRemaining
-= count
+ padBytes
;
810 replyinfo
.startOfReply
= FALSE
;
811 replyinfo
.bytesRemaining
= who
->replyBytesRemaining
;
812 CallCallbacks((&ReplyCallback
), (pointer
) &replyinfo
);
814 else if (who
->clientState
== ClientStateRunning
&& buf
[0] == X_Reply
) { /* start of new reply */
816 unsigned long bytesleft
;
818 replylen
= ((const xGenericReply
*) buf
)->length
;
821 bytesleft
= (replylen
* 4) + SIZEOF(xReply
) - count
- padBytes
;
822 replyinfo
.startOfReply
= TRUE
;
823 replyinfo
.bytesRemaining
= who
->replyBytesRemaining
= bytesleft
;
824 CallCallbacks((&ReplyCallback
), (pointer
) &replyinfo
);
827 #ifdef DEBUG_COMMUNICATION
828 else if (multicount
) {
829 if (who
->replyBytesRemaining
) {
830 who
->replyBytesRemaining
-= (count
+ padBytes
);
835 replylen
= ((xGenericReply
*) buf
)->length
;
836 who
->replyBytesRemaining
=
837 (replylen
* 4) + SIZEOF(xReply
) - count
- padBytes
;
841 if (oco
->count
== 0 || oco
->count
+ count
+ padBytes
> oco
->size
) {
842 FD_CLR(oc
->fd
, &OutputPending
);
843 if (!XFD_ANYSET(&OutputPending
)) {
844 CriticalOutputPending
= FALSE
;
845 NewOutputPending
= FALSE
;
849 CallCallbacks(&FlushCallback
, NULL
);
851 return FlushClient(who
, oc
, buf
, count
);
854 NewOutputPending
= TRUE
;
855 FD_SET(oc
->fd
, &OutputPending
);
856 memmove((char *) oco
->buf
+ oco
->count
, buf
, count
);
859 memset(oco
->buf
+ oco
->count
, '\0', padBytes
);
860 oco
->count
+= padBytes
;
865 /********************
867 * If the client isn't keeping up with us, then we try to continue
868 * buffering the data and set the apropriate bit in ClientsWritable
869 * (which is used by WaitFor in the select). If the connection yields
870 * a permanent error, or we can't allocate any more space, we then
871 * close the connection.
873 **********************/
876 FlushClient(ClientPtr who
, OsCommPtr oc
, const void *__extraBuf
, int extraCount
)
878 ConnectionOutputPtr oco
= oc
->output
;
879 int connection
= oc
->fd
;
880 XtransConnInfo trans_conn
= oc
->trans_conn
;
882 static char padBuffer
[3];
883 const char *extraBuf
= __extraBuf
;
892 padsize
= padding_for_int32(extraCount
);
893 notWritten
= oco
->count
+ extraCount
+ padsize
;
899 long before
= written
; /* amount of whole thing written */
900 long remain
= todo
; /* amount to try this time, <= notWritten */
904 /* You could be very general here and have "in" and "out" iovecs
905 * and write a loop without using a macro, but what the heck. This
908 * how much of this piece is new?
909 * if more new then we are trying this time, clamp
911 * then bump down amount already written, for next piece
912 * else put new stuff in iovec, will need all of next piece
914 * Note that todo had better be at least 1 or else we'll end up
917 #define InsertIOV(pointer, length) \
918 len = (length) - before; \
924 iov[i].iov_len = len; \
925 iov[i].iov_base = (pointer) + before; \
931 InsertIOV((char *) oco
->buf
, oco
->count
)
932 InsertIOV((char *) extraBuf
, extraCount
)
933 InsertIOV(padBuffer
, padsize
)
936 if (trans_conn
&& (len
= _XSERVTransWritev(trans_conn
, iov
, i
)) >= 0) {
941 else if (ETEST(errno
)
942 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
945 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
946 || ((errno
== EMSGSIZE
) && (todo
== 1))
949 /* If we've arrived here, then the client is stuffed to the gills
950 and not ready to accept more. Make a note of it and buffer
952 FD_SET(connection
, &ClientsWriteBlocked
);
953 AnyClientsWriteBlocked
= TRUE
;
955 if (written
< oco
->count
) {
957 oco
->count
-= written
;
958 memmove((char *) oco
->buf
,
959 (char *) oco
->buf
+ written
, oco
->count
);
964 written
-= oco
->count
;
968 if (notWritten
> oco
->size
) {
971 obuf
= (unsigned char *) realloc(oco
->buf
,
972 notWritten
+ BUFSIZE
);
974 _XSERVTransDisconnect(oc
->trans_conn
);
975 _XSERVTransClose(oc
->trans_conn
);
976 oc
->trans_conn
= NULL
;
977 MarkClientException(who
);
981 oco
->size
= notWritten
+ BUFSIZE
;
985 /* If the amount written extended into the padBuffer, then the
986 difference "extraCount - written" may be less than 0 */
987 if ((len
= extraCount
- written
) > 0)
988 memmove((char *) oco
->buf
+ oco
->count
,
989 extraBuf
+ written
, len
);
991 oco
->count
= notWritten
; /* this will include the pad */
992 /* return only the amount explicitly requested */
995 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
996 else if (errno
== EMSGSIZE
) {
1001 if (oc
->trans_conn
) {
1002 _XSERVTransDisconnect(oc
->trans_conn
);
1003 _XSERVTransClose(oc
->trans_conn
);
1004 oc
->trans_conn
= NULL
;
1006 MarkClientException(who
);
1012 /* everything was flushed out */
1014 /* check to see if this client was write blocked */
1015 if (AnyClientsWriteBlocked
) {
1016 FD_CLR(oc
->fd
, &ClientsWriteBlocked
);
1017 if (!XFD_ANYSET(&ClientsWriteBlocked
))
1018 AnyClientsWriteBlocked
= FALSE
;
1020 if (oco
->size
> BUFWATERMARK
) {
1025 oco
->next
= FreeOutputs
;
1028 oc
->output
= (ConnectionOutputPtr
) NULL
;
1029 return extraCount
; /* return only the amount explicitly requested */
1032 static ConnectionInputPtr
1033 AllocateInputBuffer(void)
1035 ConnectionInputPtr oci
;
1037 oci
= malloc(sizeof(ConnectionInput
));
1040 oci
->buffer
= malloc(BUFSIZE
);
1045 oci
->size
= BUFSIZE
;
1046 oci
->bufptr
= oci
->buffer
;
1048 oci
->lenLastReq
= 0;
1049 oci
->ignoreBytes
= 0;
1053 static ConnectionOutputPtr
1054 AllocateOutputBuffer(void)
1056 ConnectionOutputPtr oco
;
1058 oco
= malloc(sizeof(ConnectionOutput
));
1061 oco
->buf
= calloc(1, BUFSIZE
);
1066 oco
->size
= BUFSIZE
;
1072 FreeOsBuffers(OsCommPtr oc
)
1074 ConnectionInputPtr oci
;
1075 ConnectionOutputPtr oco
;
1077 if (AvailableInput
== oc
)
1078 AvailableInput
= (OsCommPtr
) NULL
;
1079 if ((oci
= oc
->input
)) {
1086 oci
->next
= (ConnectionInputPtr
) NULL
;
1087 oci
->bufptr
= oci
->buffer
;
1089 oci
->lenLastReq
= 0;
1090 oci
->ignoreBytes
= 0;
1093 if ((oco
= oc
->output
)) {
1100 oco
->next
= (ConnectionOutputPtr
) NULL
;
1107 ResetOsBuffers(void)
1109 ConnectionInputPtr oci
;
1110 ConnectionOutputPtr oco
;
1112 while ((oci
= FreeInputs
)) {
1113 FreeInputs
= oci
->next
;
1117 while ((oco
= FreeOutputs
)) {
1118 FreeOutputs
= oco
->next
;