io.c revision 706f2543
1/***********************************************************
2
3Copyright 1987, 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46
47******************************************************************/
48/*****************************************************************
49 * i/o functions
50 *
51 *   WriteToClient, ReadRequestFromClient
52 *   InsertFakeRequest, ResetCurrentRequest
53 *
54 *****************************************************************/
55
56#include <X11/Xpoll.h>
57
58#ifdef HAVE_DIX_CONFIG_H
59#include <dix-config.h>
60#endif
61
62#undef DEBUG_COMMUNICATION
63
64#ifdef WIN32
65#include <X11/Xwinsock.h>
66#endif
67#include <stdio.h>
68#define XSERV_t
69#define TRANS_SERVER
70#define TRANS_REOPEN
71#include <X11/Xtrans/Xtrans.h>
72#include <X11/Xmd.h>
73#include <errno.h>
74#if !defined(WIN32)
75#include <sys/uio.h>
76#endif
77#include <X11/X.h>
78#include <X11/Xproto.h>
79#include "os.h"
80#include "osdep.h"
81#include "opaque.h"
82#include "dixstruct.h"
83#include "misc.h"
84
85CallbackListPtr       ReplyCallback;
86CallbackListPtr       FlushCallback;
87
88static ConnectionInputPtr AllocateInputBuffer(void);
89static ConnectionOutputPtr AllocateOutputBuffer(void);
90
91/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
92 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
93 */
94#ifndef WIN32
95#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
96#else /* WIN32 The socket errorcodes differ from the normal errors*/
97#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
98#endif
99
100static Bool CriticalOutputPending;
101static int timesThisConnection = 0;
102static ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
103static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
104static OsCommPtr AvailableInput = (OsCommPtr)NULL;
105
106#define get_req_len(req,cli) ((cli)->swapped ? \
107			      lswaps((req)->length) : (req)->length)
108
109#include <X11/extensions/bigreqsproto.h>
110
111#define get_big_req_len(req,cli) ((cli)->swapped ? \
112				  lswapl(((xBigReq *)(req))->length) : \
113				  ((xBigReq *)(req))->length)
114
115#define MAX_TIMES_PER         10
116
117/*
118 *   A lot of the code in this file manipulates a ConnectionInputPtr:
119 *
120 *    -----------------------------------------------
121 *   |------- bufcnt ------->|           |           |
122 *   |           |- gotnow ->|           |           |
123 *   |           |-------- needed ------>|           |
124 *   |-----------+--------- size --------+---------->|
125 *    -----------------------------------------------
126 *   ^           ^
127 *   |           |
128 *   buffer   bufptr
129 *
130 *  buffer is a pointer to the start of the buffer.
131 *  bufptr points to the start of the current request.
132 *  bufcnt counts how many bytes are in the buffer.
133 *  size is the size of the buffer in bytes.
134 *
135 *  In several of the functions, gotnow and needed are local variables
136 *  that do the following:
137 *
138 *  gotnow is the number of bytes of the request that we're
139 *  trying to read that are currently in the buffer.
140 *  Typically, gotnow = (buffer + bufcnt) - bufptr
141 *
142 *  needed = the length of the request that we're trying to
143 *  read.  Watch out: needed sometimes counts bytes and sometimes
144 *  counts CARD32's.
145 */
146
147
148/*****************************************************************
149 * ReadRequestFromClient
150 *    Returns one request in client->requestBuffer.  The request
151 *    length will be in client->req_len.  Return status is:
152 *
153 *    > 0  if  successful, specifies length in bytes of the request
154 *    = 0  if  entire request is not yet available
155 *    < 0  if  client should be terminated
156 *
157 *    The request returned must be contiguous so that it can be
158 *    cast in the dispatcher to the correct request type.  Because requests
159 *    are variable length, ReadRequestFromClient() must look at the first 4
160 *    or 8 bytes of a request to determine the length (the request length is
161 *    in the 3rd and 4th bytes of the request unless it is a Big Request
162 *    (see the Big Request Extension), in which case the 3rd and 4th bytes
163 *    are zero and the following 4 bytes are the request length.
164 *
165 *    Note: in order to make the server scheduler (WaitForSomething())
166 *    "fair", the ClientsWithInput mask is used.  This mask tells which
167 *    clients have FULL requests left in their buffers.  Clients with
168 *    partial requests require a read.  Basically, client buffers
169 *    are drained before select() is called again.  But, we can't keep
170 *    reading from a client that is sending buckets of data (or has
171 *    a partial request) because others clients need to be scheduled.
172 *****************************************************************/
173
174static void
175YieldControl(void)
176{
177    isItTimeToYield = TRUE;
178    timesThisConnection = 0;
179}
180
181static void
182YieldControlNoInput(int fd)
183{
184    YieldControl();
185    FD_CLR(fd, &ClientsWithInput);
186}
187
188static void
189YieldControlDeath(void)
190{
191    timesThisConnection = 0;
192}
193
194int
195ReadRequestFromClient(ClientPtr client)
196{
197    OsCommPtr oc = (OsCommPtr)client->osPrivate;
198    ConnectionInputPtr oci = oc->input;
199    int fd = oc->fd;
200    unsigned int gotnow, needed;
201    int result;
202    register xReq *request;
203    Bool need_header;
204    Bool move_header;
205
206    /* If an input buffer was empty, either free it if it is too big
207     * or link it into our list of free input buffers.  This means that
208     * different clients can share the same input buffer (at different
209     * times).  This was done to save memory.
210     */
211
212    if (AvailableInput)
213    {
214	if (AvailableInput != oc)
215	{
216	    register ConnectionInputPtr aci = AvailableInput->input;
217	    if (aci->size > BUFWATERMARK)
218	    {
219		free(aci->buffer);
220		free(aci);
221	    }
222	    else
223	    {
224		aci->next = FreeInputs;
225		FreeInputs = aci;
226	    }
227	    AvailableInput->input = (ConnectionInputPtr)NULL;
228	}
229	AvailableInput = (OsCommPtr)NULL;
230    }
231
232    /* make sure we have an input buffer */
233
234    if (!oci)
235    {
236	if ((oci = FreeInputs))
237	{
238	    FreeInputs = oci->next;
239	}
240	else if (!(oci = AllocateInputBuffer()))
241	{
242	    YieldControlDeath();
243	    return -1;
244	}
245	oc->input = oci;
246    }
247
248    /* advance to start of next request */
249
250    oci->bufptr += oci->lenLastReq;
251
252    need_header = FALSE;
253    move_header = FALSE;
254    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
255
256    if (oci->ignoreBytes > 0) {
257	if (oci->ignoreBytes > oci->size)
258	    needed = oci->size;
259	else
260	    needed = oci->ignoreBytes;
261    }
262    else if (gotnow < sizeof(xReq))
263    {
264	/* We don't have an entire xReq yet.  Can't tell how big
265	 * the request will be until we get the whole xReq.
266	 */
267	needed = sizeof(xReq);
268	need_header = TRUE;
269    }
270    else
271    {
272	/* We have a whole xReq.  We can tell how big the whole
273	 * request will be unless it is a Big Request.
274	 */
275	request = (xReq *)oci->bufptr;
276	needed = get_req_len(request, client);
277	if (!needed && client->big_requests)
278	{
279	    /* It's a Big Request. */
280	    move_header = TRUE;
281	    if (gotnow < sizeof(xBigReq))
282	    {
283		/* Still need more data to tell just how big. */
284		needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */
285		need_header = TRUE;
286	    }
287	    else
288		needed = get_big_req_len(request, client);
289	}
290	client->req_len = needed;
291	needed <<= 2; /* needed is in bytes now */
292    }
293    if (gotnow < needed)
294    {
295	/* Need to read more data, either so that we can get a
296	 * complete xReq (if need_header is TRUE), a complete
297	 * xBigReq (if move_header is TRUE), or the rest of the
298	 * request (if need_header and move_header are both FALSE).
299	 */
300
301	oci->lenLastReq = 0;
302	if (needed > maxBigRequestSize << 2)
303	{
304	    /* request is too big for us to handle */
305	    /*
306	     * Mark the rest of it as needing to be ignored, and then return
307	     * the full size.  Dispatch() will turn it into a BadLength error.
308	     */
309	    oci->ignoreBytes = needed - gotnow;
310	    oci->lenLastReq = gotnow;
311	    return needed;
312	}
313	if ((gotnow == 0) ||
314	    ((oci->bufptr - oci->buffer + needed) > oci->size))
315	{
316	    /* no data, or the request is too big to fit in the buffer */
317
318	    if ((gotnow > 0) && (oci->bufptr != oci->buffer))
319		/* save the data we've already read */
320		memmove(oci->buffer, oci->bufptr, gotnow);
321	    if (needed > oci->size)
322	    {
323		/* make buffer bigger to accomodate request */
324		char *ibuf;
325
326		ibuf = (char *)realloc(oci->buffer, needed);
327		if (!ibuf)
328		{
329		    YieldControlDeath();
330		    return -1;
331		}
332		oci->size = needed;
333		oci->buffer = ibuf;
334	    }
335	    oci->bufptr = oci->buffer;
336	    oci->bufcnt = gotnow;
337	}
338	/*  XXX this is a workaround.  This function is sometimes called
339	 *  after the trans_conn has been freed.  In this case trans_conn
340	 *  will be null.  Really ought to restructure things so that we
341	 *  never get here in those circumstances.
342	 */
343	if (!oc->trans_conn)
344	{
345	    /*  treat as if an error occured on the read, which is what
346	     *  used to happen
347	     */
348	    YieldControlDeath();
349	    return -1;
350	}
351	    result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
352				     oci->size - oci->bufcnt);
353	if (result <= 0)
354	{
355	    if ((result < 0) && ETEST(errno))
356	    {
357#if defined(SVR4) && defined(__i386__) && !defined(sun)
358		if (0)
359#endif
360		{
361		    YieldControlNoInput(fd);
362		    return 0;
363		}
364	    }
365	    YieldControlDeath();
366	    return -1;
367	}
368	oci->bufcnt += result;
369	gotnow += result;
370	/* free up some space after huge requests */
371	if ((oci->size > BUFWATERMARK) &&
372	    (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
373	{
374	    char *ibuf;
375
376	    ibuf = (char *)realloc(oci->buffer, BUFSIZE);
377	    if (ibuf)
378	    {
379		oci->size = BUFSIZE;
380		oci->buffer = ibuf;
381		oci->bufptr = ibuf + oci->bufcnt - gotnow;
382	    }
383	}
384	if (need_header && gotnow >= needed)
385	{
386	    /* We wanted an xReq, now we've gotten it. */
387	    request = (xReq *)oci->bufptr;
388	    needed = get_req_len(request, client);
389	    if (!needed && client->big_requests)
390	    {
391		move_header = TRUE;
392		if (gotnow < sizeof(xBigReq))
393		    needed = bytes_to_int32(sizeof(xBigReq));
394		else
395		    needed = get_big_req_len(request, client);
396	    }
397	    client->req_len = needed;
398	    needed <<= 2;
399	}
400	if (gotnow < needed)
401	{
402	    /* Still don't have enough; punt. */
403	    YieldControlNoInput(fd);
404	    return 0;
405	}
406    }
407    if (needed == 0)
408    {
409	if (client->big_requests)
410	    needed = sizeof(xBigReq);
411	else
412	    needed = sizeof(xReq);
413    }
414
415    /* If there are bytes to ignore, ignore them now. */
416
417    if (oci->ignoreBytes > 0) {
418	assert(needed == oci->ignoreBytes || needed == oci->size);
419	/*
420	 * The _XSERVTransRead call above may return more or fewer bytes than we
421	 * want to ignore.  Ignore the smaller of the two sizes.
422	 */
423	if (gotnow < needed) {
424	    oci->ignoreBytes -= gotnow;
425	    oci->bufptr += gotnow;
426	    gotnow = 0;
427	} else {
428	    oci->ignoreBytes -= needed;
429	    oci->bufptr += needed;
430	    gotnow -= needed;
431	}
432	needed = 0;
433    }
434
435    oci->lenLastReq = needed;
436
437    /*
438     *  Check to see if client has at least one whole request in the
439     *  buffer beyond the request we're returning to the caller.
440     *  If there is only a partial request, treat like buffer
441     *  is empty so that select() will be called again and other clients
442     *  can get into the queue.
443     */
444
445    gotnow -= needed;
446    if (gotnow >= sizeof(xReq))
447    {
448	request = (xReq *)(oci->bufptr + needed);
449	if (gotnow >= (result = (get_req_len(request, client) << 2))
450	    && (result ||
451		(client->big_requests &&
452		 (gotnow >= sizeof(xBigReq) &&
453		  gotnow >= (get_big_req_len(request, client) << 2))))
454	    )
455	    FD_SET(fd, &ClientsWithInput);
456	else
457	{
458	    if (!SmartScheduleDisable)
459		FD_CLR(fd, &ClientsWithInput);
460	    else
461		YieldControlNoInput(fd);
462	}
463    }
464    else
465    {
466	if (!gotnow)
467	    AvailableInput = oc;
468	if (!SmartScheduleDisable)
469	    FD_CLR(fd, &ClientsWithInput);
470	else
471	    YieldControlNoInput(fd);
472    }
473    if (SmartScheduleDisable)
474    if (++timesThisConnection >= MAX_TIMES_PER)
475	YieldControl();
476    if (move_header)
477    {
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));
483    }
484    client->requestBuffer = (pointer)oci->bufptr;
485#ifdef DEBUG_COMMUNICATION
486    {
487	xReq *req = client->requestBuffer;
488	ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
489	       client->index,req->reqType,req->data,req->length);
490    }
491#endif
492    return needed;
493}
494
495/*****************************************************************
496 * InsertFakeRequest
497 *    Splice a consed up (possibly partial) request in as the next request.
498 *
499 **********************/
500
501Bool
502InsertFakeRequest(ClientPtr client, char *data, int count)
503{
504    OsCommPtr oc = (OsCommPtr)client->osPrivate;
505    ConnectionInputPtr oci = oc->input;
506    int fd = oc->fd;
507    int gotnow, moveup;
508
509    if (AvailableInput)
510    {
511	if (AvailableInput != oc)
512	{
513	    ConnectionInputPtr aci = AvailableInput->input;
514	    if (aci->size > BUFWATERMARK)
515	    {
516		free(aci->buffer);
517		free(aci);
518	    }
519	    else
520	    {
521		aci->next = FreeInputs;
522		FreeInputs = aci;
523	    }
524	    AvailableInput->input = (ConnectionInputPtr)NULL;
525	}
526	AvailableInput = (OsCommPtr)NULL;
527    }
528    if (!oci)
529    {
530	if ((oci = FreeInputs))
531	    FreeInputs = oci->next;
532	else if (!(oci = AllocateInputBuffer()))
533	    return FALSE;
534	oc->input = oci;
535    }
536    oci->bufptr += oci->lenLastReq;
537    oci->lenLastReq = 0;
538    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
539    if ((gotnow + count) > oci->size)
540    {
541	char *ibuf;
542
543	ibuf = (char *)realloc(oci->buffer, gotnow + count);
544	if (!ibuf)
545	    return FALSE;
546	oci->size = gotnow + count;
547	oci->buffer = ibuf;
548	oci->bufptr = ibuf + oci->bufcnt - gotnow;
549    }
550    moveup = count - (oci->bufptr - oci->buffer);
551    if (moveup > 0)
552    {
553	if (gotnow > 0)
554	    memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
555	oci->bufptr += moveup;
556	oci->bufcnt += moveup;
557    }
558    memmove(oci->bufptr - count, data, count);
559    oci->bufptr -= count;
560    gotnow += count;
561    if ((gotnow >= sizeof(xReq)) &&
562	(gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
563	FD_SET(fd, &ClientsWithInput);
564    else
565	YieldControlNoInput(fd);
566    return TRUE;
567}
568
569/*****************************************************************
570 * ResetRequestFromClient
571 *    Reset to reexecute the current request, and yield.
572 *
573 **********************/
574
575void
576ResetCurrentRequest(ClientPtr client)
577{
578    OsCommPtr oc = (OsCommPtr)client->osPrivate;
579    register ConnectionInputPtr oci = oc->input;
580    int fd = oc->fd;
581    register xReq *request;
582    int gotnow, needed;
583    if (AvailableInput == oc)
584	AvailableInput = (OsCommPtr)NULL;
585    oci->lenLastReq = 0;
586    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
587    if (gotnow < sizeof(xReq))
588    {
589	YieldControlNoInput(fd);
590    }
591    else
592    {
593	request = (xReq *)oci->bufptr;
594	needed = get_req_len(request, client);
595	if (!needed && client->big_requests)
596	{
597	    oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
598	    *(xReq *)oci->bufptr = *request;
599	    ((xBigReq *)oci->bufptr)->length = client->req_len;
600	    if (client->swapped)
601	    {
602		char n;
603		swapl(&((xBigReq *)oci->bufptr)->length, n);
604	    }
605	}
606	if (gotnow >= (needed << 2))
607	{
608	    if (FD_ISSET(fd, &AllClients))
609	    {
610		FD_SET(fd, &ClientsWithInput);
611	    }
612	    else
613	    {
614		FD_SET(fd, &IgnoredClientsWithInput);
615	    }
616	    YieldControl();
617	}
618	else
619	    YieldControlNoInput(fd);
620    }
621}
622
623static const int padlength[4] = {0, 3, 2, 1};
624
625 /********************
626 * FlushAllOutput()
627 *    Flush all clients with output.  However, if some client still
628 *    has input in the queue (more requests), then don't flush.  This
629 *    will prevent the output queue from being flushed every time around
630 *    the round robin queue.  Now, some say that it SHOULD be flushed
631 *    every time around, but...
632 *
633 **********************/
634
635void
636FlushAllOutput(void)
637{
638    register int index, base;
639    register fd_mask mask; /* raphael */
640    OsCommPtr oc;
641    register ClientPtr client;
642    Bool newoutput = NewOutputPending;
643#if defined(WIN32)
644    fd_set newOutputPending;
645#endif
646
647    if (FlushCallback)
648	CallCallbacks(&FlushCallback, NULL);
649
650    if (!newoutput)
651	return;
652
653    /*
654     * It may be that some client still has critical output pending,
655     * but he is not yet ready to receive it anyway, so we will
656     * simply wait for the select to tell us when he's ready to receive.
657     */
658    CriticalOutputPending = FALSE;
659    NewOutputPending = FALSE;
660
661#ifndef WIN32
662    for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
663    {
664	mask = OutputPending.fds_bits[ base ];
665	OutputPending.fds_bits[ base ] = 0;
666	while (mask)
667	{
668	    index = ffs(mask) - 1;
669	    mask &= ~lowbit(mask);
670	    if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0)
671		continue;
672	    client = clients[index];
673	    if (client->clientGone)
674		continue;
675	    oc = (OsCommPtr)client->osPrivate;
676	    if (FD_ISSET(oc->fd, &ClientsWithInput))
677	    {
678		FD_SET(oc->fd, &OutputPending); /* set the bit again */
679		NewOutputPending = TRUE;
680	    }
681	    else
682		(void)FlushClient(client, oc, (char *)NULL, 0);
683	}
684    }
685#else  /* WIN32 */
686    FD_ZERO(&newOutputPending);
687    for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
688    {
689	    index = XFD_FD(&OutputPending, base);
690	    if ((index = GetConnectionTranslation(index)) == 0)
691		continue;
692	    client = clients[index];
693	    if (client->clientGone)
694		continue;
695	    oc = (OsCommPtr)client->osPrivate;
696	    if (FD_ISSET(oc->fd, &ClientsWithInput))
697	    {
698		FD_SET(oc->fd, &newOutputPending); /* set the bit again */
699		NewOutputPending = TRUE;
700	    }
701	    else
702		(void)FlushClient(client, oc, (char *)NULL, 0);
703    }
704    XFD_COPYSET(&newOutputPending, &OutputPending);
705#endif /* WIN32 */
706}
707
708void
709FlushIfCriticalOutputPending(void)
710{
711    if (CriticalOutputPending)
712	FlushAllOutput();
713}
714
715void
716SetCriticalOutputPending(void)
717{
718    CriticalOutputPending = TRUE;
719}
720
721/*****************
722 * WriteToClient
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.
730 *****************/
731
732int
733WriteToClient (ClientPtr who, int count, const void *__buf)
734{
735    OsCommPtr oc;
736    ConnectionOutputPtr oco;
737    int padBytes;
738    const char *buf = __buf;
739#ifdef DEBUG_COMMUNICATION
740    Bool multicount = FALSE;
741#endif
742    if (!count || !who || who == serverClient || who->clientGone)
743	return 0;
744    oc = who->osPrivate;
745    oco = oc->output;
746#ifdef DEBUG_COMMUNICATION
747    {
748	char info[128];
749	xError *err;
750	xGenericReply *rep;
751	xEvent *ev;
752
753	if (!who->replyBytesRemaining) {
754	    switch(buf[0]) {
755	    case X_Reply:
756		rep = (xGenericReply*)buf;
757		if (rep->sequenceNumber == who->sequence) {
758		    snprintf(info,127,"Xreply: type: 0x%x data: 0x%x "
759			     "len: %i seq#: 0x%x", rep->type, rep->data1,
760			     rep->length, rep->sequenceNumber);
761		    multicount = TRUE;
762		}
763		break;
764	    case X_Error:
765		err = (xError*)buf;
766		snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
767			 "min: %x", err->errorCode,err->resourceID,
768			 err->minorCode,err->majorCode);
769		break;
770	    default:
771		if ((buf[0] & 0x7f) == KeymapNotify)
772		    snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]);
773		else {
774		    ev = (xEvent*)buf;
775		    snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x "
776			     "seq#: 0x%x",  ev->u.u.type, ev->u.u.detail,
777			     ev->u.u.sequenceNumber);
778		}
779	    }
780	    ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info);
781	} else
782	    multicount = TRUE;
783    }
784#endif
785
786    if (!oco)
787    {
788	if ((oco = FreeOutputs))
789	{
790	    FreeOutputs = oco->next;
791	}
792	else if (!(oco = AllocateOutputBuffer()))
793	{
794	    if (oc->trans_conn) {
795		_XSERVTransDisconnect(oc->trans_conn);
796		_XSERVTransClose(oc->trans_conn);
797		oc->trans_conn = NULL;
798	    }
799	    MarkClientException(who);
800	    return -1;
801	}
802	oc->output = oco;
803    }
804
805    padBytes = padlength[count & 3];
806
807    if(ReplyCallback)
808    {
809        ReplyInfoRec replyinfo;
810
811	replyinfo.client = who;
812	replyinfo.replyData = buf;
813	replyinfo.dataLenBytes = count + padBytes;
814	if (who->replyBytesRemaining)
815	{ /* still sending data of an earlier reply */
816	    who->replyBytesRemaining -= count + padBytes;
817	    replyinfo.startOfReply = FALSE;
818	    replyinfo.bytesRemaining = who->replyBytesRemaining;
819	    CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
820	}
821	else if (who->clientState == ClientStateRunning
822		 && buf[0] == X_Reply)
823        { /* start of new reply */
824	    CARD32 replylen;
825	    unsigned long bytesleft;
826	    char n;
827
828	    replylen = ((xGenericReply *)buf)->length;
829	    if (who->swapped)
830		swapl(&replylen, n);
831	    bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
832	    replyinfo.startOfReply = TRUE;
833	    replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
834	    CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
835	}
836    }
837#ifdef DEBUG_COMMUNICATION
838    else if (multicount) {
839	if (who->replyBytesRemaining) {
840	    who->replyBytesRemaining -= (count + padBytes);
841	} else {
842	    CARD32 replylen;
843	    replylen = ((xGenericReply *)buf)->length;
844	    who->replyBytesRemaining =
845		(replylen * 4) + SIZEOF(xReply) - count - padBytes;
846	}
847    }
848#endif
849    if (oco->count + count + padBytes > oco->size)
850    {
851	FD_CLR(oc->fd, &OutputPending);
852	if(!XFD_ANYSET(&OutputPending)) {
853	  CriticalOutputPending = FALSE;
854	  NewOutputPending = FALSE;
855	}
856
857	if (FlushCallback)
858	    CallCallbacks(&FlushCallback, NULL);
859
860	return FlushClient(who, oc, buf, count);
861    }
862
863    NewOutputPending = TRUE;
864    FD_SET(oc->fd, &OutputPending);
865    memmove((char *)oco->buf + oco->count, buf, count);
866    oco->count += count + padBytes;
867    return count;
868}
869
870 /********************
871 * FlushClient()
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.
877 *
878 **********************/
879
880int
881FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
882{
883    ConnectionOutputPtr oco = oc->output;
884    int connection = oc->fd;
885    XtransConnInfo trans_conn = oc->trans_conn;
886    struct iovec iov[3];
887    static char padBuffer[3];
888    const char *extraBuf = __extraBuf;
889    long written;
890    long padsize;
891    long notWritten;
892    long todo;
893
894    if (!oco)
895	return 0;
896    written = 0;
897    padsize = padlength[extraCount & 3];
898    notWritten = oco->count + extraCount + padsize;
899    todo = notWritten;
900    while (notWritten) {
901	long before = written;	/* amount of whole thing written */
902	long remain = todo;	/* amount to try this time, <= notWritten */
903	int i = 0;
904	long len;
905
906	/* You could be very general here and have "in" and "out" iovecs
907	 * and write a loop without using a macro, but what the heck.  This
908	 * translates to:
909	 *
910	 *     how much of this piece is new?
911	 *     if more new then we are trying this time, clamp
912	 *     if nothing new
913	 *         then bump down amount already written, for next piece
914	 *         else put new stuff in iovec, will need all of next piece
915	 *
916	 * Note that todo had better be at least 1 or else we'll end up
917	 * writing 0 iovecs.
918	 */
919#define InsertIOV(pointer, length) \
920	len = (length) - before; \
921	if (len > remain) \
922	    len = remain; \
923	if (len <= 0) { \
924	    before = (-len); \
925	} else { \
926	    iov[i].iov_len = len; \
927	    iov[i].iov_base = (pointer) + before;	\
928	    i++; \
929	    remain -= len; \
930	    before = 0; \
931	}
932
933	InsertIOV ((char *)oco->buf, oco->count)
934	InsertIOV ((char *)extraBuf, extraCount)
935	InsertIOV (padBuffer, padsize)
936
937	errno = 0;
938	if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
939	{
940	    written += len;
941	    notWritten -= len;
942	    todo = notWritten;
943	}
944	else if (ETEST(errno)
945#ifdef SUNSYSV /* check for another brain-damaged OS bug */
946		 || (errno == 0)
947#endif
948#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
949		 || ((errno == EMSGSIZE) && (todo == 1))
950#endif
951		)
952	{
953	    /* If we've arrived here, then the client is stuffed to the gills
954	       and not ready to accept more.  Make a note of it and buffer
955	       the rest. */
956	    FD_SET(connection, &ClientsWriteBlocked);
957	    AnyClientsWriteBlocked = TRUE;
958
959	    if (written < oco->count)
960	    {
961		if (written > 0)
962		{
963		    oco->count -= written;
964		    memmove((char *)oco->buf,
965			    (char *)oco->buf + written,
966			  oco->count);
967		    written = 0;
968		}
969	    }
970	    else
971	    {
972		written -= oco->count;
973		oco->count = 0;
974	    }
975
976	    if (notWritten > oco->size)
977	    {
978		unsigned char *obuf;
979
980		obuf = (unsigned char *)realloc(oco->buf,
981						 notWritten + BUFSIZE);
982		if (!obuf)
983		{
984		    _XSERVTransDisconnect(oc->trans_conn);
985		    _XSERVTransClose(oc->trans_conn);
986		    oc->trans_conn = NULL;
987		    MarkClientException(who);
988		    oco->count = 0;
989		    return -1;
990		}
991		oco->size = notWritten + BUFSIZE;
992		oco->buf = obuf;
993	    }
994
995	    /* If the amount written extended into the padBuffer, then the
996	       difference "extraCount - written" may be less than 0 */
997	    if ((len = extraCount - written) > 0)
998		memmove ((char *)oco->buf + oco->count,
999			 extraBuf + written,
1000		       len);
1001
1002	    oco->count = notWritten; /* this will include the pad */
1003	    /* return only the amount explicitly requested */
1004	    return extraCount;
1005	}
1006#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
1007	else if (errno == EMSGSIZE)
1008	{
1009	    todo >>= 1;
1010	}
1011#endif
1012	else
1013	{
1014	    if (oc->trans_conn)
1015	    {
1016		_XSERVTransDisconnect(oc->trans_conn);
1017		_XSERVTransClose(oc->trans_conn);
1018		oc->trans_conn = NULL;
1019	    }
1020	    MarkClientException(who);
1021	    oco->count = 0;
1022	    return -1;
1023	}
1024    }
1025
1026    /* everything was flushed out */
1027    oco->count = 0;
1028    /* check to see if this client was write blocked */
1029    if (AnyClientsWriteBlocked)
1030    {
1031	FD_CLR(oc->fd, &ClientsWriteBlocked);
1032 	if (! XFD_ANYSET(&ClientsWriteBlocked))
1033	    AnyClientsWriteBlocked = FALSE;
1034    }
1035    if (oco->size > BUFWATERMARK)
1036    {
1037	free(oco->buf);
1038	free(oco);
1039    }
1040    else
1041    {
1042	oco->next = FreeOutputs;
1043	FreeOutputs = oco;
1044    }
1045    oc->output = (ConnectionOutputPtr)NULL;
1046    return extraCount; /* return only the amount explicitly requested */
1047}
1048
1049static ConnectionInputPtr
1050AllocateInputBuffer(void)
1051{
1052    ConnectionInputPtr oci;
1053
1054    oci = malloc(sizeof(ConnectionInput));
1055    if (!oci)
1056	return NULL;
1057    oci->buffer = malloc(BUFSIZE);
1058    if (!oci->buffer)
1059    {
1060	free(oci);
1061	return NULL;
1062    }
1063    oci->size = BUFSIZE;
1064    oci->bufptr = oci->buffer;
1065    oci->bufcnt = 0;
1066    oci->lenLastReq = 0;
1067    oci->ignoreBytes = 0;
1068    return oci;
1069}
1070
1071static ConnectionOutputPtr
1072AllocateOutputBuffer(void)
1073{
1074    ConnectionOutputPtr oco;
1075
1076    oco = malloc(sizeof(ConnectionOutput));
1077    if (!oco)
1078	return NULL;
1079    oco->buf = calloc(1, BUFSIZE);
1080    if (!oco->buf)
1081    {
1082	free(oco);
1083	return NULL;
1084    }
1085    oco->size = BUFSIZE;
1086    oco->count = 0;
1087    return oco;
1088}
1089
1090void
1091FreeOsBuffers(OsCommPtr oc)
1092{
1093    ConnectionInputPtr oci;
1094    ConnectionOutputPtr oco;
1095
1096    if (AvailableInput == oc)
1097	AvailableInput = (OsCommPtr)NULL;
1098    if ((oci = oc->input))
1099    {
1100	if (FreeInputs)
1101	{
1102	    free(oci->buffer);
1103	    free(oci);
1104	}
1105	else
1106	{
1107	    FreeInputs = oci;
1108	    oci->next = (ConnectionInputPtr)NULL;
1109	    oci->bufptr = oci->buffer;
1110	    oci->bufcnt = 0;
1111	    oci->lenLastReq = 0;
1112	}
1113    }
1114    if ((oco = oc->output))
1115    {
1116	if (FreeOutputs)
1117	{
1118	    free(oco->buf);
1119	    free(oco);
1120	}
1121	else
1122	{
1123	    FreeOutputs = oco;
1124	    oco->next = (ConnectionOutputPtr)NULL;
1125	    oco->count = 0;
1126	}
1127    }
1128}
1129
1130void
1131ResetOsBuffers(void)
1132{
1133    ConnectionInputPtr oci;
1134    ConnectionOutputPtr oco;
1135
1136    while ((oci = FreeInputs))
1137    {
1138	FreeInputs = oci->next;
1139	free(oci->buffer);
1140	free(oci);
1141    }
1142    while ((oco = FreeOutputs))
1143    {
1144	FreeOutputs = oco->next;
1145	free(oco->buf);
1146	free(oco);
1147    }
1148}
1149