io.c revision 30e1ba2c
1bbe1b32bSmrg/*
2bbe1b32bSmrg * i/o functions
3bbe1b32bSmrg */
4bbe1b32bSmrg/*
5bbe1b32bSmrg
6bbe1b32bSmrgCopyright 1990, 1991, 1998  The Open Group
7bbe1b32bSmrg
8bbe1b32bSmrgPermission to use, copy, modify, distribute, and sell this software and its
9bbe1b32bSmrgdocumentation for any purpose is hereby granted without fee, provided that
10bbe1b32bSmrgthe above copyright notice appear in all copies and that both that
11bbe1b32bSmrgcopyright notice and this permission notice appear in supporting
12bbe1b32bSmrgdocumentation.
13bbe1b32bSmrg
14bbe1b32bSmrgThe above copyright notice and this permission notice shall be included in
15bbe1b32bSmrgall copies or substantial portions of the Software.
16bbe1b32bSmrg
17bbe1b32bSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18bbe1b32bSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bbe1b32bSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20bbe1b32bSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21bbe1b32bSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22bbe1b32bSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23bbe1b32bSmrg
24bbe1b32bSmrgExcept as contained in this notice, the name of The Open Group shall not be
25bbe1b32bSmrgused in advertising or otherwise to promote the sale, use or other dealings
26bbe1b32bSmrgin this Software without prior written authorization from The Open Group.
27bbe1b32bSmrg
28bbe1b32bSmrg * Copyright 1990, 1991 Network Computing Devices;
29bbe1b32bSmrg * Portions Copyright 1987 by Digital Equipment Corporation
30bbe1b32bSmrg *
31bbe1b32bSmrg * Permission to use, copy, modify, distribute, and sell this software and
32bbe1b32bSmrg * its documentation for any purpose is hereby granted without fee, provided
33bbe1b32bSmrg * that the above copyright notice appear in all copies and that both that
34bbe1b32bSmrg * copyright notice and this permission notice appear in supporting
35bbe1b32bSmrg * documentation, and that the names of Network Computing Devices, or Digital
36bbe1b32bSmrg * not be used in advertising or publicity pertaining to distribution
37bbe1b32bSmrg * of the software without specific, written prior permission.
38bbe1b32bSmrg *
39bbe1b32bSmrg * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
40bbe1b32bSmrg * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
41bbe1b32bSmrg * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
42bbe1b32bSmrg * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
43bbe1b32bSmrg * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44bbe1b32bSmrg * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45bbe1b32bSmrg * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
46bbe1b32bSmrg * THIS SOFTWARE.
47bbe1b32bSmrg */
48ce6676dbSmrg
49f30dc278Smrg#include	"X11/Xpoll.h"
50f30dc278Smrg
5134f90d55Smrg#include	"config.h"
52bbe1b32bSmrg
5330e1ba2cSmrg/* include Xpoll.h early for possible FD_SETSIZE re-definition */
5430e1ba2cSmrg#include	"X11/Xpoll.h"
5530e1ba2cSmrg
56bbe1b32bSmrg#include	<X11/Xtrans/Xtrans.h>
57bbe1b32bSmrg#include	<stdio.h>
58bbe1b32bSmrg#include	<errno.h>
59bbe1b32bSmrg#include	<sys/types.h>
60bbe1b32bSmrg#include	<sys/param.h>
61bbe1b32bSmrg#include	<sys/uio.h>
62bbe1b32bSmrg
63bbe1b32bSmrg#include	<X11/fonts/FSproto.h>
64bbe1b32bSmrg#include	"clientstr.h"
65bbe1b32bSmrg#include	"osdep.h"
66bbe1b32bSmrg#include	"globals.h"
67bbe1b32bSmrg#include	"dispatch.h"
68bbe1b32bSmrg
69bbe1b32bSmrg
70bbe1b32bSmrg/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
71bbe1b32bSmrg * systems are broken and return EWOULDBLOCK when they should return EAGAIN
72bbe1b32bSmrg  */
73bbe1b32bSmrg
74bbe1b32bSmrg#if defined(EAGAIN) && defined(EWOULDBLOCK)
75bbe1b32bSmrg#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
76bbe1b32bSmrg#else
77bbe1b32bSmrg
78bbe1b32bSmrg#ifdef EAGAIN
79bbe1b32bSmrg#define ETEST(err) (err == EAGAIN)
80bbe1b32bSmrg#else
81bbe1b32bSmrg#define ETEST(err) (err == EWOULDBLOCK)
82bbe1b32bSmrg#endif
83bbe1b32bSmrg
84bbe1b32bSmrg#endif
85bbe1b32bSmrg
86bbe1b32bSmrgstatic int  timesThisConnection = 0;
87bbe1b32bSmrgstatic ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL;
88bbe1b32bSmrgstatic ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL;
89bbe1b32bSmrgstatic OsCommPtr AvailableInput = (OsCommPtr) NULL;
90bbe1b32bSmrg
9130f8ce46Smrgextern int xfd_ffs(fd_mask);
92bbe1b32bSmrgstatic ConnectionInputPtr AllocateInputBuffer(void);
93bbe1b32bSmrgstatic ConnectionOutputPtr AllocateOutputBuffer(void);
94bbe1b32bSmrg
95bbe1b32bSmrg
96bbe1b32bSmrg#define		MAX_TIMES_PER	10
97bbe1b32bSmrg
98bbe1b32bSmrg#define	yield_control()				\
99bbe1b32bSmrg	{ isItTimeToYield = TRUE;		\
100bbe1b32bSmrg	  timesThisConnection = 0; }
101bbe1b32bSmrg
102bbe1b32bSmrg#define	yield_control_no_input()		\
103bbe1b32bSmrg	{ yield_control();			\
104bbe1b32bSmrg	  FD_CLR(fd, &ClientsWithInput); }
105bbe1b32bSmrg
106bbe1b32bSmrg#define	yield_control_death()			\
107bbe1b32bSmrg	{ timesThisConnection = 0; }
108bbe1b32bSmrg
109bbe1b32bSmrg#define	request_length(req, client)		\
110bbe1b32bSmrg	((int)((client)->swapped ? lswaps((req)->length) : (req)->length) << 2)
111bbe1b32bSmrg
112bbe1b32bSmrgint
113bbe1b32bSmrgReadRequest(ClientPtr client)
114bbe1b32bSmrg{
115bbe1b32bSmrg    OsCommPtr   oc;
116bbe1b32bSmrg    ConnectionInputPtr oci;
117bbe1b32bSmrg    fsReq      *request;
118bbe1b32bSmrg    int         fd,
119bbe1b32bSmrg                result,
120bbe1b32bSmrg                gotnow,
121bbe1b32bSmrg                needed = 0;
122bbe1b32bSmrg
123bbe1b32bSmrg    if (client == NULL)
124bbe1b32bSmrg	return -1;
125bbe1b32bSmrg    oc = (OsCommPtr) client->osPrivate;
126bbe1b32bSmrg    if (oc == NULL)
127bbe1b32bSmrg	return -1;
128bbe1b32bSmrg    oci = oc->input;
129bbe1b32bSmrg    fd = oc->fd;
130bbe1b32bSmrg    if (oci != NULL && fd < 0)
131bbe1b32bSmrg	return -1;
132bbe1b32bSmrg
133bbe1b32bSmrg    if (AvailableInput) {
134bbe1b32bSmrg	if (AvailableInput != oc) {
135bbe1b32bSmrg	    ConnectionInputPtr aci = AvailableInput->input;
136bbe1b32bSmrg
137bbe1b32bSmrg	    if (aci->size > BUFWATERMARK) {
138bbe1b32bSmrg		fsfree(aci->buffer);
139bbe1b32bSmrg		fsfree(aci);
140bbe1b32bSmrg	    } else {
141bbe1b32bSmrg		aci->next = FreeInputs;
142bbe1b32bSmrg		FreeInputs = aci;
143bbe1b32bSmrg	    }
144bbe1b32bSmrg	    AvailableInput->input = (ConnectionInputPtr) NULL;
145bbe1b32bSmrg	}
146bbe1b32bSmrg	AvailableInput = (OsCommPtr) NULL;
147bbe1b32bSmrg    }
148bbe1b32bSmrg    if (!oci) {
149bbe1b32bSmrg	if ((oci = FreeInputs ) != (ConnectionInputPtr) 0) {
150bbe1b32bSmrg	    FreeInputs = oci->next;
151bbe1b32bSmrg	} else if (!(oci = AllocateInputBuffer())) {
152bbe1b32bSmrg	    yield_control_death();
153bbe1b32bSmrg	    return -1;
154bbe1b32bSmrg	}
155bbe1b32bSmrg	oc->input = oci;
156bbe1b32bSmrg    }
157bbe1b32bSmrg    oci->bufptr += oci->lenLastReq;
158bbe1b32bSmrg
159bbe1b32bSmrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
160bbe1b32bSmrg    request = (fsReq *) oci->bufptr;
161bbe1b32bSmrg
162bbe1b32bSmrg    /* not enough for a request */
163bbe1b32bSmrg    if ((gotnow < SIZEOF(fsReq)) ||
164bbe1b32bSmrg	    (gotnow < (needed = request_length(request, client)))) {
165bbe1b32bSmrg	oci->lenLastReq = 0;
166bbe1b32bSmrg	if ((gotnow < SIZEOF(fsReq)) || needed == 0)
167bbe1b32bSmrg	    needed = SIZEOF(fsReq);
168bbe1b32bSmrg	else if (needed > MAXBUFSIZE) {
169bbe1b32bSmrg	    yield_control_death();
170bbe1b32bSmrg	    return -1;
171bbe1b32bSmrg	}
172bbe1b32bSmrg	/* see if we need to shift up a partial request so the rest can fit */
173bbe1b32bSmrg	if ((gotnow == 0) ||
174bbe1b32bSmrg	    ((oci->bufptr - oci->buffer + needed) > oci->size))
175bbe1b32bSmrg	{
176bbe1b32bSmrg	    if ((gotnow > 0) && (oci->bufptr != oci->buffer))
177bbe1b32bSmrg		memmove( oci->buffer, oci->bufptr, gotnow);
178bbe1b32bSmrg	    /* grow buffer if necessary */
179bbe1b32bSmrg	    if (needed > oci->size) {
180bbe1b32bSmrg		char       *ibuf;
181bbe1b32bSmrg
182bbe1b32bSmrg		ibuf = (char *) fsrealloc(oci->buffer, needed);
183bbe1b32bSmrg		if (!ibuf) {
184bbe1b32bSmrg		    yield_control_death();
185bbe1b32bSmrg		    return -1;
186bbe1b32bSmrg		}
187bbe1b32bSmrg		oci->size = needed;
188bbe1b32bSmrg		oci->buffer = ibuf;
189bbe1b32bSmrg	    }
190bbe1b32bSmrg	    oci->bufptr = oci->buffer;
191bbe1b32bSmrg	    oci->bufcnt = gotnow;
192bbe1b32bSmrg	}
193bbe1b32bSmrg	/* fill 'er up */
194bbe1b32bSmrg	if (oc->trans_conn == NULL) {
195bbe1b32bSmrg	    yield_control_death();
196bbe1b32bSmrg	    return -1;
197bbe1b32bSmrg	}
198bbe1b32bSmrg	result = _FontTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
199bbe1b32bSmrg		      oci->size - oci->bufcnt);
200bbe1b32bSmrg	if (result <= 0) {
201bbe1b32bSmrg#if !(defined(SVR4) && defined(i386) && !defined(sun))
202bbe1b32bSmrg	    if ((result < 0) && ETEST(errno)) {
203bbe1b32bSmrg		yield_control_no_input();
204bbe1b32bSmrg		return 0;
205bbe1b32bSmrg	    } else
206bbe1b32bSmrg#endif
207bbe1b32bSmrg	    {
208bbe1b32bSmrg
209bbe1b32bSmrg		yield_control_death();
210bbe1b32bSmrg		return -1;
211bbe1b32bSmrg	    }
212bbe1b32bSmrg	}
213bbe1b32bSmrg	oci->bufcnt += result;
214bbe1b32bSmrg	gotnow += result;
215bbe1b32bSmrg
216bbe1b32bSmrg	/* free up space after huge requests */
217bbe1b32bSmrg	if ((oci->size > BUFWATERMARK) &&
218bbe1b32bSmrg		(oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) {
219bbe1b32bSmrg	    char       *ibuf;
220bbe1b32bSmrg
221bbe1b32bSmrg	    ibuf = (char *) fsrealloc(oci->buffer, BUFSIZE);
222bbe1b32bSmrg	    if (ibuf) {
223bbe1b32bSmrg		oci->size = BUFSIZE;
224bbe1b32bSmrg		oci->buffer = ibuf;
225bbe1b32bSmrg		oci->bufptr = ibuf + oci->bufcnt - gotnow;
226bbe1b32bSmrg	    }
227bbe1b32bSmrg	}
228bbe1b32bSmrg	request = (fsReq *) oci->bufptr;
229bbe1b32bSmrg	if ((gotnow < SIZEOF(fsReq)) ||
230bbe1b32bSmrg	    (gotnow < (needed = request_length(request, client)))) {
231bbe1b32bSmrg	    yield_control_no_input();
232bbe1b32bSmrg	    return 0;
233bbe1b32bSmrg	}
234bbe1b32bSmrg    }
235bbe1b32bSmrg    if (needed == 0)
236bbe1b32bSmrg	needed = SIZEOF(fsReq);
237bbe1b32bSmrg    oci->lenLastReq = needed;
238bbe1b32bSmrg    /*
239bbe1b32bSmrg     * Check to see if client has at least one whole request in the buffer. If
240bbe1b32bSmrg     * there is only a partial request, treat like buffer is empty so that
241bbe1b32bSmrg     * select() will be called again and other clients can get into the queue.
242bbe1b32bSmrg     */
243bbe1b32bSmrg
244bbe1b32bSmrg    if (gotnow >= needed + SIZEOF(fsReq)) {
245bbe1b32bSmrg	request = (fsReq *) (oci->bufptr + needed);
246bbe1b32bSmrg	if (gotnow >= needed + request_length(request, client))
247bbe1b32bSmrg	    FD_SET(fd, &ClientsWithInput);
248bbe1b32bSmrg	else
249bbe1b32bSmrg	    yield_control_no_input();
250bbe1b32bSmrg    } else {
251bbe1b32bSmrg	if (gotnow == needed)
252bbe1b32bSmrg	    AvailableInput = oc;
253bbe1b32bSmrg	yield_control_no_input();
254bbe1b32bSmrg    }
255bbe1b32bSmrg
256bbe1b32bSmrg    if (++timesThisConnection >= MAX_TIMES_PER)
257bbe1b32bSmrg	yield_control();
258bbe1b32bSmrg
259bbe1b32bSmrg    client->requestBuffer = (pointer) oci->bufptr;
260bbe1b32bSmrg    return needed;
261bbe1b32bSmrg}
262bbe1b32bSmrg
263bbe1b32bSmrgBool
264bbe1b32bSmrgInsertFakeRequest(ClientPtr client, char *data, int count)
265bbe1b32bSmrg{
266bbe1b32bSmrg    OsCommPtr   oc = (OsCommPtr) client->osPrivate;
267bbe1b32bSmrg    ConnectionInputPtr oci = oc->input;
268bbe1b32bSmrg    int         fd = oc->fd;
269bbe1b32bSmrg    fsReq      *request;
270bbe1b32bSmrg    int         gotnow,
271bbe1b32bSmrg                moveup;
272bbe1b32bSmrg
273bbe1b32bSmrg    if (AvailableInput) {
274bbe1b32bSmrg	if (AvailableInput != oc) {
275bbe1b32bSmrg	    register ConnectionInputPtr aci = AvailableInput->input;
276bbe1b32bSmrg
277bbe1b32bSmrg	    if (aci->size > BUFWATERMARK) {
278bbe1b32bSmrg		fsfree(aci->buffer);
279bbe1b32bSmrg		fsfree(aci);
280bbe1b32bSmrg	    } else {
281bbe1b32bSmrg		aci->next = FreeInputs;
282bbe1b32bSmrg		FreeInputs = aci;
283bbe1b32bSmrg	    }
284bbe1b32bSmrg	    AvailableInput->input = (ConnectionInputPtr) NULL;
285bbe1b32bSmrg	}
286bbe1b32bSmrg	AvailableInput = (OsCommPtr) NULL;
287bbe1b32bSmrg    }
288bbe1b32bSmrg    if (!oci) {
289bbe1b32bSmrg	if ((oci = FreeInputs) != (ConnectionInputPtr) 0)
290bbe1b32bSmrg	    FreeInputs = oci->next;
291bbe1b32bSmrg	else if (!(oci = AllocateInputBuffer()))
292bbe1b32bSmrg	    return FALSE;
293bbe1b32bSmrg	oc->input = oci;
294bbe1b32bSmrg
295bbe1b32bSmrg    }
296bbe1b32bSmrg    oci->bufptr += oci->lenLastReq;
297bbe1b32bSmrg    oci->lenLastReq = 0;
298bbe1b32bSmrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
299bbe1b32bSmrg    if ((gotnow + count) > oci->size) {
300bbe1b32bSmrg	char       *ibuf;
301bbe1b32bSmrg
302bbe1b32bSmrg	ibuf = (char *) fsrealloc(oci->buffer, gotnow + count);
303bbe1b32bSmrg	if (!ibuf)
304bbe1b32bSmrg	    return FALSE;
305bbe1b32bSmrg	oci->size = gotnow + count;
306bbe1b32bSmrg	oci->buffer = ibuf;
307bbe1b32bSmrg	oci->bufptr = ibuf + oci->bufcnt - gotnow;
308bbe1b32bSmrg    }
309bbe1b32bSmrg    moveup = count - (oci->bufptr - oci->buffer);
310bbe1b32bSmrg    if (moveup > 0) {
311bbe1b32bSmrg	if (gotnow > 0)
312bbe1b32bSmrg	    memmove( oci->bufptr + moveup, oci->bufptr, gotnow);
313bbe1b32bSmrg	oci->bufptr += moveup;
314bbe1b32bSmrg	oci->bufcnt += moveup;
315bbe1b32bSmrg    }
316bbe1b32bSmrg    memmove( oci->bufptr - count, data, count);
317bbe1b32bSmrg    oci->bufptr -= count;
318bbe1b32bSmrg    request = (fsReq *) oci->bufptr;
319bbe1b32bSmrg    gotnow += count;
320bbe1b32bSmrg    if ((gotnow >= SIZEOF(fsReq)) &&
321bbe1b32bSmrg	    (gotnow >= request_length(request, client)))
322bbe1b32bSmrg	FD_SET(fd, &ClientsWithInput);
323bbe1b32bSmrg    else
324bbe1b32bSmrg	yield_control_no_input();
325bbe1b32bSmrg    return TRUE;
326bbe1b32bSmrg}
327bbe1b32bSmrg
328bbe1b32bSmrgvoid
329bbe1b32bSmrgResetCurrentRequest(ClientPtr client)
330bbe1b32bSmrg{
331bbe1b32bSmrg    OsCommPtr   oc = (OsCommPtr) client->osPrivate;
332bbe1b32bSmrg    ConnectionInputPtr oci = oc->input;
333bbe1b32bSmrg    int         fd = oc->fd;
334bbe1b32bSmrg    fsReq      *request;
335bbe1b32bSmrg    int         gotnow;
336bbe1b32bSmrg
337bbe1b32bSmrg    if (AvailableInput == oc)
338bbe1b32bSmrg	AvailableInput = (OsCommPtr) NULL;
339bbe1b32bSmrg    oci->lenLastReq = 0;
340bbe1b32bSmrg    request = (fsReq *) oci->bufptr;
341bbe1b32bSmrg    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
342bbe1b32bSmrg    if ((gotnow >= SIZEOF(fsReq)) &&
343bbe1b32bSmrg	    (gotnow >= request_length(request, client))) {
344bbe1b32bSmrg	FD_SET(fd, &ClientsWithInput);
345bbe1b32bSmrg	yield_control();
346bbe1b32bSmrg    } else {
347bbe1b32bSmrg	yield_control_no_input();
348bbe1b32bSmrg    }
349bbe1b32bSmrg}
350bbe1b32bSmrg
351bbe1b32bSmrgint
352bbe1b32bSmrgFlushClient(
353bbe1b32bSmrg    ClientPtr   client,
354bbe1b32bSmrg    OsCommPtr   oc,
355bbe1b32bSmrg    char       *extraBuf,
356bbe1b32bSmrg    int         extraCount,
357bbe1b32bSmrg    int         padsize)
358bbe1b32bSmrg{
359bbe1b32bSmrg    ConnectionOutputPtr oco = oc->output;
360bbe1b32bSmrg    int         fd = oc->fd;
361bbe1b32bSmrg    struct iovec iov[3];
362bbe1b32bSmrg    char        padBuffer[3];
363bbe1b32bSmrg    long        written;
364bbe1b32bSmrg    long        notWritten;
365bbe1b32bSmrg    long        todo;
366bbe1b32bSmrg
367bbe1b32bSmrg    if (!oco)
368bbe1b32bSmrg	return 0;
369bbe1b32bSmrg    written = 0;
370bbe1b32bSmrg    notWritten = oco->count + extraCount + padsize;
371bbe1b32bSmrg    todo = notWritten;
372bbe1b32bSmrg    while (notWritten) {
373bbe1b32bSmrg	long        before = written;
374bbe1b32bSmrg	long        remain = todo;
375bbe1b32bSmrg	int         i = 0;
376bbe1b32bSmrg	long        len;
377bbe1b32bSmrg
378bbe1b32bSmrg	/*-
379bbe1b32bSmrg	 * You could be very general here and have "in" and "out" iovecs and
380bbe1b32bSmrg	 * write a loop without using a macro, but what the heck.  This
381bbe1b32bSmrg	 * translates to:
382bbe1b32bSmrg	 *
383bbe1b32bSmrg	 * 	how much of this piece is new?
384bbe1b32bSmrg	 *	if more new then we are trying this time, clamp
385bbe1b32bSmrg	 *	if nothing new
386bbe1b32bSmrg	 *	    then bump down amount already written, for next piece
387bbe1b32bSmrg	 *	    else put new stuff in iovec, will need all of next piece
388bbe1b32bSmrg	 *
389bbe1b32bSmrg	 * Note that todo had better be at least 1 or else we'll end up
390bbe1b32bSmrg	 * writing 0 iovecs.
391bbe1b32bSmrg	 */
392bbe1b32bSmrg
393bbe1b32bSmrg#define	InsertIOV(pointer, length)	\
394bbe1b32bSmrg	len = (length) - before;	\
395bbe1b32bSmrg	if (len > remain)		\
396bbe1b32bSmrg	    len = remain;		\
397bbe1b32bSmrg	if (len <= 0) {			\
398bbe1b32bSmrg	    before = (-len);		\
399bbe1b32bSmrg	} else {			\
400bbe1b32bSmrg	    iov[i].iov_len = len;	\
401bbe1b32bSmrg	    iov[i].iov_base = (pointer) + before; \
402bbe1b32bSmrg	    i++;			\
403bbe1b32bSmrg	    remain -= len;		\
404bbe1b32bSmrg	    before = 0;			\
405bbe1b32bSmrg	}
406bbe1b32bSmrg
407bbe1b32bSmrg	InsertIOV((char *) oco->buf, oco->count);
408bbe1b32bSmrg	InsertIOV(extraBuf, extraCount);
409bbe1b32bSmrg	InsertIOV(padBuffer, padsize);
410bbe1b32bSmrg
411bbe1b32bSmrg	errno = 0;
412bbe1b32bSmrg	if (oc->trans_conn && (len = _FontTransWritev(oc->trans_conn, iov, i)) >= 0) {
413bbe1b32bSmrg	    written += len;
414bbe1b32bSmrg	    notWritten -= len;
415bbe1b32bSmrg	    todo = notWritten;
416bbe1b32bSmrg	} else if (ETEST(errno)
417bbe1b32bSmrg#ifdef SUNSYSV /* check for another brain-damaged OS bug */
418bbe1b32bSmrg		 || (errno == 0)
419bbe1b32bSmrg#endif
420bbe1b32bSmrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
421bbe1b32bSmrg		 || ((errno == EMSGSIZE) && (todo == 1))
422bbe1b32bSmrg#endif
423bbe1b32bSmrg		)
424bbe1b32bSmrg	{
425bbe1b32bSmrg	    FD_SET(fd, &ClientsWriteBlocked);
426bbe1b32bSmrg	    AnyClientsWriteBlocked = TRUE;
427bbe1b32bSmrg
428bbe1b32bSmrg	    if (written < oco->count) {
429bbe1b32bSmrg		if (written > 0) {
430bbe1b32bSmrg		    oco->count -= written;
431bbe1b32bSmrg		    memmove( (char *) oco->buf, (char *) oco->buf + written,
432bbe1b32bSmrg			    oco->count);
433bbe1b32bSmrg		    written = 0;
434bbe1b32bSmrg		}
435bbe1b32bSmrg	    } else {
436bbe1b32bSmrg		written -= oco->count;
437bbe1b32bSmrg		oco->count = 0;
438bbe1b32bSmrg	    }
439bbe1b32bSmrg
440bbe1b32bSmrg	    /* grow buffer if necessary */
441bbe1b32bSmrg	    if (notWritten > oco->size) {
442bbe1b32bSmrg		unsigned char *obuf;
443bbe1b32bSmrg
444bbe1b32bSmrg		obuf = (unsigned char *) fsrealloc(oco->buf,
445bbe1b32bSmrg					      notWritten + OutputBufferSize);
446bbe1b32bSmrg		if (!obuf) {
447bbe1b32bSmrg		    if (oc->trans_conn)
448bbe1b32bSmrg			_FontTransClose(oc->trans_conn);
449bbe1b32bSmrg		    oc->trans_conn = NULL;
450bbe1b32bSmrg		    MarkClientException(client);
451bbe1b32bSmrg		    oco->count = 0;
452bbe1b32bSmrg		    return -1;
453bbe1b32bSmrg		}
454bbe1b32bSmrg		oco->size = notWritten + OutputBufferSize;
455bbe1b32bSmrg		oco->buf = obuf;
456bbe1b32bSmrg	    }
457bbe1b32bSmrg	    if ((len = extraCount - written) > 0) {
458bbe1b32bSmrg		memmove( (char *) oco->buf + oco->count,
459bbe1b32bSmrg			extraBuf + written, len);
460bbe1b32bSmrg	    }
461bbe1b32bSmrg	    oco->count = notWritten;
462bbe1b32bSmrg	    return extraCount;
463bbe1b32bSmrg	}
464bbe1b32bSmrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
465bbe1b32bSmrg	else if (errno == EMSGSIZE)
466bbe1b32bSmrg	{
467bbe1b32bSmrg	    todo >>= 1;
468bbe1b32bSmrg	}
469bbe1b32bSmrg#endif
470bbe1b32bSmrg	else
471bbe1b32bSmrg	{
472bbe1b32bSmrg	    if (oc->trans_conn)
473bbe1b32bSmrg	        _FontTransClose(oc->trans_conn);
474bbe1b32bSmrg	    oc->trans_conn = NULL;
475bbe1b32bSmrg	    MarkClientException(client);
476bbe1b32bSmrg	    oco->count = 0;
477bbe1b32bSmrg	    return -1;
478bbe1b32bSmrg	}
479bbe1b32bSmrg    }
480bbe1b32bSmrg
481bbe1b32bSmrg    /* everything was flushed */
482bbe1b32bSmrg    oco->count = 0;
483bbe1b32bSmrg
484bbe1b32bSmrg    /* clear the write block if it was set */
485bbe1b32bSmrg    if (AnyClientsWriteBlocked) {
486bbe1b32bSmrg	FD_CLR(fd, &ClientsWriteBlocked);
487bbe1b32bSmrg	if (!XFD_ANYSET(&ClientsWriteBlocked))
488bbe1b32bSmrg	    AnyClientsWriteBlocked = FALSE;
489bbe1b32bSmrg    }
490bbe1b32bSmrg    if (oco->size > BUFWATERMARK) {
491bbe1b32bSmrg	fsfree(oco->buf);
492bbe1b32bSmrg	fsfree(oco);
493bbe1b32bSmrg    } else {
494bbe1b32bSmrg	oco->next = FreeOutputs;
495bbe1b32bSmrg	FreeOutputs = oco;
496bbe1b32bSmrg    }
497bbe1b32bSmrg    oc->output = (ConnectionOutputPtr) NULL;
498bbe1b32bSmrg
499bbe1b32bSmrg    return extraCount;
500bbe1b32bSmrg}
501bbe1b32bSmrg
502bbe1b32bSmrgvoid
503bbe1b32bSmrgFlushAllOutput(void)
504bbe1b32bSmrg{
505bbe1b32bSmrg    int         index, base;
506bbe1b32bSmrg    fd_mask	mask;
507bbe1b32bSmrg    OsCommPtr   oc;
508bbe1b32bSmrg    ClientPtr   client;
509bbe1b32bSmrg
510bbe1b32bSmrg    if (!NewOutputPending)
511bbe1b32bSmrg	return;
512bbe1b32bSmrg
513bbe1b32bSmrg    NewOutputPending = FALSE;
514bbe1b32bSmrg
515bbe1b32bSmrg    for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) {
516bbe1b32bSmrg	mask = OutputPending.fds_bits[base];
517bbe1b32bSmrg	OutputPending.fds_bits[base] = 0;
518bbe1b32bSmrg	while (mask) {
51930f8ce46Smrg	    index = xfd_ffs(mask) - 1;
520bbe1b32bSmrg	    mask &= ~lowbit(mask);
52130f8ce46Smrg	    if ((index = ConnectionTranslation[(base * (sizeof(fd_mask) * 8)) + index]) == 0)
522bbe1b32bSmrg		continue;
523bbe1b32bSmrg	    client = clients[index];
524bbe1b32bSmrg	    if (client->clientGone == CLIENT_GONE)
525bbe1b32bSmrg		continue;
526bbe1b32bSmrg	    oc = (OsCommPtr) client->osPrivate;
527bbe1b32bSmrg	    if (FD_ISSET(oc->fd, &ClientsWithInput)) {
528bbe1b32bSmrg		FD_SET(oc->fd, &OutputPending);
529bbe1b32bSmrg		NewOutputPending = TRUE;
530bbe1b32bSmrg	    } else {
531bbe1b32bSmrg		(void) FlushClient(client, oc, (char *) NULL, 0, 0);
532bbe1b32bSmrg	    }
533bbe1b32bSmrg	}
534bbe1b32bSmrg    }
535bbe1b32bSmrg}
536bbe1b32bSmrg
537bbe1b32bSmrg/*
538bbe1b32bSmrg * returns number of bytes written
539bbe1b32bSmrg */
540bbe1b32bSmrgstatic int
541bbe1b32bSmrgwrite_to_client_internal(ClientPtr client, int count, char *buf, int padBytes)
542bbe1b32bSmrg{
543bbe1b32bSmrg    OsCommPtr   oc = (OsCommPtr) client->osPrivate;
544bbe1b32bSmrg    ConnectionOutputPtr oco = oc->output;
545bbe1b32bSmrg
546bbe1b32bSmrg    if (!count)
547bbe1b32bSmrg	return 0;
548bbe1b32bSmrg
549bbe1b32bSmrg    if (!oco) {
550bbe1b32bSmrg	if ((oco = FreeOutputs) != (ConnectionOutputPtr) 0) {
551bbe1b32bSmrg	    FreeOutputs = oco->next;
552bbe1b32bSmrg	} else if (!(oco = AllocateOutputBuffer())) {
553bbe1b32bSmrg	    _FontTransClose(oc->trans_conn);
554bbe1b32bSmrg	    oc->trans_conn = NULL;
555bbe1b32bSmrg	    MarkClientException(client);
556bbe1b32bSmrg	    return -1;
557bbe1b32bSmrg	}
558bbe1b32bSmrg	oc->output = oco;
559bbe1b32bSmrg    }
560bbe1b32bSmrg    if (oco->count + count + padBytes > oco->size) {
561bbe1b32bSmrg	FD_CLR(oc->fd, &OutputPending);
562bbe1b32bSmrg	NewOutputPending = FALSE;
563bbe1b32bSmrg	return FlushClient(client, oc, buf, count, padBytes);
564bbe1b32bSmrg    }
565bbe1b32bSmrg    NewOutputPending = TRUE;
566bbe1b32bSmrg    FD_SET(oc->fd, &OutputPending);
567bbe1b32bSmrg    memmove( (char *) oco->buf + oco->count, buf, count);
568bbe1b32bSmrg    oco->count += count + padBytes;
569bbe1b32bSmrg
570bbe1b32bSmrg    return count;
571bbe1b32bSmrg}
572bbe1b32bSmrg
573bbe1b32bSmrgvoid
574bbe1b32bSmrgWriteToClientUnpadded(ClientPtr client, int count, char *buf)
575bbe1b32bSmrg{
576bbe1b32bSmrg    write_to_client_internal(client, count, buf, 0);
577bbe1b32bSmrg}
578bbe1b32bSmrg
579bbe1b32bSmrgstatic int  padlength[4] = {0, 3, 2, 1};
580bbe1b32bSmrg
581bbe1b32bSmrgvoid
582bbe1b32bSmrgWriteToClient(ClientPtr client, int count, char *buf)
583bbe1b32bSmrg{
584bbe1b32bSmrg    int flag = 0;
585bbe1b32bSmrg    if (NULL == buf) {
586bbe1b32bSmrg	flag = -1;
587bbe1b32bSmrg	buf = (char *)fsalloc(count); memset(buf, 0, count);
588bbe1b32bSmrg    }
589bbe1b32bSmrg     write_to_client_internal(client, count, buf, padlength[count & 3]);
590bbe1b32bSmrg    if (flag)
591bbe1b32bSmrg	fsfree(buf);
592bbe1b32bSmrg}
593bbe1b32bSmrg
594bbe1b32bSmrgstatic ConnectionInputPtr
595bbe1b32bSmrgAllocateInputBuffer(void)
596bbe1b32bSmrg{
597bbe1b32bSmrg    register ConnectionInputPtr oci;
598bbe1b32bSmrg
599bbe1b32bSmrg    oci = (ConnectionInputPtr) fsalloc(sizeof(ConnectionInput));
600bbe1b32bSmrg    if (!oci)
601bbe1b32bSmrg	return (ConnectionInputPtr) NULL;
602bbe1b32bSmrg    oci->buffer = (char *) fsalloc(BUFSIZE);
603bbe1b32bSmrg    if (!oci->buffer) {
604bbe1b32bSmrg	fsfree(oci);
605bbe1b32bSmrg	return (ConnectionInputPtr) NULL;
606bbe1b32bSmrg    }
607ce6676dbSmrg    oci->next = NULL;
608bbe1b32bSmrg    oci->size = BUFSIZE;
609bbe1b32bSmrg    oci->bufptr = oci->buffer;
610bbe1b32bSmrg    oci->bufcnt = 0;
611bbe1b32bSmrg    oci->lenLastReq = 0;
612bbe1b32bSmrg    return oci;
613bbe1b32bSmrg}
614bbe1b32bSmrg
615bbe1b32bSmrgstatic ConnectionOutputPtr
616bbe1b32bSmrgAllocateOutputBuffer(void)
617bbe1b32bSmrg{
618bbe1b32bSmrg    register ConnectionOutputPtr oco;
619bbe1b32bSmrg
620bbe1b32bSmrg    oco = (ConnectionOutputPtr) fsalloc(sizeof(ConnectionOutput));
621bbe1b32bSmrg    if (!oco)
622bbe1b32bSmrg	return (ConnectionOutputPtr) NULL;
623bbe1b32bSmrg    oco->buf = (unsigned char *) fsalloc(BUFSIZE);
624bbe1b32bSmrg    if (!oco->buf) {
625bbe1b32bSmrg	fsfree(oco);
626bbe1b32bSmrg	return (ConnectionOutputPtr) NULL;
627bbe1b32bSmrg    }
628bbe1b32bSmrg    oco->size = BUFSIZE;
629bbe1b32bSmrg    oco->count = 0;
630bbe1b32bSmrg    return oco;
631bbe1b32bSmrg}
632bbe1b32bSmrg
633bbe1b32bSmrg
634bbe1b32bSmrgvoid
635bbe1b32bSmrgFreeOsBuffers(OsCommPtr oc)
636bbe1b32bSmrg{
637bbe1b32bSmrg    register ConnectionInputPtr oci;
638bbe1b32bSmrg    register ConnectionOutputPtr oco;
639bbe1b32bSmrg
640bbe1b32bSmrg    if (AvailableInput == oc)
641bbe1b32bSmrg	AvailableInput = (OsCommPtr) NULL;
642bbe1b32bSmrg    if ((oci = oc->input) != (ConnectionInputPtr) 0) {
643bbe1b32bSmrg	if (FreeInputs) {
644bbe1b32bSmrg	    fsfree(oci->buffer);
645bbe1b32bSmrg	    fsfree(oci);
646bbe1b32bSmrg	} else {
647bbe1b32bSmrg	    FreeInputs = oci;
648bbe1b32bSmrg	    oci->next = (ConnectionInputPtr) NULL;
649bbe1b32bSmrg	    oci->bufptr = oci->buffer;
650bbe1b32bSmrg	    oci->bufcnt = 0;
651bbe1b32bSmrg	    oci->lenLastReq = 0;
652bbe1b32bSmrg	}
653bbe1b32bSmrg    }
654bbe1b32bSmrg    if ((oco = oc->output) != (ConnectionOutputPtr) 0) {
655bbe1b32bSmrg	if (FreeOutputs) {
656bbe1b32bSmrg	    fsfree(oco->buf);
657bbe1b32bSmrg	    fsfree(oco);
658bbe1b32bSmrg	} else {
659bbe1b32bSmrg	    FreeOutputs = oco;
660bbe1b32bSmrg	    oco->next = (ConnectionOutputPtr) NULL;
661bbe1b32bSmrg	    oco->count = 0;
662bbe1b32bSmrg	}
663bbe1b32bSmrg    }
664bbe1b32bSmrg}
665bbe1b32bSmrg
666bbe1b32bSmrgvoid
667bbe1b32bSmrgResetOsBuffers(void)
668bbe1b32bSmrg{
669bbe1b32bSmrg    register ConnectionInputPtr oci;
670bbe1b32bSmrg    register ConnectionOutputPtr oco;
671bbe1b32bSmrg
672bbe1b32bSmrg    while ((oci = FreeInputs) != (ConnectionInputPtr) 0) {
673bbe1b32bSmrg	FreeInputs = oci->next;
674bbe1b32bSmrg	fsfree(oci->buffer);
675bbe1b32bSmrg	fsfree(oci);
676bbe1b32bSmrg    }
677bbe1b32bSmrg    while ((oco = FreeOutputs) != (ConnectionOutputPtr) 0) {
678bbe1b32bSmrg	FreeOutputs = oco->next;
679bbe1b32bSmrg	fsfree(oco->buf);
680bbe1b32bSmrg	fsfree(oco);
681bbe1b32bSmrg    }
682bbe1b32bSmrg}
683