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