1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1989, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg
47706f2543Smrg******************************************************************/
48706f2543Smrg/*****************************************************************
49706f2543Smrg * i/o functions
50706f2543Smrg *
51706f2543Smrg *   WriteToClient, ReadRequestFromClient
52706f2543Smrg *   InsertFakeRequest, ResetCurrentRequest
53706f2543Smrg *
54706f2543Smrg *****************************************************************/
55706f2543Smrg
56706f2543Smrg#include <X11/Xpoll.h>
57706f2543Smrg
58706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
59706f2543Smrg#include <dix-config.h>
60706f2543Smrg#endif
61706f2543Smrg
62706f2543Smrg#undef DEBUG_COMMUNICATION
63706f2543Smrg
64706f2543Smrg#ifdef WIN32
65706f2543Smrg#include <X11/Xwinsock.h>
66706f2543Smrg#endif
67706f2543Smrg#include <stdio.h>
68706f2543Smrg#define XSERV_t
69706f2543Smrg#define TRANS_SERVER
70706f2543Smrg#define TRANS_REOPEN
71706f2543Smrg#include <X11/Xtrans/Xtrans.h>
72706f2543Smrg#include <X11/Xmd.h>
73706f2543Smrg#include <errno.h>
74706f2543Smrg#if !defined(WIN32)
75706f2543Smrg#include <sys/uio.h>
76706f2543Smrg#endif
77706f2543Smrg#include <X11/X.h>
78706f2543Smrg#include <X11/Xproto.h>
79706f2543Smrg#include "os.h"
80706f2543Smrg#include "osdep.h"
81706f2543Smrg#include "opaque.h"
82706f2543Smrg#include "dixstruct.h"
83706f2543Smrg#include "misc.h"
84706f2543Smrg
85706f2543SmrgCallbackListPtr       ReplyCallback;
86706f2543SmrgCallbackListPtr       FlushCallback;
87706f2543Smrg
88706f2543Smrgstatic ConnectionInputPtr AllocateInputBuffer(void);
89706f2543Smrgstatic ConnectionOutputPtr AllocateOutputBuffer(void);
90706f2543Smrg
91706f2543Smrg/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
92706f2543Smrg * systems are broken and return EWOULDBLOCK when they should return EAGAIN
93706f2543Smrg */
94706f2543Smrg#ifndef WIN32
95706f2543Smrg#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
96706f2543Smrg#else /* WIN32 The socket errorcodes differ from the normal errors*/
97706f2543Smrg#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
98706f2543Smrg#endif
99706f2543Smrg
100706f2543Smrgstatic Bool CriticalOutputPending;
101706f2543Smrgstatic int timesThisConnection = 0;
102706f2543Smrgstatic ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
103706f2543Smrgstatic ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
104706f2543Smrgstatic OsCommPtr AvailableInput = (OsCommPtr)NULL;
105706f2543Smrg
106706f2543Smrg#define get_req_len(req,cli) ((cli)->swapped ? \
107706f2543Smrg			      lswaps((req)->length) : (req)->length)
108706f2543Smrg
109706f2543Smrg#include <X11/extensions/bigreqsproto.h>
110706f2543Smrg
111706f2543Smrg#define get_big_req_len(req,cli) ((cli)->swapped ? \
112706f2543Smrg				  lswapl(((xBigReq *)(req))->length) : \
113706f2543Smrg				  ((xBigReq *)(req))->length)
114706f2543Smrg
115706f2543Smrg#define MAX_TIMES_PER         10
116706f2543Smrg
117706f2543Smrg/*
118706f2543Smrg *   A lot of the code in this file manipulates a ConnectionInputPtr:
119706f2543Smrg *
120706f2543Smrg *    -----------------------------------------------
121706f2543Smrg *   |------- bufcnt ------->|           |           |
122706f2543Smrg *   |           |- gotnow ->|           |           |
123706f2543Smrg *   |           |-------- needed ------>|           |
124706f2543Smrg *   |-----------+--------- size --------+---------->|
125706f2543Smrg *    -----------------------------------------------
126706f2543Smrg *   ^           ^
127706f2543Smrg *   |           |
128706f2543Smrg *   buffer   bufptr
129706f2543Smrg *
130706f2543Smrg *  buffer is a pointer to the start of the buffer.
131706f2543Smrg *  bufptr points to the start of the current request.
132706f2543Smrg *  bufcnt counts how many bytes are in the buffer.
133706f2543Smrg *  size is the size of the buffer in bytes.
134706f2543Smrg *
135706f2543Smrg *  In several of the functions, gotnow and needed are local variables
136706f2543Smrg *  that do the following:
137706f2543Smrg *
138706f2543Smrg *  gotnow is the number of bytes of the request that we're
139706f2543Smrg *  trying to read that are currently in the buffer.
140706f2543Smrg *  Typically, gotnow = (buffer + bufcnt) - bufptr
141706f2543Smrg *
142706f2543Smrg *  needed = the length of the request that we're trying to
143706f2543Smrg *  read.  Watch out: needed sometimes counts bytes and sometimes
144706f2543Smrg *  counts CARD32's.
145706f2543Smrg */
146706f2543Smrg
147706f2543Smrg
148706f2543Smrg/*****************************************************************
149706f2543Smrg * ReadRequestFromClient
150706f2543Smrg *    Returns one request in client->requestBuffer.  The request
151706f2543Smrg *    length will be in client->req_len.  Return status is:
152706f2543Smrg *
153706f2543Smrg *    > 0  if  successful, specifies length in bytes of the request
154706f2543Smrg *    = 0  if  entire request is not yet available
155706f2543Smrg *    < 0  if  client should be terminated
156706f2543Smrg *
157706f2543Smrg *    The request returned must be contiguous so that it can be
158706f2543Smrg *    cast in the dispatcher to the correct request type.  Because requests
159706f2543Smrg *    are variable length, ReadRequestFromClient() must look at the first 4
160706f2543Smrg *    or 8 bytes of a request to determine the length (the request length is
161706f2543Smrg *    in the 3rd and 4th bytes of the request unless it is a Big Request
162706f2543Smrg *    (see the Big Request Extension), in which case the 3rd and 4th bytes
163706f2543Smrg *    are zero and the following 4 bytes are the request length.
164706f2543Smrg *
165706f2543Smrg *    Note: in order to make the server scheduler (WaitForSomething())
166706f2543Smrg *    "fair", the ClientsWithInput mask is used.  This mask tells which
167706f2543Smrg *    clients have FULL requests left in their buffers.  Clients with
168706f2543Smrg *    partial requests require a read.  Basically, client buffers
169706f2543Smrg *    are drained before select() is called again.  But, we can't keep
170706f2543Smrg *    reading from a client that is sending buckets of data (or has
171706f2543Smrg *    a partial request) because others clients need to be scheduled.
172706f2543Smrg *****************************************************************/
173706f2543Smrg
174706f2543Smrgstatic void
175706f2543SmrgYieldControl(void)
176706f2543Smrg{
177706f2543Smrg    isItTimeToYield = TRUE;
178706f2543Smrg    timesThisConnection = 0;
179706f2543Smrg}
180706f2543Smrg
181706f2543Smrgstatic void
182706f2543SmrgYieldControlNoInput(int fd)
183706f2543Smrg{
184706f2543Smrg    YieldControl();
185706f2543Smrg    FD_CLR(fd, &ClientsWithInput);
186706f2543Smrg}
187706f2543Smrg
188706f2543Smrgstatic void
189706f2543SmrgYieldControlDeath(void)
190706f2543Smrg{
191706f2543Smrg    timesThisConnection = 0;
192706f2543Smrg}
193706f2543Smrg
194706f2543Smrgint
195706f2543SmrgReadRequestFromClient(ClientPtr client)
196706f2543Smrg{
197706f2543Smrg    OsCommPtr oc = (OsCommPtr)client->osPrivate;
198706f2543Smrg    ConnectionInputPtr oci = oc->input;
199706f2543Smrg    int fd = oc->fd;
200706f2543Smrg    unsigned int gotnow, needed;
201706f2543Smrg    int result;
202706f2543Smrg    register xReq *request;
203706f2543Smrg    Bool need_header;
204706f2543Smrg    Bool move_header;
205706f2543Smrg
206706f2543Smrg    /* If an input buffer was empty, either free it if it is too big
207706f2543Smrg     * or link it into our list of free input buffers.  This means that
208706f2543Smrg     * different clients can share the same input buffer (at different
209706f2543Smrg     * times).  This was done to save memory.
210706f2543Smrg     */
211706f2543Smrg
212706f2543Smrg    if (AvailableInput)
213706f2543Smrg    {
214706f2543Smrg	if (AvailableInput != oc)
215706f2543Smrg	{
216706f2543Smrg	    register ConnectionInputPtr aci = AvailableInput->input;
217706f2543Smrg	    if (aci->size > BUFWATERMARK)
218706f2543Smrg	    {
219706f2543Smrg		free(aci->buffer);
220706f2543Smrg		free(aci);
221706f2543Smrg	    }
222706f2543Smrg	    else
223706f2543Smrg	    {
224706f2543Smrg		aci->next = FreeInputs;
225706f2543Smrg		FreeInputs = aci;
226706f2543Smrg	    }
227706f2543Smrg	    AvailableInput->input = (ConnectionInputPtr)NULL;
228706f2543Smrg	}
229706f2543Smrg	AvailableInput = (OsCommPtr)NULL;
230706f2543Smrg    }
231706f2543Smrg
232706f2543Smrg    /* make sure we have an input buffer */
233706f2543Smrg
234706f2543Smrg    if (!oci)
235706f2543Smrg    {
236706f2543Smrg	if ((oci = FreeInputs))
237706f2543Smrg	{
238706f2543Smrg	    FreeInputs = oci->next;
239706f2543Smrg	}
240706f2543Smrg	else if (!(oci = AllocateInputBuffer()))
241706f2543Smrg	{
242706f2543Smrg	    YieldControlDeath();
243706f2543Smrg	    return -1;
244706f2543Smrg	}
245706f2543Smrg	oc->input = oci;
246706f2543Smrg    }
247706f2543Smrg
248706f2543Smrg    /* advance to start of next request */
249706f2543Smrg
250706f2543Smrg    oci->bufptr += oci->lenLastReq;
251706f2543Smrg
252706f2543Smrg    need_header = FALSE;
253706f2543Smrg    move_header = FALSE;
254706f2543Smrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
255706f2543Smrg
256706f2543Smrg    if (oci->ignoreBytes > 0) {
257706f2543Smrg	if (oci->ignoreBytes > oci->size)
258706f2543Smrg	    needed = oci->size;
259706f2543Smrg	else
260706f2543Smrg	    needed = oci->ignoreBytes;
261706f2543Smrg    }
262706f2543Smrg    else if (gotnow < sizeof(xReq))
263706f2543Smrg    {
264706f2543Smrg	/* We don't have an entire xReq yet.  Can't tell how big
265706f2543Smrg	 * the request will be until we get the whole xReq.
266706f2543Smrg	 */
267706f2543Smrg	needed = sizeof(xReq);
268706f2543Smrg	need_header = TRUE;
269706f2543Smrg    }
270706f2543Smrg    else
271706f2543Smrg    {
272706f2543Smrg	/* We have a whole xReq.  We can tell how big the whole
273706f2543Smrg	 * request will be unless it is a Big Request.
274706f2543Smrg	 */
275706f2543Smrg	request = (xReq *)oci->bufptr;
276706f2543Smrg	needed = get_req_len(request, client);
277706f2543Smrg	if (!needed && client->big_requests)
278706f2543Smrg	{
279706f2543Smrg	    /* It's a Big Request. */
280706f2543Smrg	    move_header = TRUE;
281706f2543Smrg	    if (gotnow < sizeof(xBigReq))
282706f2543Smrg	    {
283706f2543Smrg		/* Still need more data to tell just how big. */
284706f2543Smrg		needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */
285706f2543Smrg		need_header = TRUE;
286706f2543Smrg	    }
287706f2543Smrg	    else
288706f2543Smrg		needed = get_big_req_len(request, client);
289706f2543Smrg	}
290706f2543Smrg	client->req_len = needed;
291706f2543Smrg	needed <<= 2; /* needed is in bytes now */
292706f2543Smrg    }
293706f2543Smrg    if (gotnow < needed)
294706f2543Smrg    {
295706f2543Smrg	/* Need to read more data, either so that we can get a
296706f2543Smrg	 * complete xReq (if need_header is TRUE), a complete
297706f2543Smrg	 * xBigReq (if move_header is TRUE), or the rest of the
298706f2543Smrg	 * request (if need_header and move_header are both FALSE).
299706f2543Smrg	 */
300706f2543Smrg
301706f2543Smrg	oci->lenLastReq = 0;
302706f2543Smrg	if (needed > maxBigRequestSize << 2)
303706f2543Smrg	{
304706f2543Smrg	    /* request is too big for us to handle */
305706f2543Smrg	    /*
306706f2543Smrg	     * Mark the rest of it as needing to be ignored, and then return
307706f2543Smrg	     * the full size.  Dispatch() will turn it into a BadLength error.
308706f2543Smrg	     */
309706f2543Smrg	    oci->ignoreBytes = needed - gotnow;
310706f2543Smrg	    oci->lenLastReq = gotnow;
311706f2543Smrg	    return needed;
312706f2543Smrg	}
313706f2543Smrg	if ((gotnow == 0) ||
314706f2543Smrg	    ((oci->bufptr - oci->buffer + needed) > oci->size))
315706f2543Smrg	{
316706f2543Smrg	    /* no data, or the request is too big to fit in the buffer */
317706f2543Smrg
318706f2543Smrg	    if ((gotnow > 0) && (oci->bufptr != oci->buffer))
319706f2543Smrg		/* save the data we've already read */
320706f2543Smrg		memmove(oci->buffer, oci->bufptr, gotnow);
321706f2543Smrg	    if (needed > oci->size)
322706f2543Smrg	    {
323706f2543Smrg		/* make buffer bigger to accomodate request */
324706f2543Smrg		char *ibuf;
325706f2543Smrg
326706f2543Smrg		ibuf = (char *)realloc(oci->buffer, needed);
327706f2543Smrg		if (!ibuf)
328706f2543Smrg		{
329706f2543Smrg		    YieldControlDeath();
330706f2543Smrg		    return -1;
331706f2543Smrg		}
332706f2543Smrg		oci->size = needed;
333706f2543Smrg		oci->buffer = ibuf;
334706f2543Smrg	    }
335706f2543Smrg	    oci->bufptr = oci->buffer;
336706f2543Smrg	    oci->bufcnt = gotnow;
337706f2543Smrg	}
338706f2543Smrg	/*  XXX this is a workaround.  This function is sometimes called
339706f2543Smrg	 *  after the trans_conn has been freed.  In this case trans_conn
340706f2543Smrg	 *  will be null.  Really ought to restructure things so that we
341706f2543Smrg	 *  never get here in those circumstances.
342706f2543Smrg	 */
343706f2543Smrg	if (!oc->trans_conn)
344706f2543Smrg	{
345706f2543Smrg	    /*  treat as if an error occured on the read, which is what
346706f2543Smrg	     *  used to happen
347706f2543Smrg	     */
348706f2543Smrg	    YieldControlDeath();
349706f2543Smrg	    return -1;
350706f2543Smrg	}
351706f2543Smrg	    result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
352706f2543Smrg				     oci->size - oci->bufcnt);
353706f2543Smrg	if (result <= 0)
354706f2543Smrg	{
355706f2543Smrg	    if ((result < 0) && ETEST(errno))
356706f2543Smrg	    {
357706f2543Smrg#if defined(SVR4) && defined(__i386__) && !defined(sun)
358706f2543Smrg		if (0)
359706f2543Smrg#endif
360706f2543Smrg		{
361706f2543Smrg		    YieldControlNoInput(fd);
362706f2543Smrg		    return 0;
363706f2543Smrg		}
364706f2543Smrg	    }
365706f2543Smrg	    YieldControlDeath();
366706f2543Smrg	    return -1;
367706f2543Smrg	}
368706f2543Smrg	oci->bufcnt += result;
369706f2543Smrg	gotnow += result;
370706f2543Smrg	/* free up some space after huge requests */
371706f2543Smrg	if ((oci->size > BUFWATERMARK) &&
372706f2543Smrg	    (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
373706f2543Smrg	{
374706f2543Smrg	    char *ibuf;
375706f2543Smrg
376706f2543Smrg	    ibuf = (char *)realloc(oci->buffer, BUFSIZE);
377706f2543Smrg	    if (ibuf)
378706f2543Smrg	    {
379706f2543Smrg		oci->size = BUFSIZE;
380706f2543Smrg		oci->buffer = ibuf;
381706f2543Smrg		oci->bufptr = ibuf + oci->bufcnt - gotnow;
382706f2543Smrg	    }
383706f2543Smrg	}
384706f2543Smrg	if (need_header && gotnow >= needed)
385706f2543Smrg	{
386706f2543Smrg	    /* We wanted an xReq, now we've gotten it. */
387706f2543Smrg	    request = (xReq *)oci->bufptr;
388706f2543Smrg	    needed = get_req_len(request, client);
389706f2543Smrg	    if (!needed && client->big_requests)
390706f2543Smrg	    {
391706f2543Smrg		move_header = TRUE;
392706f2543Smrg		if (gotnow < sizeof(xBigReq))
393706f2543Smrg		    needed = bytes_to_int32(sizeof(xBigReq));
394706f2543Smrg		else
395706f2543Smrg		    needed = get_big_req_len(request, client);
396706f2543Smrg	    }
397706f2543Smrg	    client->req_len = needed;
398706f2543Smrg	    needed <<= 2;
399706f2543Smrg	}
400706f2543Smrg	if (gotnow < needed)
401706f2543Smrg	{
402706f2543Smrg	    /* Still don't have enough; punt. */
403706f2543Smrg	    YieldControlNoInput(fd);
404706f2543Smrg	    return 0;
405706f2543Smrg	}
406706f2543Smrg    }
407706f2543Smrg    if (needed == 0)
408706f2543Smrg    {
409706f2543Smrg	if (client->big_requests)
410706f2543Smrg	    needed = sizeof(xBigReq);
411706f2543Smrg	else
412706f2543Smrg	    needed = sizeof(xReq);
413706f2543Smrg    }
414706f2543Smrg
415706f2543Smrg    /* If there are bytes to ignore, ignore them now. */
416706f2543Smrg
417706f2543Smrg    if (oci->ignoreBytes > 0) {
418706f2543Smrg	assert(needed == oci->ignoreBytes || needed == oci->size);
419706f2543Smrg	/*
420706f2543Smrg	 * The _XSERVTransRead call above may return more or fewer bytes than we
421706f2543Smrg	 * want to ignore.  Ignore the smaller of the two sizes.
422706f2543Smrg	 */
423706f2543Smrg	if (gotnow < needed) {
424706f2543Smrg	    oci->ignoreBytes -= gotnow;
425706f2543Smrg	    oci->bufptr += gotnow;
426706f2543Smrg	    gotnow = 0;
427706f2543Smrg	} else {
428706f2543Smrg	    oci->ignoreBytes -= needed;
429706f2543Smrg	    oci->bufptr += needed;
430706f2543Smrg	    gotnow -= needed;
431706f2543Smrg	}
432706f2543Smrg	needed = 0;
433706f2543Smrg    }
434706f2543Smrg
435706f2543Smrg    oci->lenLastReq = needed;
436706f2543Smrg
437706f2543Smrg    /*
438706f2543Smrg     *  Check to see if client has at least one whole request in the
439706f2543Smrg     *  buffer beyond the request we're returning to the caller.
440706f2543Smrg     *  If there is only a partial request, treat like buffer
441706f2543Smrg     *  is empty so that select() will be called again and other clients
442706f2543Smrg     *  can get into the queue.
443706f2543Smrg     */
444706f2543Smrg
445706f2543Smrg    gotnow -= needed;
446706f2543Smrg    if (gotnow >= sizeof(xReq))
447706f2543Smrg    {
448706f2543Smrg	request = (xReq *)(oci->bufptr + needed);
449706f2543Smrg	if (gotnow >= (result = (get_req_len(request, client) << 2))
450706f2543Smrg	    && (result ||
451706f2543Smrg		(client->big_requests &&
452706f2543Smrg		 (gotnow >= sizeof(xBigReq) &&
453706f2543Smrg		  gotnow >= (get_big_req_len(request, client) << 2))))
454706f2543Smrg	    )
455706f2543Smrg	    FD_SET(fd, &ClientsWithInput);
456706f2543Smrg	else
457706f2543Smrg	{
458706f2543Smrg	    if (!SmartScheduleDisable)
459706f2543Smrg		FD_CLR(fd, &ClientsWithInput);
460706f2543Smrg	    else
461706f2543Smrg		YieldControlNoInput(fd);
462706f2543Smrg	}
463706f2543Smrg    }
464706f2543Smrg    else
465706f2543Smrg    {
466706f2543Smrg	if (!gotnow)
467706f2543Smrg	    AvailableInput = oc;
468706f2543Smrg	if (!SmartScheduleDisable)
469706f2543Smrg	    FD_CLR(fd, &ClientsWithInput);
470706f2543Smrg	else
471706f2543Smrg	    YieldControlNoInput(fd);
472706f2543Smrg    }
473706f2543Smrg    if (SmartScheduleDisable)
474706f2543Smrg    if (++timesThisConnection >= MAX_TIMES_PER)
475706f2543Smrg	YieldControl();
476706f2543Smrg    if (move_header)
477706f2543Smrg    {
478706f2543Smrg	request = (xReq *)oci->bufptr;
479706f2543Smrg	oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
480706f2543Smrg	*(xReq *)oci->bufptr = *request;
481706f2543Smrg	oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
482706f2543Smrg	client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq));
483706f2543Smrg    }
484706f2543Smrg    client->requestBuffer = (pointer)oci->bufptr;
485706f2543Smrg#ifdef DEBUG_COMMUNICATION
486706f2543Smrg    {
487706f2543Smrg	xReq *req = client->requestBuffer;
488706f2543Smrg	ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
489706f2543Smrg	       client->index,req->reqType,req->data,req->length);
490706f2543Smrg    }
491706f2543Smrg#endif
492706f2543Smrg    return needed;
493706f2543Smrg}
494706f2543Smrg
495706f2543Smrg/*****************************************************************
496706f2543Smrg * InsertFakeRequest
497706f2543Smrg *    Splice a consed up (possibly partial) request in as the next request.
498706f2543Smrg *
499706f2543Smrg **********************/
500706f2543Smrg
501706f2543SmrgBool
502706f2543SmrgInsertFakeRequest(ClientPtr client, char *data, int count)
503706f2543Smrg{
504706f2543Smrg    OsCommPtr oc = (OsCommPtr)client->osPrivate;
505706f2543Smrg    ConnectionInputPtr oci = oc->input;
506706f2543Smrg    int fd = oc->fd;
507706f2543Smrg    int gotnow, moveup;
508706f2543Smrg
509706f2543Smrg    if (AvailableInput)
510706f2543Smrg    {
511706f2543Smrg	if (AvailableInput != oc)
512706f2543Smrg	{
513706f2543Smrg	    ConnectionInputPtr aci = AvailableInput->input;
514706f2543Smrg	    if (aci->size > BUFWATERMARK)
515706f2543Smrg	    {
516706f2543Smrg		free(aci->buffer);
517706f2543Smrg		free(aci);
518706f2543Smrg	    }
519706f2543Smrg	    else
520706f2543Smrg	    {
521706f2543Smrg		aci->next = FreeInputs;
522706f2543Smrg		FreeInputs = aci;
523706f2543Smrg	    }
524706f2543Smrg	    AvailableInput->input = (ConnectionInputPtr)NULL;
525706f2543Smrg	}
526706f2543Smrg	AvailableInput = (OsCommPtr)NULL;
527706f2543Smrg    }
528706f2543Smrg    if (!oci)
529706f2543Smrg    {
530706f2543Smrg	if ((oci = FreeInputs))
531706f2543Smrg	    FreeInputs = oci->next;
532706f2543Smrg	else if (!(oci = AllocateInputBuffer()))
533706f2543Smrg	    return FALSE;
534706f2543Smrg	oc->input = oci;
535706f2543Smrg    }
536706f2543Smrg    oci->bufptr += oci->lenLastReq;
537706f2543Smrg    oci->lenLastReq = 0;
538706f2543Smrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
539706f2543Smrg    if ((gotnow + count) > oci->size)
540706f2543Smrg    {
541706f2543Smrg	char *ibuf;
542706f2543Smrg
543706f2543Smrg	ibuf = (char *)realloc(oci->buffer, gotnow + count);
544706f2543Smrg	if (!ibuf)
545706f2543Smrg	    return FALSE;
546706f2543Smrg	oci->size = gotnow + count;
547706f2543Smrg	oci->buffer = ibuf;
548706f2543Smrg	oci->bufptr = ibuf + oci->bufcnt - gotnow;
549706f2543Smrg    }
550706f2543Smrg    moveup = count - (oci->bufptr - oci->buffer);
551706f2543Smrg    if (moveup > 0)
552706f2543Smrg    {
553706f2543Smrg	if (gotnow > 0)
554706f2543Smrg	    memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
555706f2543Smrg	oci->bufptr += moveup;
556706f2543Smrg	oci->bufcnt += moveup;
557706f2543Smrg    }
558706f2543Smrg    memmove(oci->bufptr - count, data, count);
559706f2543Smrg    oci->bufptr -= count;
560706f2543Smrg    gotnow += count;
561706f2543Smrg    if ((gotnow >= sizeof(xReq)) &&
562706f2543Smrg	(gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
563706f2543Smrg	FD_SET(fd, &ClientsWithInput);
564706f2543Smrg    else
565706f2543Smrg	YieldControlNoInput(fd);
566706f2543Smrg    return TRUE;
567706f2543Smrg}
568706f2543Smrg
569706f2543Smrg/*****************************************************************
570706f2543Smrg * ResetRequestFromClient
571706f2543Smrg *    Reset to reexecute the current request, and yield.
572706f2543Smrg *
573706f2543Smrg **********************/
574706f2543Smrg
575706f2543Smrgvoid
576706f2543SmrgResetCurrentRequest(ClientPtr client)
577706f2543Smrg{
578706f2543Smrg    OsCommPtr oc = (OsCommPtr)client->osPrivate;
579706f2543Smrg    register ConnectionInputPtr oci = oc->input;
580706f2543Smrg    int fd = oc->fd;
581706f2543Smrg    register xReq *request;
582706f2543Smrg    int gotnow, needed;
583706f2543Smrg    if (AvailableInput == oc)
584706f2543Smrg	AvailableInput = (OsCommPtr)NULL;
585706f2543Smrg    oci->lenLastReq = 0;
586706f2543Smrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
587706f2543Smrg    if (gotnow < sizeof(xReq))
588706f2543Smrg    {
589706f2543Smrg	YieldControlNoInput(fd);
590706f2543Smrg    }
591706f2543Smrg    else
592706f2543Smrg    {
593706f2543Smrg	request = (xReq *)oci->bufptr;
594706f2543Smrg	needed = get_req_len(request, client);
595706f2543Smrg	if (!needed && client->big_requests)
596706f2543Smrg	{
597706f2543Smrg	    oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
598706f2543Smrg	    *(xReq *)oci->bufptr = *request;
599706f2543Smrg	    ((xBigReq *)oci->bufptr)->length = client->req_len;
600706f2543Smrg	    if (client->swapped)
601706f2543Smrg	    {
602706f2543Smrg		char n;
603706f2543Smrg		swapl(&((xBigReq *)oci->bufptr)->length, n);
604706f2543Smrg	    }
605706f2543Smrg	}
606706f2543Smrg	if (gotnow >= (needed << 2))
607706f2543Smrg	{
608706f2543Smrg	    if (FD_ISSET(fd, &AllClients))
609706f2543Smrg	    {
610706f2543Smrg		FD_SET(fd, &ClientsWithInput);
611706f2543Smrg	    }
612706f2543Smrg	    else
613706f2543Smrg	    {
614706f2543Smrg		FD_SET(fd, &IgnoredClientsWithInput);
615706f2543Smrg	    }
616706f2543Smrg	    YieldControl();
617706f2543Smrg	}
618706f2543Smrg	else
619706f2543Smrg	    YieldControlNoInput(fd);
620706f2543Smrg    }
621706f2543Smrg}
622706f2543Smrg
623706f2543Smrgstatic const int padlength[4] = {0, 3, 2, 1};
624706f2543Smrg
625706f2543Smrg /********************
626706f2543Smrg * FlushAllOutput()
627706f2543Smrg *    Flush all clients with output.  However, if some client still
628706f2543Smrg *    has input in the queue (more requests), then don't flush.  This
629706f2543Smrg *    will prevent the output queue from being flushed every time around
630706f2543Smrg *    the round robin queue.  Now, some say that it SHOULD be flushed
631706f2543Smrg *    every time around, but...
632706f2543Smrg *
633706f2543Smrg **********************/
634706f2543Smrg
635706f2543Smrgvoid
636706f2543SmrgFlushAllOutput(void)
637706f2543Smrg{
638706f2543Smrg    register int index, base;
639706f2543Smrg    register fd_mask mask; /* raphael */
640706f2543Smrg    OsCommPtr oc;
641706f2543Smrg    register ClientPtr client;
642706f2543Smrg    Bool newoutput = NewOutputPending;
643706f2543Smrg#if defined(WIN32)
644706f2543Smrg    fd_set newOutputPending;
645706f2543Smrg#endif
646706f2543Smrg
647706f2543Smrg    if (FlushCallback)
648706f2543Smrg	CallCallbacks(&FlushCallback, NULL);
649706f2543Smrg
650706f2543Smrg    if (!newoutput)
651706f2543Smrg	return;
652706f2543Smrg
653706f2543Smrg    /*
654706f2543Smrg     * It may be that some client still has critical output pending,
655706f2543Smrg     * but he is not yet ready to receive it anyway, so we will
656706f2543Smrg     * simply wait for the select to tell us when he's ready to receive.
657706f2543Smrg     */
658706f2543Smrg    CriticalOutputPending = FALSE;
659706f2543Smrg    NewOutputPending = FALSE;
660706f2543Smrg
661706f2543Smrg#ifndef WIN32
662706f2543Smrg    for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
663706f2543Smrg    {
664706f2543Smrg	mask = OutputPending.fds_bits[ base ];
665706f2543Smrg	OutputPending.fds_bits[ base ] = 0;
666706f2543Smrg	while (mask)
667706f2543Smrg	{
668706f2543Smrg	    index = ffs(mask) - 1;
669706f2543Smrg	    mask &= ~lowbit(mask);
670706f2543Smrg	    if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0)
671706f2543Smrg		continue;
672706f2543Smrg	    client = clients[index];
673706f2543Smrg	    if (client->clientGone)
674706f2543Smrg		continue;
675706f2543Smrg	    oc = (OsCommPtr)client->osPrivate;
676706f2543Smrg	    if (FD_ISSET(oc->fd, &ClientsWithInput))
677706f2543Smrg	    {
678706f2543Smrg		FD_SET(oc->fd, &OutputPending); /* set the bit again */
679706f2543Smrg		NewOutputPending = TRUE;
680706f2543Smrg	    }
681706f2543Smrg	    else
682706f2543Smrg		(void)FlushClient(client, oc, (char *)NULL, 0);
683706f2543Smrg	}
684706f2543Smrg    }
685706f2543Smrg#else  /* WIN32 */
686706f2543Smrg    FD_ZERO(&newOutputPending);
687706f2543Smrg    for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
688706f2543Smrg    {
689706f2543Smrg	    index = XFD_FD(&OutputPending, base);
690706f2543Smrg	    if ((index = GetConnectionTranslation(index)) == 0)
691706f2543Smrg		continue;
692706f2543Smrg	    client = clients[index];
693706f2543Smrg	    if (client->clientGone)
694706f2543Smrg		continue;
695706f2543Smrg	    oc = (OsCommPtr)client->osPrivate;
696706f2543Smrg	    if (FD_ISSET(oc->fd, &ClientsWithInput))
697706f2543Smrg	    {
698706f2543Smrg		FD_SET(oc->fd, &newOutputPending); /* set the bit again */
699706f2543Smrg		NewOutputPending = TRUE;
700706f2543Smrg	    }
701706f2543Smrg	    else
702706f2543Smrg		(void)FlushClient(client, oc, (char *)NULL, 0);
703706f2543Smrg    }
704706f2543Smrg    XFD_COPYSET(&newOutputPending, &OutputPending);
705706f2543Smrg#endif /* WIN32 */
706706f2543Smrg}
707706f2543Smrg
708706f2543Smrgvoid
709706f2543SmrgFlushIfCriticalOutputPending(void)
710706f2543Smrg{
711706f2543Smrg    if (CriticalOutputPending)
712706f2543Smrg	FlushAllOutput();
713706f2543Smrg}
714706f2543Smrg
715706f2543Smrgvoid
716706f2543SmrgSetCriticalOutputPending(void)
717706f2543Smrg{
718706f2543Smrg    CriticalOutputPending = TRUE;
719706f2543Smrg}
720706f2543Smrg
721706f2543Smrg/*****************
722706f2543Smrg * WriteToClient
723706f2543Smrg *    Copies buf into ClientPtr.buf if it fits (with padding), else
724706f2543Smrg *    flushes ClientPtr.buf and buf to client.  As of this writing,
725706f2543Smrg *    every use of WriteToClient is cast to void, and the result
726706f2543Smrg *    is ignored.  Potentially, this could be used by requests
727706f2543Smrg *    that are sending several chunks of data and want to break
728706f2543Smrg *    out of a loop on error.  Thus, we will leave the type of
729706f2543Smrg *    this routine as int.
730706f2543Smrg *****************/
731706f2543Smrg
732706f2543Smrgint
733706f2543SmrgWriteToClient (ClientPtr who, int count, const void *__buf)
734706f2543Smrg{
735706f2543Smrg    OsCommPtr oc;
736706f2543Smrg    ConnectionOutputPtr oco;
737706f2543Smrg    int padBytes;
738706f2543Smrg    const char *buf = __buf;
739706f2543Smrg#ifdef DEBUG_COMMUNICATION
740706f2543Smrg    Bool multicount = FALSE;
741706f2543Smrg#endif
742706f2543Smrg    if (!count || !who || who == serverClient || who->clientGone)
743706f2543Smrg	return 0;
744706f2543Smrg    oc = who->osPrivate;
745706f2543Smrg    oco = oc->output;
746706f2543Smrg#ifdef DEBUG_COMMUNICATION
747706f2543Smrg    {
748706f2543Smrg	char info[128];
749706f2543Smrg	xError *err;
750706f2543Smrg	xGenericReply *rep;
751706f2543Smrg	xEvent *ev;
752706f2543Smrg
753706f2543Smrg	if (!who->replyBytesRemaining) {
754706f2543Smrg	    switch(buf[0]) {
755706f2543Smrg	    case X_Reply:
756706f2543Smrg		rep = (xGenericReply*)buf;
757706f2543Smrg		if (rep->sequenceNumber == who->sequence) {
758706f2543Smrg		    snprintf(info,127,"Xreply: type: 0x%x data: 0x%x "
759706f2543Smrg			     "len: %i seq#: 0x%x", rep->type, rep->data1,
760706f2543Smrg			     rep->length, rep->sequenceNumber);
761706f2543Smrg		    multicount = TRUE;
762706f2543Smrg		}
763706f2543Smrg		break;
764706f2543Smrg	    case X_Error:
765706f2543Smrg		err = (xError*)buf;
766706f2543Smrg		snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
767706f2543Smrg			 "min: %x", err->errorCode,err->resourceID,
768706f2543Smrg			 err->minorCode,err->majorCode);
769706f2543Smrg		break;
770706f2543Smrg	    default:
771706f2543Smrg		if ((buf[0] & 0x7f) == KeymapNotify)
772706f2543Smrg		    snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]);
773706f2543Smrg		else {
774706f2543Smrg		    ev = (xEvent*)buf;
775706f2543Smrg		    snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x "
776706f2543Smrg			     "seq#: 0x%x",  ev->u.u.type, ev->u.u.detail,
777706f2543Smrg			     ev->u.u.sequenceNumber);
778706f2543Smrg		}
779706f2543Smrg	    }
780706f2543Smrg	    ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info);
781706f2543Smrg	} else
782706f2543Smrg	    multicount = TRUE;
783706f2543Smrg    }
784706f2543Smrg#endif
785706f2543Smrg
786706f2543Smrg    if (!oco)
787706f2543Smrg    {
788706f2543Smrg	if ((oco = FreeOutputs))
789706f2543Smrg	{
790706f2543Smrg	    FreeOutputs = oco->next;
791706f2543Smrg	}
792706f2543Smrg	else if (!(oco = AllocateOutputBuffer()))
793706f2543Smrg	{
794706f2543Smrg	    if (oc->trans_conn) {
795706f2543Smrg		_XSERVTransDisconnect(oc->trans_conn);
796706f2543Smrg		_XSERVTransClose(oc->trans_conn);
797706f2543Smrg		oc->trans_conn = NULL;
798706f2543Smrg	    }
799706f2543Smrg	    MarkClientException(who);
800706f2543Smrg	    return -1;
801706f2543Smrg	}
802706f2543Smrg	oc->output = oco;
803706f2543Smrg    }
804706f2543Smrg
805706f2543Smrg    padBytes = padlength[count & 3];
806706f2543Smrg
807706f2543Smrg    if(ReplyCallback)
808706f2543Smrg    {
809706f2543Smrg        ReplyInfoRec replyinfo;
810706f2543Smrg
811706f2543Smrg	replyinfo.client = who;
812706f2543Smrg	replyinfo.replyData = buf;
813706f2543Smrg	replyinfo.dataLenBytes = count + padBytes;
814706f2543Smrg	if (who->replyBytesRemaining)
815706f2543Smrg	{ /* still sending data of an earlier reply */
816706f2543Smrg	    who->replyBytesRemaining -= count + padBytes;
817706f2543Smrg	    replyinfo.startOfReply = FALSE;
818706f2543Smrg	    replyinfo.bytesRemaining = who->replyBytesRemaining;
819706f2543Smrg	    CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
820706f2543Smrg	}
821706f2543Smrg	else if (who->clientState == ClientStateRunning
822706f2543Smrg		 && buf[0] == X_Reply)
823706f2543Smrg        { /* start of new reply */
824706f2543Smrg	    CARD32 replylen;
825706f2543Smrg	    unsigned long bytesleft;
826706f2543Smrg	    char n;
827706f2543Smrg
828706f2543Smrg	    replylen = ((xGenericReply *)buf)->length;
829706f2543Smrg	    if (who->swapped)
830706f2543Smrg		swapl(&replylen, n);
831706f2543Smrg	    bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
832706f2543Smrg	    replyinfo.startOfReply = TRUE;
833706f2543Smrg	    replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
834706f2543Smrg	    CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
835706f2543Smrg	}
836706f2543Smrg    }
837706f2543Smrg#ifdef DEBUG_COMMUNICATION
838706f2543Smrg    else if (multicount) {
839706f2543Smrg	if (who->replyBytesRemaining) {
840706f2543Smrg	    who->replyBytesRemaining -= (count + padBytes);
841706f2543Smrg	} else {
842706f2543Smrg	    CARD32 replylen;
843706f2543Smrg	    replylen = ((xGenericReply *)buf)->length;
844706f2543Smrg	    who->replyBytesRemaining =
845706f2543Smrg		(replylen * 4) + SIZEOF(xReply) - count - padBytes;
846706f2543Smrg	}
847706f2543Smrg    }
848706f2543Smrg#endif
849706f2543Smrg    if (oco->count + count + padBytes > oco->size)
850706f2543Smrg    {
851706f2543Smrg	FD_CLR(oc->fd, &OutputPending);
852706f2543Smrg	if(!XFD_ANYSET(&OutputPending)) {
853706f2543Smrg	  CriticalOutputPending = FALSE;
854706f2543Smrg	  NewOutputPending = FALSE;
855706f2543Smrg	}
856706f2543Smrg
857706f2543Smrg	if (FlushCallback)
858706f2543Smrg	    CallCallbacks(&FlushCallback, NULL);
859706f2543Smrg
860706f2543Smrg	return FlushClient(who, oc, buf, count);
861706f2543Smrg    }
862706f2543Smrg
863706f2543Smrg    NewOutputPending = TRUE;
864706f2543Smrg    FD_SET(oc->fd, &OutputPending);
865706f2543Smrg    memmove((char *)oco->buf + oco->count, buf, count);
866706f2543Smrg    oco->count += count + padBytes;
867706f2543Smrg    return count;
868706f2543Smrg}
869706f2543Smrg
870706f2543Smrg /********************
871706f2543Smrg * FlushClient()
872706f2543Smrg *    If the client isn't keeping up with us, then we try to continue
873706f2543Smrg *    buffering the data and set the apropriate bit in ClientsWritable
874706f2543Smrg *    (which is used by WaitFor in the select).  If the connection yields
875706f2543Smrg *    a permanent error, or we can't allocate any more space, we then
876706f2543Smrg *    close the connection.
877706f2543Smrg *
878706f2543Smrg **********************/
879706f2543Smrg
880706f2543Smrgint
881706f2543SmrgFlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
882706f2543Smrg{
883706f2543Smrg    ConnectionOutputPtr oco = oc->output;
884706f2543Smrg    int connection = oc->fd;
885706f2543Smrg    XtransConnInfo trans_conn = oc->trans_conn;
886706f2543Smrg    struct iovec iov[3];
887706f2543Smrg    static char padBuffer[3];
888706f2543Smrg    const char *extraBuf = __extraBuf;
889706f2543Smrg    long written;
890706f2543Smrg    long padsize;
891706f2543Smrg    long notWritten;
892706f2543Smrg    long todo;
893706f2543Smrg
894706f2543Smrg    if (!oco)
895706f2543Smrg	return 0;
896706f2543Smrg    written = 0;
897706f2543Smrg    padsize = padlength[extraCount & 3];
898706f2543Smrg    notWritten = oco->count + extraCount + padsize;
899706f2543Smrg    todo = notWritten;
900706f2543Smrg    while (notWritten) {
901706f2543Smrg	long before = written;	/* amount of whole thing written */
902706f2543Smrg	long remain = todo;	/* amount to try this time, <= notWritten */
903706f2543Smrg	int i = 0;
904706f2543Smrg	long len;
905706f2543Smrg
906706f2543Smrg	/* You could be very general here and have "in" and "out" iovecs
907706f2543Smrg	 * and write a loop without using a macro, but what the heck.  This
908706f2543Smrg	 * translates to:
909706f2543Smrg	 *
910706f2543Smrg	 *     how much of this piece is new?
911706f2543Smrg	 *     if more new then we are trying this time, clamp
912706f2543Smrg	 *     if nothing new
913706f2543Smrg	 *         then bump down amount already written, for next piece
914706f2543Smrg	 *         else put new stuff in iovec, will need all of next piece
915706f2543Smrg	 *
916706f2543Smrg	 * Note that todo had better be at least 1 or else we'll end up
917706f2543Smrg	 * writing 0 iovecs.
918706f2543Smrg	 */
919706f2543Smrg#define InsertIOV(pointer, length) \
920706f2543Smrg	len = (length) - before; \
921706f2543Smrg	if (len > remain) \
922706f2543Smrg	    len = remain; \
923706f2543Smrg	if (len <= 0) { \
924706f2543Smrg	    before = (-len); \
925706f2543Smrg	} else { \
926706f2543Smrg	    iov[i].iov_len = len; \
927706f2543Smrg	    iov[i].iov_base = (pointer) + before;	\
928706f2543Smrg	    i++; \
929706f2543Smrg	    remain -= len; \
930706f2543Smrg	    before = 0; \
931706f2543Smrg	}
932706f2543Smrg
933706f2543Smrg	InsertIOV ((char *)oco->buf, oco->count)
934706f2543Smrg	InsertIOV ((char *)extraBuf, extraCount)
935706f2543Smrg	InsertIOV (padBuffer, padsize)
936706f2543Smrg
937706f2543Smrg	errno = 0;
938706f2543Smrg	if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
939706f2543Smrg	{
940706f2543Smrg	    written += len;
941706f2543Smrg	    notWritten -= len;
942706f2543Smrg	    todo = notWritten;
943706f2543Smrg	}
944706f2543Smrg	else if (ETEST(errno)
945706f2543Smrg#ifdef SUNSYSV /* check for another brain-damaged OS bug */
946706f2543Smrg		 || (errno == 0)
947706f2543Smrg#endif
948706f2543Smrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
949706f2543Smrg		 || ((errno == EMSGSIZE) && (todo == 1))
950706f2543Smrg#endif
951706f2543Smrg		)
952706f2543Smrg	{
953706f2543Smrg	    /* If we've arrived here, then the client is stuffed to the gills
954706f2543Smrg	       and not ready to accept more.  Make a note of it and buffer
955706f2543Smrg	       the rest. */
956706f2543Smrg	    FD_SET(connection, &ClientsWriteBlocked);
957706f2543Smrg	    AnyClientsWriteBlocked = TRUE;
958706f2543Smrg
959706f2543Smrg	    if (written < oco->count)
960706f2543Smrg	    {
961706f2543Smrg		if (written > 0)
962706f2543Smrg		{
963706f2543Smrg		    oco->count -= written;
964706f2543Smrg		    memmove((char *)oco->buf,
965706f2543Smrg			    (char *)oco->buf + written,
966706f2543Smrg			  oco->count);
967706f2543Smrg		    written = 0;
968706f2543Smrg		}
969706f2543Smrg	    }
970706f2543Smrg	    else
971706f2543Smrg	    {
972706f2543Smrg		written -= oco->count;
973706f2543Smrg		oco->count = 0;
974706f2543Smrg	    }
975706f2543Smrg
976706f2543Smrg	    if (notWritten > oco->size)
977706f2543Smrg	    {
978706f2543Smrg		unsigned char *obuf;
979706f2543Smrg
980706f2543Smrg		obuf = (unsigned char *)realloc(oco->buf,
981706f2543Smrg						 notWritten + BUFSIZE);
982706f2543Smrg		if (!obuf)
983706f2543Smrg		{
984706f2543Smrg		    _XSERVTransDisconnect(oc->trans_conn);
985706f2543Smrg		    _XSERVTransClose(oc->trans_conn);
986706f2543Smrg		    oc->trans_conn = NULL;
987706f2543Smrg		    MarkClientException(who);
988706f2543Smrg		    oco->count = 0;
989706f2543Smrg		    return -1;
990706f2543Smrg		}
991706f2543Smrg		oco->size = notWritten + BUFSIZE;
992706f2543Smrg		oco->buf = obuf;
993706f2543Smrg	    }
994706f2543Smrg
995706f2543Smrg	    /* If the amount written extended into the padBuffer, then the
996706f2543Smrg	       difference "extraCount - written" may be less than 0 */
997706f2543Smrg	    if ((len = extraCount - written) > 0)
998706f2543Smrg		memmove ((char *)oco->buf + oco->count,
999706f2543Smrg			 extraBuf + written,
1000706f2543Smrg		       len);
1001706f2543Smrg
1002706f2543Smrg	    oco->count = notWritten; /* this will include the pad */
1003706f2543Smrg	    /* return only the amount explicitly requested */
1004706f2543Smrg	    return extraCount;
1005706f2543Smrg	}
1006706f2543Smrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
1007706f2543Smrg	else if (errno == EMSGSIZE)
1008706f2543Smrg	{
1009706f2543Smrg	    todo >>= 1;
1010706f2543Smrg	}
1011706f2543Smrg#endif
1012706f2543Smrg	else
1013706f2543Smrg	{
1014706f2543Smrg	    if (oc->trans_conn)
1015706f2543Smrg	    {
1016706f2543Smrg		_XSERVTransDisconnect(oc->trans_conn);
1017706f2543Smrg		_XSERVTransClose(oc->trans_conn);
1018706f2543Smrg		oc->trans_conn = NULL;
1019706f2543Smrg	    }
1020706f2543Smrg	    MarkClientException(who);
1021706f2543Smrg	    oco->count = 0;
1022706f2543Smrg	    return -1;
1023706f2543Smrg	}
1024706f2543Smrg    }
1025706f2543Smrg
1026706f2543Smrg    /* everything was flushed out */
1027706f2543Smrg    oco->count = 0;
1028706f2543Smrg    /* check to see if this client was write blocked */
1029706f2543Smrg    if (AnyClientsWriteBlocked)
1030706f2543Smrg    {
1031706f2543Smrg	FD_CLR(oc->fd, &ClientsWriteBlocked);
1032706f2543Smrg 	if (! XFD_ANYSET(&ClientsWriteBlocked))
1033706f2543Smrg	    AnyClientsWriteBlocked = FALSE;
1034706f2543Smrg    }
1035706f2543Smrg    if (oco->size > BUFWATERMARK)
1036706f2543Smrg    {
1037706f2543Smrg	free(oco->buf);
1038706f2543Smrg	free(oco);
1039706f2543Smrg    }
1040706f2543Smrg    else
1041706f2543Smrg    {
1042706f2543Smrg	oco->next = FreeOutputs;
1043706f2543Smrg	FreeOutputs = oco;
1044706f2543Smrg    }
1045706f2543Smrg    oc->output = (ConnectionOutputPtr)NULL;
1046706f2543Smrg    return extraCount; /* return only the amount explicitly requested */
1047706f2543Smrg}
1048706f2543Smrg
1049706f2543Smrgstatic ConnectionInputPtr
1050706f2543SmrgAllocateInputBuffer(void)
1051706f2543Smrg{
1052706f2543Smrg    ConnectionInputPtr oci;
1053706f2543Smrg
1054706f2543Smrg    oci = malloc(sizeof(ConnectionInput));
1055706f2543Smrg    if (!oci)
1056706f2543Smrg	return NULL;
1057706f2543Smrg    oci->buffer = malloc(BUFSIZE);
1058706f2543Smrg    if (!oci->buffer)
1059706f2543Smrg    {
1060706f2543Smrg	free(oci);
1061706f2543Smrg	return NULL;
1062706f2543Smrg    }
1063706f2543Smrg    oci->size = BUFSIZE;
1064706f2543Smrg    oci->bufptr = oci->buffer;
1065706f2543Smrg    oci->bufcnt = 0;
1066706f2543Smrg    oci->lenLastReq = 0;
1067706f2543Smrg    oci->ignoreBytes = 0;
1068706f2543Smrg    return oci;
1069706f2543Smrg}
1070706f2543Smrg
1071706f2543Smrgstatic ConnectionOutputPtr
1072706f2543SmrgAllocateOutputBuffer(void)
1073706f2543Smrg{
1074706f2543Smrg    ConnectionOutputPtr oco;
1075706f2543Smrg
1076706f2543Smrg    oco = malloc(sizeof(ConnectionOutput));
1077706f2543Smrg    if (!oco)
1078706f2543Smrg	return NULL;
1079706f2543Smrg    oco->buf = calloc(1, BUFSIZE);
1080706f2543Smrg    if (!oco->buf)
1081706f2543Smrg    {
1082706f2543Smrg	free(oco);
1083706f2543Smrg	return NULL;
1084706f2543Smrg    }
1085706f2543Smrg    oco->size = BUFSIZE;
1086706f2543Smrg    oco->count = 0;
1087706f2543Smrg    return oco;
1088706f2543Smrg}
1089706f2543Smrg
1090706f2543Smrgvoid
1091706f2543SmrgFreeOsBuffers(OsCommPtr oc)
1092706f2543Smrg{
1093706f2543Smrg    ConnectionInputPtr oci;
1094706f2543Smrg    ConnectionOutputPtr oco;
1095706f2543Smrg
1096706f2543Smrg    if (AvailableInput == oc)
1097706f2543Smrg	AvailableInput = (OsCommPtr)NULL;
1098706f2543Smrg    if ((oci = oc->input))
1099706f2543Smrg    {
1100706f2543Smrg	if (FreeInputs)
1101706f2543Smrg	{
1102706f2543Smrg	    free(oci->buffer);
1103706f2543Smrg	    free(oci);
1104706f2543Smrg	}
1105706f2543Smrg	else
1106706f2543Smrg	{
1107706f2543Smrg	    FreeInputs = oci;
1108706f2543Smrg	    oci->next = (ConnectionInputPtr)NULL;
1109706f2543Smrg	    oci->bufptr = oci->buffer;
1110706f2543Smrg	    oci->bufcnt = 0;
1111706f2543Smrg	    oci->lenLastReq = 0;
1112706f2543Smrg	}
1113706f2543Smrg    }
1114706f2543Smrg    if ((oco = oc->output))
1115706f2543Smrg    {
1116706f2543Smrg	if (FreeOutputs)
1117706f2543Smrg	{
1118706f2543Smrg	    free(oco->buf);
1119706f2543Smrg	    free(oco);
1120706f2543Smrg	}
1121706f2543Smrg	else
1122706f2543Smrg	{
1123706f2543Smrg	    FreeOutputs = oco;
1124706f2543Smrg	    oco->next = (ConnectionOutputPtr)NULL;
1125706f2543Smrg	    oco->count = 0;
1126706f2543Smrg	}
1127706f2543Smrg    }
1128706f2543Smrg}
1129706f2543Smrg
1130706f2543Smrgvoid
1131706f2543SmrgResetOsBuffers(void)
1132706f2543Smrg{
1133706f2543Smrg    ConnectionInputPtr oci;
1134706f2543Smrg    ConnectionOutputPtr oco;
1135706f2543Smrg
1136706f2543Smrg    while ((oci = FreeInputs))
1137706f2543Smrg    {
1138706f2543Smrg	FreeInputs = oci->next;
1139706f2543Smrg	free(oci->buffer);
1140706f2543Smrg	free(oci);
1141706f2543Smrg    }
1142706f2543Smrg    while ((oco = FreeOutputs))
1143706f2543Smrg    {
1144706f2543Smrg	FreeOutputs = oco->next;
1145706f2543Smrg	free(oco->buf);
1146706f2543Smrg	free(oco);
1147706f2543Smrg    }
1148706f2543Smrg}
1149