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