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