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