fsio.c revision 41c30155
1/*
2 * Copyright 1990 Network Computing Devices
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Network Computing Devices not be
9 * used in advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.  Network Computing
11 * Devices makes no representations about the suitability of this software
12 * for any purpose.  It is provided "as is" without express or implied
13 * warranty.
14 *
15 * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
17 * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
18 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
19 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
20 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
21 * OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author:  	Dave Lemke, Network Computing Devices, Inc
24 */
25/*
26 * font server i/o routines
27 */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32
33#ifdef WIN32
34#define _WILLWINSOCK_
35#include	"X11/Xwindows.h"
36#endif
37
38#define FONT_t
39#define TRANS_CLIENT
40#include 	"X11/Xtrans/Xtrans.h"
41#include	"X11/Xpoll.h"
42#include	<X11/fonts/FS.h>
43#include	<X11/fonts/FSproto.h>
44#include	<X11/fonts/fontmisc.h>
45#include	<X11/fonts/fontstruct.h>
46#include	"fservestr.h"
47
48#include	<stdio.h>
49#include	<signal.h>
50#include	<sys/types.h>
51#if !defined(WIN32)
52#ifndef Lynx
53#include	<sys/socket.h>
54#else
55#include	<socket.h>
56#endif
57#endif
58#include	<errno.h>
59#ifdef WIN32
60#define EWOULDBLOCK WSAEWOULDBLOCK
61#undef EINTR
62#define EINTR WSAEINTR
63#endif
64
65
66
67static int  padlength[4] = {0, 3, 2, 1};
68fd_set _fs_fd_mask;
69
70static int
71_fs_resize (FSBufPtr buf, long size);
72
73static void
74_fs_downsize (FSBufPtr buf, long size);
75
76int
77_fs_poll_connect (XtransConnInfo trans_conn, int timeout)
78{
79    fd_set	    w_mask;
80    struct timeval  tv;
81    int		    fs_fd = _FontTransGetConnectionNumber (trans_conn);
82    int		    ret;
83
84    do
85    {
86	tv.tv_usec = 0;
87	tv.tv_sec = timeout;
88	FD_ZERO (&w_mask);
89	FD_SET (fs_fd, &w_mask);
90	ret = Select (fs_fd + 1, NULL, &w_mask, NULL, &tv);
91    } while (ret < 0 && ECHECK(EINTR));
92    if (ret == 0)
93	return FSIO_BLOCK;
94    if (ret < 0)
95	return FSIO_ERROR;
96    return FSIO_READY;
97}
98
99XtransConnInfo
100_fs_connect(char *servername, int *err)
101{
102    XtransConnInfo  trans_conn;		/* transport connection object */
103    int		    ret;
104    int		    i = 0;
105    int		    retries = 5;
106
107    /*
108     * Open the network connection.
109     */
110    if( (trans_conn=_FontTransOpenCOTSClient(servername)) == NULL )
111    {
112	*err = FSIO_ERROR;
113	return 0;
114    }
115
116    /*
117     * Set the connection non-blocking since we use select() to block.
118     */
119
120    _FontTransSetOption(trans_conn, TRANS_NONBLOCKING, 1);
121
122    do {
123	i = _FontTransConnect(trans_conn,servername);
124    } while ((i == TRANS_TRY_CONNECT_AGAIN) && (retries-- > 0));
125
126    if (i < 0)
127    {
128	if (i == TRANS_IN_PROGRESS)
129	    ret = FSIO_BLOCK;
130	else
131	    ret = FSIO_ERROR;
132    }
133    else
134	ret = FSIO_READY;
135
136    if (ret == FSIO_ERROR)
137    {
138	_FontTransClose(trans_conn);
139	trans_conn = 0;
140    }
141
142    *err = ret;
143    return trans_conn;
144}
145
146static int
147_fs_fill (FSFpePtr conn)
148{
149    long    avail;
150    long    bytes_read;
151    Bool    waited = FALSE;
152
153    if (_fs_flush (conn) < 0)
154	return FSIO_ERROR;
155    /*
156     * Don't go overboard here; stop reading when we've
157     * got enough to satisfy the pending request
158     */
159    while ((conn->inNeed - (conn->inBuf.insert - conn->inBuf.remove)) > 0)
160    {
161	avail = conn->inBuf.size - conn->inBuf.insert;
162	/*
163	 * For SVR4 with a unix-domain connection, ETEST() after selecting
164	 * readable means the server has died.  To do this here, we look for
165	 * two consecutive reads returning ETEST().
166	 */
167	ESET (0);
168	bytes_read =_FontTransRead(conn->trans_conn,
169				   conn->inBuf.buf + conn->inBuf.insert,
170				   avail);
171	if (bytes_read > 0) {
172	    conn->inBuf.insert += bytes_read;
173	    waited = FALSE;
174	}
175	else
176	{
177	    if (bytes_read == 0 || ETEST ())
178	    {
179		if (!waited)
180		{
181		    waited = TRUE;
182		    if (_fs_wait_for_readable (conn, 0) == FSIO_BLOCK)
183			return FSIO_BLOCK;
184		    continue;
185		}
186	    }
187	    _fs_connection_died (conn);
188	    return FSIO_ERROR;
189	}
190    }
191    return FSIO_READY;
192}
193
194/*
195 * Make space and return whether data have already arrived
196 */
197
198int
199_fs_start_read (FSFpePtr conn, long size, char **buf)
200{
201    int	    ret;
202
203    conn->inNeed = size;
204    if (fs_inqueued(conn) < size)
205    {
206	if (_fs_resize (&conn->inBuf, size) != FSIO_READY)
207	{
208	    _fs_connection_died (conn);
209	    return FSIO_ERROR;
210	}
211	ret = _fs_fill (conn);
212	if (ret == FSIO_ERROR)
213	    return ret;
214	if (ret == FSIO_BLOCK || fs_inqueued(conn) < size)
215	    return FSIO_BLOCK;
216    }
217    if (buf)
218	*buf = conn->inBuf.buf + conn->inBuf.remove;
219    return FSIO_READY;
220}
221
222void
223_fs_done_read (FSFpePtr conn, long size)
224{
225    if (conn->inBuf.insert - conn->inBuf.remove < size)
226    {
227#ifdef DEBUG
228	fprintf (stderr, "_fs_done_read skipping to many bytes\n");
229#endif
230	return;
231    }
232    conn->inBuf.remove += size;
233    conn->inNeed -= size;
234    _fs_downsize (&conn->inBuf, FS_BUF_MAX);
235}
236
237long
238_fs_pad_length (long len)
239{
240    return len + padlength[len&3];
241}
242
243int
244_fs_flush (FSFpePtr conn)
245{
246    long    bytes_written;
247    long    remain;
248
249    /* XXX - hack.  The right fix is to remember that the font server
250       has gone away when we first discovered it. */
251    if (conn->fs_fd < 0)
252	return FSIO_ERROR;
253
254    while ((remain = conn->outBuf.insert - conn->outBuf.remove) > 0)
255    {
256	bytes_written = _FontTransWrite(conn->trans_conn,
257					conn->outBuf.buf + conn->outBuf.remove,
258					(int) remain);
259	if (bytes_written > 0)
260	{
261	    conn->outBuf.remove += bytes_written;
262	}
263	else
264	{
265	    if (bytes_written == 0 || ETEST ())
266	    {
267		conn->brokenWriteTime = GetTimeInMillis () + FS_FLUSH_POLL;
268		_fs_mark_block (conn, FS_BROKEN_WRITE);
269		break;
270	    }
271	    if (!ECHECK (EINTR))
272	    {
273		_fs_connection_died (conn);
274		return FSIO_ERROR;
275	    }
276	}
277    }
278    if (conn->outBuf.remove == conn->outBuf.insert)
279    {
280	_fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE);
281	if (conn->outBuf.size > FS_BUF_INC)
282	    conn->outBuf.buf = realloc (conn->outBuf.buf, FS_BUF_INC);
283	conn->outBuf.remove = conn->outBuf.insert = 0;
284    }
285    return FSIO_READY;
286}
287
288static int
289_fs_resize (FSBufPtr buf, long size)
290{
291    char    *new;
292    long    new_size;
293
294    if (buf->remove)
295    {
296	if (buf->remove != buf->insert)
297	{
298	    memmove (buf->buf,
299		     buf->buf + buf->remove,
300		     buf->insert - buf->remove);
301	}
302	buf->insert -= buf->remove;
303	buf->remove = 0;
304    }
305    if (buf->size - buf->remove < size)
306    {
307	new_size = ((buf->remove + size + FS_BUF_INC) / FS_BUF_INC) * FS_BUF_INC;
308	new = realloc (buf->buf, new_size);
309	if (!new)
310	    return FSIO_ERROR;
311	buf->buf = new;
312	buf->size = new_size;
313    }
314    return FSIO_READY;
315}
316
317static void
318_fs_downsize (FSBufPtr buf, long size)
319{
320    if (buf->insert == buf->remove)
321    {
322	buf->insert = buf->remove = 0;
323	if (buf->size > size)
324	{
325	    buf->buf = realloc (buf->buf, size);
326	    buf->size = size;
327	}
328    }
329}
330
331void
332_fs_io_reinit (FSFpePtr conn)
333{
334    conn->outBuf.insert = conn->outBuf.remove = 0;
335    _fs_downsize (&conn->outBuf, FS_BUF_INC);
336    conn->inBuf.insert = conn->inBuf.remove = 0;
337    _fs_downsize (&conn->inBuf, FS_BUF_MAX);
338}
339
340Bool
341_fs_io_init (FSFpePtr conn)
342{
343    conn->outBuf.insert = conn->outBuf.remove = 0;
344    conn->outBuf.buf = malloc (FS_BUF_INC);
345    if (!conn->outBuf.buf)
346	return FALSE;
347    conn->outBuf.size = FS_BUF_INC;
348
349    conn->inBuf.insert = conn->inBuf.remove = 0;
350    conn->inBuf.buf = malloc (FS_BUF_INC);
351    if (!conn->inBuf.buf)
352    {
353	free (conn->outBuf.buf);
354	conn->outBuf.buf = 0;
355	return FALSE;
356    }
357    conn->inBuf.size = FS_BUF_INC;
358
359    return TRUE;
360}
361
362void
363_fs_io_fini (FSFpePtr conn)
364{
365    if (conn->outBuf.buf)
366	free (conn->outBuf.buf);
367    if (conn->inBuf.buf)
368	free (conn->inBuf.buf);
369}
370
371static int
372_fs_do_write(FSFpePtr conn, const char *data, long len, long size)
373{
374    if (size == 0) {
375#ifdef DEBUG
376	fprintf(stderr, "tried to write 0 bytes \n");
377#endif
378	return FSIO_READY;
379    }
380
381    if (conn->fs_fd == -1)
382	return FSIO_ERROR;
383
384    while (conn->outBuf.insert + size > conn->outBuf.size)
385    {
386	if (_fs_flush (conn) < 0)
387	    return FSIO_ERROR;
388	if (_fs_resize (&conn->outBuf, size) < 0)
389	{
390	    _fs_connection_died (conn);
391	    return FSIO_ERROR;
392	}
393    }
394    memcpy (conn->outBuf.buf + conn->outBuf.insert, data, len);
395    /* Clear pad data */
396    memset (conn->outBuf.buf + conn->outBuf.insert + len, 0, size - len);
397    conn->outBuf.insert += size;
398    _fs_mark_block (conn, FS_PENDING_WRITE);
399    return FSIO_READY;
400}
401
402/*
403 * Write the indicated bytes
404 */
405int
406_fs_write (FSFpePtr conn, const char *data, long len)
407{
408    return _fs_do_write (conn, data, len, len);
409}
410
411/*
412 * Write the indicated bytes adding any appropriate pad
413 */
414int
415_fs_write_pad(FSFpePtr conn, const char *data, long len)
416{
417    return _fs_do_write (conn, data, len, len + padlength[len & 3]);
418}
419
420int
421_fs_wait_for_readable(FSFpePtr conn, int ms)
422{
423    fd_set	r_mask;
424    fd_set	e_mask;
425    int         result;
426    struct timeval  tv;
427
428    for (;;) {
429	if (conn->fs_fd < 0)
430	    return FSIO_ERROR;
431	FD_ZERO(&r_mask);
432	FD_ZERO(&e_mask);
433	tv.tv_sec = ms / 1000;
434	tv.tv_usec = (ms % 1000) * 1000;
435	FD_SET(conn->fs_fd, &r_mask);
436	FD_SET(conn->fs_fd, &e_mask);
437	result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, &tv);
438	if (result < 0)
439	{
440	    if (ECHECK(EINTR) || ECHECK(EAGAIN))
441		continue;
442	    else
443		return FSIO_ERROR;
444	}
445	if (result == 0)
446	    return FSIO_BLOCK;
447	if (FD_ISSET(conn->fs_fd, &r_mask))
448	    return FSIO_READY;
449	return FSIO_ERROR;
450    }
451}
452