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