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