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