Home | History | Annotate | Line # | Download | only in os
      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 #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 
     83 CallbackListPtr ReplyCallback;
     84 CallbackListPtr FlushCallback;
     85 
     86 typedef 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 
     96 typedef struct _connectionOutput {
     97     struct _connectionOutput *next;
     98     unsigned char *buf;
     99     int size;
    100     int count;
    101 } ConnectionOutput;
    102 
    103 static ConnectionInputPtr AllocateInputBuffer(void);
    104 static ConnectionOutputPtr AllocateOutputBuffer(void);
    105 
    106 static Bool CriticalOutputPending;
    107 static int timesThisConnection = 0;
    108 static ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL;
    109 static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL;
    110 static 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 
    180 static void
    181 YieldControl(void)
    182 {
    183     isItTimeToYield = TRUE;
    184     timesThisConnection = 0;
    185 }
    186 
    187 static void
    188 YieldControlNoInput(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 
    196 static void
    197 YieldControlDeath(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  */
    207 static void
    208 NextAvailableInput(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 
    228 int
    229 ReadRequestFromClient(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 
    475 int
    476 ReadFdFromClient(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 
    493 int
    494 WriteFdToClient(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 
    511 Bool
    512 InsertFakeRequest(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 
    564 void
    565 ResetCurrentRequest(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 
    615 void
    616 FlushAllOutput(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 
    644 void
    645 FlushIfCriticalOutputPending(void)
    646 {
    647     if (CriticalOutputPending)
    648         FlushAllOutput();
    649 }
    650 
    651 void
    652 SetCriticalOutputPending(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 
    666 static void
    667 AbortClient(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 
    688 int
    689 WriteToClient(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 
    832 int
    833 FlushClient(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 
    983 static ConnectionInputPtr
    984 AllocateInputBuffer(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 
   1004 static ConnectionOutputPtr
   1005 AllocateOutputBuffer(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 
   1022 void
   1023 FreeOsBuffers(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 
   1057 void
   1058 ResetOsBuffers(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