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.
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.
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
24 ******************************************************************/
25 /* $XConsortium: lbxio.c /main/10 1996/12/16 23:03:30 rws $ */
30 /* $XFree86: xc/programs/Xserver/os/lbxio.c,v 3.8 1997/01/18 07:18:31 dawes Exp $ */
33 #include <X11/Xtrans.h>
40 #include <sys/param.h>
53 #include "dixstruct.h"
57 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
58 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
60 #if defined(EAGAIN) && defined(EWOULDBLOCK)
61 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
64 #define ETEST(err) (err == EAGAIN)
66 #define ETEST(err) (err == EWOULDBLOCK)
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;
83 #define get_req_len(req,cli) ((cli)->swapped ? \
84 lswaps((req)->length) : (req)->length)
86 #define YieldControl() \
87 { isItTimeToYield = TRUE; \
88 timesThisConnection = 0; }
89 #define YieldControlNoInput() \
91 FD_CLR(fd, &ClientsWithInput); }
94 SwitchClientInput (client, pending)
98 OsCommPtr oc = (OsCommPtr)client->osPrivate;
100 ConnectionTranslation[oc->fd] = client->index;
102 FD_SET(oc->fd, &ClientsWithInput);
108 LbxPrimeInput(client, proxy)
112 OsCommPtr oc = (OsCommPtr)client->osPrivate;
113 ConnectionInputPtr oci = oc->input;
115 if (oci && proxy->compHandle) {
116 char *extra = oci->bufptr + oci->lenLastReq;
117 int left = oci->bufcnt + oci->buffer - extra;
119 (*proxy->streamOpts.streamCompStuffInput)(oc->fd,
120 (unsigned char *)extra,
128 AvailableClientInput (client)
131 OsCommPtr oc = (OsCommPtr)client->osPrivate;
133 if (FD_ISSET(oc->fd, &AllSockets))
134 FD_SET(oc->fd, &ClientsWithInput);
137 /*****************************************************************
139 * Append a (possibly partial) request in as the last request.
141 **********************/
144 AppendFakeRequest (client, data, count)
149 OsCommPtr oc = (OsCommPtr)client->osPrivate;
150 register ConnectionInputPtr oci = oc->input;
156 if (oci = FreeInputs)
157 FreeInputs = oci->next;
158 else if (!(oci = AllocateInputBuffer()))
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;
166 gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
167 if ((gotnow + count) > oci->size)
171 ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
174 oci->size = gotnow + count;
176 oci->bufptr = ibuf + oci->bufcnt - gotnow;
178 if (oci->bufcnt + count > oci->size) {
179 memmove(oci->buffer, oci->bufptr, gotnow);
180 oci->bufcnt = gotnow;
181 oci->bufptr = oci->buffer;
183 memmove(oci->bufptr + gotnow, data, count);
184 oci->bufcnt += count;
186 if ((gotnow >= sizeof(xReq)) &&
187 (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
188 FD_SET(fd, &ClientsWithInput);
190 YieldControlNoInput();
195 LbxWrite(trans_conn, proxy, buf, len)
196 XtransConnInfo trans_conn;
210 if (proxy->compHandle)
211 n = (*proxy->streamOpts.streamCompWriteV)(proxy->fd, &iov, 1);
213 n = _XSERVTransWritev(trans_conn, &iov, 1);
215 iov.iov_base = (char *)iov.iov_base + n;
217 iov.iov_len = notWritten;
219 else if (ETEST(errno)
220 #ifdef SUNSYSV /* check for another brain-damaged OS bug */
223 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
224 || ((errno == EMSGSIZE) && (iov.iov_len == 1))
228 #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
229 else if (errno == EMSGSIZE)
235 return len - notWritten;
239 LbxAppendOutput(proxy, client, oco)
242 ConnectionOutputPtr oco;
244 ConnectionOutputPtr noco = proxy->olast;
245 LbxClientPtr lbxClient = LbxClient(client);
253 LbxReencodeOutput(client,
254 (char *)noco->buf, &noco->count,
255 (char *)oco->buf, &oco->count);
257 LbxReencodeOutput(client,
258 (char *)NULL, (int *)NULL,
259 (char *)oco->buf, &oco->count);
261 if (oco->size > BUFWATERMARK)
268 oco->next = FreeOutputs;
273 if ((lbxClient->id != proxy->cur_send_id) && proxy->lbxClients[0]) {
277 if (!noco || (noco->size - noco->count) < sz_xLbxSwitchEvent) {
278 if (noco = FreeOutputs)
279 FreeOutputs = noco->next;
281 noco = AllocateOutputBuffer();
283 MarkClientException(client);
288 proxy->olast->next = noco;
290 proxy->ofirst = noco;
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;
299 ev->client = proxy->cur_send_id;
300 if (LbxProxyClient(proxy)->swapped) {
301 swapl(&ev->client, n);
306 proxy->olast->next = oco;
314 LbxClientOutput(client, oc, extraBuf, extraCount, nocompress)
321 ConnectionOutputPtr oco;
324 if (oco = oc->output) {
326 if (!LbxAppendOutput(oc->proxy, client, oco))
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;
337 oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
339 MarkClientException(client);
343 if (oco->size < BUFSIZE)
345 oco->buf = (unsigned char *) xalloc(oco->size);
348 MarkClientException(client);
353 oco->nocompress = nocompress;
354 memmove((char *)oco->buf, extraBuf, extraCount);
355 if (!nocompress && oco->count < oco->size)
357 else if (!LbxAppendOutput(oc->proxy, client, oco))
364 LbxForceOutput(proxy)
368 LbxClientPtr lbxClient;
370 ConnectionOutputPtr oco;
372 for (i = proxy->maxIndex; i >= 0; i--) { /* proxy must be last */
373 lbxClient = proxy->lbxClients[i];
376 coc = (OsCommPtr)lbxClient->client->osPrivate;
377 if (oco = coc->output) {
379 LbxAppendOutput(proxy, lbxClient->client, oco);
385 LbxFlushClient(who, oc, extraBuf, extraCount)
392 ConnectionOutputPtr oco;
394 XtransConnInfo trans_conn;
397 return LbxClientOutput(who, oc, extraBuf, extraCount, FALSE);
399 if (!proxy->lbxClients[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) {
408 (*proxy->streamOpts.streamCompOff)(proxy->fd);
409 n = LbxWrite(NULL, proxy, (char *)oco->buf, oco->count);
411 (*proxy->streamOpts.streamCompOn)(proxy->fd);
413 n = LbxWrite(trans_conn, proxy, (char *)oco->buf, oco->count);
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);
423 } else if (n == oco->count) {
424 proxy->ofirst = oco->next;
427 if (oco->size > BUFWATERMARK)
434 oco->next = FreeOutputs;
441 memmove((char *)oco->buf, (char *)oco->buf + n, oco->count);
446 if ((proxy->compHandle &&
447 (*proxy->streamOpts.streamCompFlush)(proxy->fd)) ||
449 FD_SET(proxy->fd, &ClientsWriteBlocked);
450 AnyClientsWriteBlocked = TRUE;
456 UncompressedWriteToClient (who, count, buf)
461 return LbxClientOutput(who, (OsCommPtr)who->osPrivate, buf, count, TRUE);
464 LbxFreeOsBuffers(proxy)
467 ConnectionOutputPtr oco;
469 while (oco = proxy->ofirst) {
470 proxy->ofirst = oco->next;
477 AllocateLargeReqBuffer(client, size)
481 OsCommPtr oc = (OsCommPtr)client->osPrivate;
482 register ConnectionInputPtr oci;
484 if (!(oci = oc->largereq)) {
485 if (oci = FreeInputs)
486 FreeInputs = oci->next;
488 oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
495 if (oci->size < size) {
501 if (!(ibuf = (char *)xrealloc(oci->buffer, oci->size)))
510 oci->bufptr = oci->buffer;
512 oci->lenLastReq = size;
518 AddToLargeReqBuffer(client, data, size)
523 OsCommPtr oc = (OsCommPtr)client->osPrivate;
524 register ConnectionInputPtr oci = oc->largereq;
526 if (!oci || (oci->bufcnt + size > oci->lenLastReq))
528 memcpy(oci->buffer + oci->bufcnt, data, size);
533 static OsCommRec lbxAvailableInput;
536 PrepareLargeReqBuffer(client)
539 OsCommPtr oc = (OsCommPtr)client->osPrivate;
540 register ConnectionInputPtr oci = oc->largereq;
543 return client->req_len << 2;
545 if (oci->bufcnt != oci->lenLastReq) {
548 return client->req_len << 2;
550 client->requestBuffer = oci->buffer;
551 client->req_len = oci->lenLastReq >> 2;
556 register ConnectionInputPtr aci = AvailableInput->input;
557 if (aci->size > BUFWATERMARK)
564 aci->next = FreeInputs;
567 AvailableInput->input = (ConnectionInputPtr)NULL;
569 lbxAvailableInput.input = oci;
570 AvailableInput = &lbxAvailableInput;
571 return client->req_len << 2;