]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/os/lbxio.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / os / lbxio.c
1 /***********************************************************
2 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts,
3 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4 Copyright 1996 X Consortium, Inc.
5
6                         All Rights Reserved
7
8 Permission to use, copy, modify, and distribute this software and its 
9 documentation for any purpose and without fee is hereby granted, 
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in 
12 supporting documentation, and that the names of Digital or MIT not be
13 used in advertising or publicity pertaining to distribution of the
14 software without specific, written prior permission.  
15
16 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 SOFTWARE.
23
24 ******************************************************************/
25 /* $XConsortium: lbxio.c /main/10 1996/12/16 23:03:30 rws $ */
26
27
28
29
30 /* $XFree86: xc/programs/Xserver/os/lbxio.c,v 3.8 1997/01/18 07:18:31 dawes Exp $ */
31
32 #include <stdio.h>
33 #include <X11/Xtrans.h>
34 #ifdef X_NOT_STDC_ENV
35 extern int errno;
36 #endif
37 #include "Xmd.h"
38 #include <errno.h>
39 #ifndef Lynx
40 #include <sys/param.h>
41 #ifndef __EMX__
42 #include <sys/uio.h>
43 #endif
44 #else
45 #include <uio.h>
46 #endif
47 #include "X.h"
48 #include "Xproto.h"
49 #include "os.h"
50 #include "Xpoll.h"
51 #include "osdep.h"
52 #include "opaque.h"
53 #include "dixstruct.h"
54 #include "misc.h"
55 #include "lbxserve.h"
56
57 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
58  * systems are broken and return EWOULDBLOCK when they should return EAGAIN
59  */
60 #if defined(EAGAIN) && defined(EWOULDBLOCK)
61 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
62 #else
63 #ifdef EAGAIN
64 #define ETEST(err) (err == EAGAIN)
65 #else
66 #define ETEST(err) (err == EWOULDBLOCK)
67 #endif
68 #endif
69
70 extern fd_set ClientsWithInput, IgnoredClientsWithInput;
71 extern fd_set AllClients, AllSockets;
72 extern fd_set ClientsWriteBlocked;
73 extern fd_set OutputPending;
74 extern int ConnectionTranslation[];
75 extern Bool NewOutputPending;
76 extern Bool AnyClientsWriteBlocked;
77 extern Bool CriticalOutputPending;
78 extern int timesThisConnection;
79 extern ConnectionInputPtr FreeInputs;
80 extern ConnectionOutputPtr FreeOutputs;
81 extern OsCommPtr AvailableInput;
82
83 #define get_req_len(req,cli) ((cli)->swapped ? \
84                               lswaps((req)->length) : (req)->length)
85
86 #define YieldControl()                          \
87         { isItTimeToYield = TRUE;               \
88           timesThisConnection = 0; }
89 #define YieldControlNoInput()                   \
90         { YieldControl();                       \
91           FD_CLR(fd, &ClientsWithInput); }
92
93 void
94 SwitchClientInput (client, pending)
95     ClientPtr client;
96     Bool pending;
97 {
98     OsCommPtr oc = (OsCommPtr)client->osPrivate;
99     
100     ConnectionTranslation[oc->fd] = client->index;
101     if (pending)
102         FD_SET(oc->fd, &ClientsWithInput);
103     else
104         YieldControl();
105 }
106
107 void
108 LbxPrimeInput(client, proxy)
109     ClientPtr   client;
110     LbxProxyPtr proxy;
111 {
112     OsCommPtr oc = (OsCommPtr)client->osPrivate;
113     ConnectionInputPtr oci = oc->input;
114
115     if (oci && proxy->compHandle) {
116         char *extra = oci->bufptr + oci->lenLastReq;
117         int left = oci->bufcnt + oci->buffer - extra;
118
119         (*proxy->streamOpts.streamCompStuffInput)(oc->fd,
120                                                   (unsigned char *)extra,
121                                                   left);
122         oci->bufcnt -= left;
123         AvailableInput = oc;
124     }
125 }
126
127 void
128 AvailableClientInput (client)
129     ClientPtr   client;
130 {
131     OsCommPtr oc = (OsCommPtr)client->osPrivate;
132
133     if (FD_ISSET(oc->fd, &AllSockets))
134         FD_SET(oc->fd, &ClientsWithInput);
135 }
136
137 /*****************************************************************
138  * AppendFakeRequest
139  *    Append a (possibly partial) request in as the last request.
140  *
141  **********************/
142  
143 Bool
144 AppendFakeRequest (client, data, count)
145     ClientPtr client;
146     char *data;
147     int count;
148 {
149     OsCommPtr oc = (OsCommPtr)client->osPrivate;
150     register ConnectionInputPtr oci = oc->input;
151     int fd = oc->fd;
152     register int gotnow;
153
154     if (!oci)
155     {
156         if (oci = FreeInputs)
157             FreeInputs = oci->next;
158         else if (!(oci = AllocateInputBuffer()))
159             return FALSE;
160         oc->input = oci;
161     } else if (AvailableInput == oc)
162         AvailableInput = (OsCommPtr)NULL;
163     /* do not free AvailableInput here, it could be proxy's */
164     oci->bufptr += oci->lenLastReq;
165     oci->lenLastReq = 0;
166     gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
167     if ((gotnow + count) > oci->size)
168     {
169         char *ibuf;
170
171         ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
172         if (!ibuf)
173             return(FALSE);
174         oci->size = gotnow + count;
175         oci->buffer = ibuf;
176         oci->bufptr = ibuf + oci->bufcnt - gotnow;
177     }
178     if (oci->bufcnt + count > oci->size) {
179         memmove(oci->buffer, oci->bufptr, gotnow);
180         oci->bufcnt = gotnow;
181         oci->bufptr = oci->buffer;
182     }
183     memmove(oci->bufptr + gotnow, data, count);
184     oci->bufcnt += count;
185     gotnow += count;
186     if ((gotnow >= sizeof(xReq)) &&
187         (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
188         FD_SET(fd, &ClientsWithInput);
189     else
190         YieldControlNoInput();
191     return(TRUE);
192 }
193
194 static int
195 LbxWrite(trans_conn, proxy, buf, len)
196     XtransConnInfo trans_conn;
197     LbxProxyPtr proxy;
198     char *buf;
199     int len;
200 {
201     struct iovec iov;
202     int n;
203     int notWritten;
204
205     notWritten = len;
206     iov.iov_base = buf;
207     iov.iov_len = len;
208     while (notWritten) {
209         errno = 0;
210         if (proxy->compHandle)
211             n = (*proxy->streamOpts.streamCompWriteV)(proxy->fd, &iov, 1);
212         else
213             n = _XSERVTransWritev(trans_conn, &iov, 1);
214         if (n >= 0) {
215             iov.iov_base = (char *)iov.iov_base + n;
216             notWritten -= n;
217             iov.iov_len = notWritten;
218         }
219         else if (ETEST(errno)
220 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
221                  || (errno == 0)
222 #endif
223 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
224                  || ((errno == EMSGSIZE) && (iov.iov_len == 1))
225 #endif
226                 )
227             break;
228 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
229         else if (errno == EMSGSIZE)
230             iov.iov_len >>= 1;
231 #endif
232         else
233             return -1;
234     }
235     return len - notWritten;
236 }
237
238 static Bool
239 LbxAppendOutput(proxy, client, oco)
240     LbxProxyPtr proxy;
241     ClientPtr client;
242     ConnectionOutputPtr oco;
243 {
244     ConnectionOutputPtr noco = proxy->olast;
245     LbxClientPtr lbxClient = LbxClient(client);
246
247     if (!lbxClient) {
248         xfree(oco->buf);
249         xfree(oco);
250         return TRUE;
251     }
252     if (noco)
253         LbxReencodeOutput(client,
254                           (char *)noco->buf, &noco->count,
255                           (char *)oco->buf, &oco->count);
256     else
257         LbxReencodeOutput(client,
258                           (char *)NULL, (int *)NULL,
259                           (char *)oco->buf, &oco->count);
260     if (!oco->count) {
261         if (oco->size > BUFWATERMARK)
262         {
263             xfree(oco->buf);
264             xfree(oco);
265         }
266         else
267         {
268             oco->next = FreeOutputs;
269             FreeOutputs = oco;
270         }
271         return TRUE;
272     }
273     if ((lbxClient->id != proxy->cur_send_id) && proxy->lbxClients[0]) {
274         xLbxSwitchEvent *ev;
275         int n;
276
277         if (!noco || (noco->size - noco->count) < sz_xLbxSwitchEvent) {
278             if (noco = FreeOutputs)
279                 FreeOutputs = noco->next;
280             else
281                 noco = AllocateOutputBuffer();
282             if (!noco) {
283                 MarkClientException(client);
284                 return FALSE;
285             }
286             noco->next = NULL;
287             if (proxy->olast)
288                 proxy->olast->next = noco;
289             else
290                 proxy->ofirst = noco;
291             proxy->olast = noco;
292         }
293         ev = (xLbxSwitchEvent *) (noco->buf + noco->count);
294         noco->count += sz_xLbxSwitchEvent;
295         proxy->cur_send_id = lbxClient->id;
296         ev->type = LbxEventCode;
297         ev->lbxType = LbxSwitchEvent;
298         ev->pad = 0;
299         ev->client = proxy->cur_send_id;
300         if (LbxProxyClient(proxy)->swapped) {
301             swapl(&ev->client, n);
302         }
303     }
304     oco->next = NULL;
305     if (proxy->olast)
306         proxy->olast->next = oco;
307     else
308         proxy->ofirst = oco;
309     proxy->olast = oco;
310     return TRUE;
311 }
312
313 static int
314 LbxClientOutput(client, oc, extraBuf, extraCount, nocompress)
315     ClientPtr client;
316     OsCommPtr oc;
317     char *extraBuf;
318     int extraCount;
319     Bool nocompress;
320 {
321     ConnectionOutputPtr oco;
322     int len;
323
324     if (oco = oc->output) {
325         oc->output = NULL;
326         if (!LbxAppendOutput(oc->proxy, client, oco))
327             return -1;
328     }
329
330     if (extraCount) {
331         NewOutputPending = TRUE;
332         FD_SET(oc->fd, &OutputPending);
333         len = (extraCount + 3) & ~3;
334         if ((oco = FreeOutputs) && (oco->size >= len))
335             FreeOutputs = oco->next;
336         else {
337             oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
338             if (!oco) {
339                 MarkClientException(client);
340                 return -1;
341             }
342             oco->size = len;
343             if (oco->size < BUFSIZE)
344                 oco->size = BUFSIZE;
345             oco->buf = (unsigned char *) xalloc(oco->size);
346             if (!oco->buf) {
347                 xfree(oco);
348                 MarkClientException(client);
349                 return -1;
350             }
351         }
352         oco->count = len;
353         oco->nocompress = nocompress;
354         memmove((char *)oco->buf, extraBuf, extraCount);
355         if (!nocompress && oco->count < oco->size)
356             oc->output = oco;
357         else if (!LbxAppendOutput(oc->proxy, client, oco))
358             return -1;
359     }
360     return extraCount;
361 }
362
363 void
364 LbxForceOutput(proxy)
365     LbxProxyPtr proxy;
366 {
367     int i;
368     LbxClientPtr lbxClient;
369     OsCommPtr coc;
370     ConnectionOutputPtr oco;
371
372     for (i = proxy->maxIndex; i >= 0; i--) { /* proxy must be last */
373         lbxClient = proxy->lbxClients[i];
374         if (!lbxClient)
375             continue;
376         coc = (OsCommPtr)lbxClient->client->osPrivate;
377         if (oco = coc->output) {
378             coc->output = NULL;
379             LbxAppendOutput(proxy, lbxClient->client, oco);
380         }
381     }
382 }
383
384 int
385 LbxFlushClient(who, oc, extraBuf, extraCount)
386     ClientPtr who;
387     OsCommPtr oc;
388     char *extraBuf;
389     int extraCount;
390 {
391     LbxProxyPtr proxy;
392     ConnectionOutputPtr oco;
393     int n;
394     XtransConnInfo trans_conn;
395
396     if (extraBuf)
397         return LbxClientOutput(who, oc, extraBuf, extraCount, FALSE);
398     proxy = oc->proxy;
399     if (!proxy->lbxClients[0])
400         return 0;
401     LbxForceOutput(proxy);
402     if (!proxy->compHandle)
403         trans_conn = ((OsCommPtr)LbxProxyClient(proxy)->osPrivate)->trans_conn;
404     while (oco = proxy->ofirst) {
405         /* XXX bundle up into writev someday */
406         if (proxy->compHandle) {
407             if (oco->nocompress)
408                 (*proxy->streamOpts.streamCompOff)(proxy->fd);
409             n = LbxWrite(NULL, proxy, (char *)oco->buf, oco->count);
410             if (oco->nocompress)
411                 (*proxy->streamOpts.streamCompOn)(proxy->fd);
412         } else
413             n = LbxWrite(trans_conn, proxy, (char *)oco->buf, oco->count);
414         if (n < 0) {
415             ClientPtr pclient = LbxProxyClient(proxy);
416             if (proxy->compHandle)
417                 trans_conn = ((OsCommPtr)pclient->osPrivate)->trans_conn;
418             _XSERVTransDisconnect(trans_conn);
419             _XSERVTransClose(trans_conn);
420             ((OsCommPtr)pclient->osPrivate)->trans_conn = NULL;
421             MarkClientException(pclient);
422             return 0;
423         } else if (n == oco->count) {
424             proxy->ofirst = oco->next;
425             if (!proxy->ofirst)
426                 proxy->olast = NULL;
427             if (oco->size > BUFWATERMARK)
428             {
429                 xfree(oco->buf);
430                 xfree(oco);
431             }
432             else
433             {
434                 oco->next = FreeOutputs;
435                 oco->count = 0;
436                 FreeOutputs = oco;
437             }
438         } else {
439             if (n) {
440                 oco->count -= n;
441                 memmove((char *)oco->buf, (char *)oco->buf + n, oco->count);
442             }
443             break;
444         }
445     }
446     if ((proxy->compHandle &&
447          (*proxy->streamOpts.streamCompFlush)(proxy->fd)) ||
448         proxy->ofirst) {
449         FD_SET(proxy->fd, &ClientsWriteBlocked);
450         AnyClientsWriteBlocked = TRUE;
451     }
452     return 0;
453 }
454
455 int
456 UncompressedWriteToClient (who, count, buf)
457     ClientPtr who;
458     char *buf;
459     int count;
460 {
461     return LbxClientOutput(who, (OsCommPtr)who->osPrivate, buf, count, TRUE);
462 }
463
464 LbxFreeOsBuffers(proxy)
465     LbxProxyPtr proxy;
466 {
467     ConnectionOutputPtr oco;
468
469     while (oco = proxy->ofirst) {
470         proxy->ofirst = oco->next;
471         xfree(oco->buf);
472         xfree(oco);
473     }
474 }
475
476 Bool
477 AllocateLargeReqBuffer(client, size)
478     ClientPtr client;
479     int size;
480 {
481     OsCommPtr oc = (OsCommPtr)client->osPrivate;
482     register ConnectionInputPtr oci;
483
484     if (!(oci = oc->largereq)) {
485         if (oci = FreeInputs)
486             FreeInputs = oci->next;
487         else {
488             oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
489             if (!oci)
490                 return FALSE;
491             oci->buffer = NULL;
492             oci->size = 0;
493         }
494     }
495     if (oci->size < size) {
496         char *ibuf;
497
498         oci->size = size;
499         if (size < BUFSIZE)
500             oci->size = BUFSIZE;
501         if (!(ibuf = (char *)xrealloc(oci->buffer, oci->size)))
502         {
503             xfree(oci->buffer);
504             xfree(oci);
505             oc->largereq = NULL;
506             return FALSE;
507         }
508         oci->buffer = ibuf;
509     }
510     oci->bufptr = oci->buffer;
511     oci->bufcnt = 0;
512     oci->lenLastReq = size;
513     oc->largereq = oci;
514     return TRUE;
515 }
516
517 Bool
518 AddToLargeReqBuffer(client, data, size)
519     ClientPtr client;
520     char *data;
521     int size;
522 {
523     OsCommPtr oc = (OsCommPtr)client->osPrivate;
524     register ConnectionInputPtr oci = oc->largereq;
525
526     if (!oci || (oci->bufcnt + size > oci->lenLastReq))
527         return FALSE;
528     memcpy(oci->buffer + oci->bufcnt, data, size);
529     oci->bufcnt += size;
530     return TRUE;
531 }
532
533 static OsCommRec lbxAvailableInput;
534
535 int
536 PrepareLargeReqBuffer(client)
537     ClientPtr client;
538 {
539     OsCommPtr oc = (OsCommPtr)client->osPrivate;
540     register ConnectionInputPtr oci = oc->largereq;
541
542     if (!oci)
543         return client->req_len << 2;
544     oc->largereq = NULL;
545     if (oci->bufcnt != oci->lenLastReq) {
546         xfree(oci->buffer);
547         xfree(oci);
548         return client->req_len << 2;
549     }
550     client->requestBuffer = oci->buffer;
551     client->req_len = oci->lenLastReq >> 2;
552     oci->bufcnt = 0;
553     oci->lenLastReq = 0;
554     if (AvailableInput)
555     {
556         register ConnectionInputPtr aci = AvailableInput->input;
557         if (aci->size > BUFWATERMARK)
558         {
559             xfree(aci->buffer);
560             xfree(aci);
561         }
562         else
563         {
564             aci->next = FreeInputs;
565             FreeInputs = aci;
566         }
567         AvailableInput->input = (ConnectionInputPtr)NULL;
568     }
569     lbxAvailableInput.input = oci;
570     AvailableInput = &lbxAvailableInput;
571     return client->req_len << 2;
572 }