1 /* $XConsortium: fsio.c,v 1.37 95/04/05 19:58:13 kaleb Exp $ */
2 /* $XFree86: xc/lib/font/fc/fsio.c,v 3.5.2.1 1998/02/15 16:08:40 hohndel Exp $ */
3 /*
4  * Copyright 1990 Network Computing Devices
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Network Computing Devices not be
11  * used in advertising or publicity pertaining to distribution of the
12  * software without specific, written prior permission.  Network Computing
13  * Devices makes no representations about the suitability of this software
14  * for any purpose.  It is provided "as is" without express or implied
15  * warranty.
16  *
17  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
19  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
20  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
23  * OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  * Author:  	Dave Lemke, Network Computing Devices, Inc
26  */
27 /*
28  * font server i/o routines
29  */
30 
31 #ifdef WIN32
32 #define _WILLWINSOCK_
33 #endif
34 
35 #include	"FS.h"
36 #include	"FSproto.h"
37 
38 #include 	"X11/Xtrans.h"
39 #include	"X11/Xpoll.h"
40 #include	"fontmisc.h"
41 #include	"fsio.h"
42 
43 #include	<stdio.h>
44 #include	<signal.h>
45 #include	<sys/types.h>
46 #if !defined(WIN32) && !defined(AMOEBA) && !defined(_MINIX)
47 #ifndef Lynx
48 #include	<sys/socket.h>
49 #else
50 #include	<socket.h>
51 #endif
52 #endif
53 #include	<errno.h>
54 #ifdef X_NOT_STDC_ENV
55 extern int errno;
56 #endif
57 #ifdef WIN32
58 #define EWOULDBLOCK WSAEWOULDBLOCK
59 #undef EINTR
60 #define EINTR WSAEINTR
61 #endif
62 
63 #ifdef MINIX
64 #include <sys/nbio.h>
65 #define select(n,r,w,x,t) nbio_select(n,r,w,x,t)
66 #endif
67 
68 #ifdef __EMX__
69 #define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t)
70 #endif
71 
72 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
73  * systems are broken and return EWOULDBLOCK when they should return EAGAIN
74  */
75 #ifdef WIN32
76 #define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
77 #else
78 #if defined(EAGAIN) && defined(EWOULDBLOCK)
79 #define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
80 #else
81 #ifdef EAGAIN
82 #define ETEST() (errno == EAGAIN)
83 #else
84 #define ETEST() (errno == EWOULDBLOCK)
85 #endif
86 #endif
87 #endif
88 #ifdef WIN32
89 #define ECHECK(err) (WSAGetLastError() == err)
90 #define ESET(val) WSASetLastError(val)
91 #else
92 #ifdef ISC
93 #define ECHECK(err) ((errno == err) || ETEST())
94 #else
95 #define ECHECK(err) (errno == err)
96 #endif
97 #define ESET(val) errno = val
98 #endif
99 
100 static int  padlength[4] = {0, 3, 2, 1};
101 fd_set _fs_fd_mask;
102 
103 int  _fs_wait_for_readable();
104 
105 #ifdef SIGNALRETURNSINT
106 #define SIGNAL_T int
107 #else
108 #define SIGNAL_T void
109 #endif
110 
111 /* ARGSUSED */
112 static      SIGNAL_T
_fs_alarm(foo)113 _fs_alarm(foo)
114     int         foo;
115 {
116     return;
117 }
118 
119 static XtransConnInfo
_fs_connect(servername,timeout)120 _fs_connect(servername, timeout)
121     char       *servername;
122     int         timeout;
123 {
124     XtransConnInfo trans_conn;		/* transport connection object */
125     int         ret = -1;
126 #ifdef SIGALRM
127     unsigned    oldTime;
128 
129     SIGNAL_T(*oldAlarm) ();
130 #endif
131 
132     /*
133      * Open the network connection.
134      */
135     if( (trans_conn=_FontTransOpenCOTSClient(servername)) == NULL )
136 	{
137 	return (NULL);
138 	}
139 
140 #ifdef SIGALRM
141     oldTime = alarm((unsigned) 0);
142     oldAlarm = signal(SIGALRM, _fs_alarm);
143     alarm((unsigned) timeout);
144 #endif
145 
146     ret = _FontTransConnect(trans_conn,servername);
147 
148 #ifdef SIGALRM
149     alarm((unsigned) 0);
150     signal(SIGALRM, oldAlarm);
151     alarm(oldTime);
152 #endif
153 
154     if (ret < 0)
155 	{
156 	_FontTransClose(trans_conn);
157 	return (NULL);
158 	}
159 
160     /*
161      * Set the connection non-blocking since we use select() to block.
162      */
163 
164     _FontTransSetOption(trans_conn, TRANS_NONBLOCKING, 1);
165 
166     return trans_conn;
167 }
168 
169 static int  generationCount;
170 
171 /* ARGSUSED */
172 static Bool
_fs_setup_connection(conn,servername,timeout,copy_name_p)173 _fs_setup_connection(conn, servername, timeout, copy_name_p)
174     FSFpePtr    conn;
175     char       *servername;
176     int         timeout;
177     Bool	copy_name_p;
178 {
179     fsConnClientPrefix prefix;
180     fsConnSetup rep;
181     int         setuplength;
182     fsConnSetupAccept conn_accept;
183     int         endian;
184     int         i;
185     int         alt_len;
186     char       *auth_data = NULL,
187                *vendor_string = NULL,
188                *alt_data = NULL,
189                *alt_dst;
190     FSFpeAltPtr alts;
191     int         nalts;
192 
193     if ((conn->trans_conn = _fs_connect(servername, 5)) == NULL)
194 	return FALSE;
195 
196     conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
197 
198     conn->generation = ++generationCount;
199 
200     /* send setup prefix */
201     endian = 1;
202     if (*(char *) &endian)
203 	prefix.byteOrder = 'l';
204     else
205 	prefix.byteOrder = 'B';
206 
207     prefix.major_version = FS_PROTOCOL;
208     prefix.minor_version = FS_PROTOCOL_MINOR;
209 
210 /* XXX add some auth info here */
211     prefix.num_auths = 0;
212     prefix.auth_len = 0;
213 
214     if (_fs_write(conn, (char *) &prefix, SIZEOF(fsConnClientPrefix)) == -1)
215 	return FALSE;
216 
217     /* read setup info */
218     if (_fs_read(conn, (char *) &rep, SIZEOF(fsConnSetup)) == -1)
219 	return FALSE;
220 
221     conn->fsMajorVersion = rep.major_version;
222     if (rep.major_version > FS_PROTOCOL)
223 	return FALSE;
224 
225     alts = 0;
226     /* parse alternate list */
227     if (nalts = rep.num_alternates) {
228 	setuplength = rep.alternate_len << 2;
229 	alts = (FSFpeAltPtr) xalloc(nalts * sizeof(FSFpeAltRec) +
230 				    setuplength);
231 	if (!alts) {
232 	    _FontTransClose(conn->trans_conn);
233 	    errno = ENOMEM;
234 	    return FALSE;
235 	}
236 	alt_data = (char *) (alts + nalts);
237 	if (_fs_read(conn, (char *) alt_data, setuplength) == -1) {
238 	    xfree(alts);
239 	    return FALSE;
240 	}
241 	alt_dst = alt_data;
242 	for (i = 0; i < nalts; i++) {
243 	    alts[i].subset = alt_data[0];
244 	    alt_len = alt_data[1];
245 	    alts[i].name = alt_dst;
246 	    memmove(alt_dst, alt_data + 2, alt_len);
247 	    alt_dst[alt_len] = '\0';
248 	    alt_dst += (alt_len + 1);
249 	    alt_data += (2 + alt_len + padlength[(2 + alt_len) & 3]);
250 	}
251     }
252     if (conn->alts)
253 	xfree(conn->alts);
254     conn->alts = alts;
255     conn->numAlts = nalts;
256 
257     setuplength = rep.auth_len << 2;
258     if (setuplength &&
259 	    !(auth_data = (char *) xalloc((unsigned int) setuplength))) {
260 	_FontTransClose(conn->trans_conn);
261 	errno = ENOMEM;
262 	return FALSE;
263     }
264     if (_fs_read(conn, (char *) auth_data, setuplength) == -1) {
265 	xfree(auth_data);
266 	return FALSE;
267     }
268     if (rep.status != AuthSuccess) {
269 	xfree(auth_data);
270 	_FontTransClose(conn->trans_conn);
271 	errno = EPERM;
272 	return FALSE;
273     }
274     /* get rest */
275     if (_fs_read(conn, (char *) &conn_accept, (long) SIZEOF(fsConnSetupAccept)) == -1) {
276 	xfree(auth_data);
277 	return FALSE;
278     }
279     if ((vendor_string = (char *)
280 	 xalloc((unsigned) conn_accept.vendor_len + 1)) == NULL) {
281 	xfree(auth_data);
282 	_FontTransClose(conn->trans_conn);
283 	errno = ENOMEM;
284 	return FALSE;
285     }
286     if (_fs_read_pad(conn, (char *) vendor_string, conn_accept.vendor_len) == -1) {
287 	xfree(vendor_string);
288 	xfree(auth_data);
289 	return FALSE;
290     }
291     xfree(auth_data);
292     xfree(vendor_string);
293 
294     if (copy_name_p)
295     {
296         conn->servername = (char *) xalloc(strlen(servername) + 1);
297         if (conn->servername == NULL)
298 	    return FALSE;
299         strcpy(conn->servername, servername);
300     }
301     else
302         conn->servername = servername;
303 
304     return TRUE;
305 }
306 
307 static Bool
_fs_try_alternates(conn,timeout)308 _fs_try_alternates(conn, timeout)
309     FSFpePtr    conn;
310     int         timeout;
311 {
312     int         i;
313 
314     for (i = 0; i < conn->numAlts; i++)
315 	if (_fs_setup_connection(conn, conn->alts[i].name, timeout, TRUE))
316 	    return TRUE;
317     return FALSE;
318 }
319 
320 #define FS_OPEN_TIMEOUT	    30
321 #define FS_REOPEN_TIMEOUT   10
322 
323 FSFpePtr
_fs_open_server(servername)324 _fs_open_server(servername)
325     char       *servername;
326 {
327     FSFpePtr    conn;
328 
329     conn = (FSFpePtr) xalloc(sizeof(FSFpeRec));
330     if (!conn) {
331 	errno = ENOMEM;
332 	return (FSFpePtr) NULL;
333     }
334     bzero((char *) conn, sizeof(FSFpeRec));
335     if (!_fs_setup_connection(conn, servername, FS_OPEN_TIMEOUT, TRUE)) {
336 	if (!_fs_try_alternates(conn, FS_OPEN_TIMEOUT)) {
337 	    xfree(conn->alts);
338 	    xfree(conn);
339 	    return (FSFpePtr) NULL;
340 	}
341     }
342     return conn;
343 }
344 
345 Bool
_fs_reopen_server(conn)346 _fs_reopen_server(conn)
347     FSFpePtr    conn;
348 {
349     if (_fs_setup_connection(conn, conn->servername, FS_REOPEN_TIMEOUT, FALSE))
350 	return TRUE;
351     if (_fs_try_alternates(conn, FS_REOPEN_TIMEOUT))
352 	return TRUE;
353     return FALSE;
354 }
355 
356 /*
357  * expects everything to be here.  *not* to be called when reading huge
358  * numbers of replies, but rather to get each chunk
359  */
_fs_read(conn,data,size)360 _fs_read(conn, data, size)
361     FSFpePtr    conn;
362     char       *data;
363     unsigned long size;
364 {
365     long        bytes_read;
366 #if defined(SVR4) && defined(i386)
367     int		num_failed_reads = 0;
368 #endif
369 
370     if (size == 0) {
371 
372 #ifdef DEBUG
373 	fprintf(stderr, "tried to read 0 bytes \n");
374 #endif
375 
376 	return 0;
377     }
378     ESET(0);
379     /*
380      * For SVR4 with a unix-domain connection, ETEST() after selecting
381      * readable means the server has died.  To do this here, we look for
382      * two consecutive reads returning ETEST().
383      */
384     while ((bytes_read = _FontTransRead(conn->trans_conn,
385 	data, (int) size)) != size) {
386 	if (bytes_read > 0) {
387 	    size -= bytes_read;
388 	    data += bytes_read;
389 #if defined(SVR4) && defined(i386)
390 	    num_failed_reads = 0;
391 #endif
392 	} else if (ETEST()) {
393 	    /* in a perfect world, this shouldn't happen */
394 	    /* ... but then, its less than perfect... */
395 	    if (_fs_wait_for_readable(conn) == -1) {	/* check for error */
396 		_fs_connection_died(conn);
397 		ESET(EPIPE);
398 		return -1;
399 	    }
400 #if defined(SVR4) && defined(i386)
401 	    num_failed_reads++;
402 	    if (num_failed_reads > 1) {
403 		_fs_connection_died(conn);
404 		ESET(EPIPE);
405 		return -1;
406 	    }
407 #endif
408 	    ESET(0);
409 	} else if (ECHECK(EINTR)) {
410 #if defined(SVR4) && defined(i386)
411 	    num_failed_reads = 0;
412 #endif
413 	    continue;
414 	} else {		/* something bad happened */
415 	    if (conn->fs_fd > 0)
416 		_fs_connection_died(conn);
417 	    ESET(EPIPE);
418 	    return -1;
419 	}
420     }
421     return 0;
422 }
423 
_fs_write(conn,data,size)424 _fs_write(conn, data, size)
425     FSFpePtr    conn;
426     char       *data;
427     unsigned long size;
428 {
429     long        bytes_written;
430 
431     if (size == 0) {
432 
433 #ifdef DEBUG
434 	fprintf(stderr, "tried to write 0 bytes \n");
435 #endif
436 
437 	return 0;
438     }
439 
440     /* XXX - hack.  The right fix is to remember that the font server
441        has gone away when we first discovered it. */
442     if (!conn->trans_conn)
443 	return -1;
444 
445     ESET(0);
446     while ((bytes_written = _FontTransWrite(conn->trans_conn,
447 	data, (int) size)) != size) {
448 	if (bytes_written > 0) {
449 	    size -= bytes_written;
450 	    data += bytes_written;
451 	} else if (ETEST()) {
452 	    /* XXX -- we assume this can't happen */
453 
454 #ifdef DEBUG
455 	    fprintf(stderr, "fs_write blocking\n");
456 #endif
457 	} else if (ECHECK(EINTR)) {
458 	    continue;
459 	} else {		/* something bad happened */
460 	    _fs_connection_died(conn);
461 	    ESET(EPIPE);
462 	    return -1;
463 	}
464     }
465     return 0;
466 }
467 
_fs_read_pad(conn,data,len)468 _fs_read_pad(conn, data, len)
469     FSFpePtr    conn;
470     char       *data;
471     int         len;
472 {
473     char        pad[3];
474 
475     if (_fs_read(conn, data, len) == -1)
476 	return -1;
477 
478     /* read the junk */
479     if (padlength[len & 3]) {
480 	return _fs_read(conn, pad, padlength[len & 3]);
481     }
482     return 0;
483 }
484 
_fs_write_pad(conn,data,len)485 _fs_write_pad(conn, data, len)
486     FSFpePtr    conn;
487     char       *data;
488     int         len;
489 {
490     static char pad[3];
491 
492     if (_fs_write(conn, data, len) == -1)
493 	return -1;
494 
495     /* write the pad */
496     if (padlength[len & 3]) {
497 	return _fs_write(conn, pad, padlength[len & 3]);
498     }
499     return 0;
500 }
501 
502 /*
503  * returns the amount of data waiting to be read
504  */
505 int
_fs_data_ready(conn)506 _fs_data_ready(conn)
507     FSFpePtr    conn;
508 {
509     BytesReadable_t readable;
510 
511     if (_FontTransBytesReadable(conn->trans_conn, &readable) < 0)
512 	return -1;
513     return readable;
514 }
515 
516 int
_fs_wait_for_readable(conn)517 _fs_wait_for_readable(conn)
518     FSFpePtr    conn;
519 {
520 #ifndef AMOEBA
521     fd_set r_mask;
522     fd_set e_mask;
523     int         result;
524 
525 #ifdef DEBUG
526     fprintf(stderr, "read would block\n");
527 #endif
528 
529     do {
530 	FD_ZERO(&r_mask);
531 #ifndef MINIX
532 	FD_ZERO(&e_mask);
533 #endif
534 	FD_SET(conn->fs_fd, &r_mask);
535 	FD_SET(conn->fs_fd, &e_mask);
536 	result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, NULL);
537 	if (result == -1) {
538 	    if (ECHECK(EINTR) || ECHECK(EAGAIN))
539 		continue;
540 	    else
541 		return -1;
542 	}
543 	if (result && FD_ISSET(conn->fs_fd, &e_mask))
544 	    return -1;
545     } while (result <= 0);
546 
547     return 0;
548 #else
549     printf("fs_wait_for_readable(): fail\n");
550     return -1;
551 #endif
552 }
553 
554 int
_fs_set_bit(mask,fd)555 _fs_set_bit(mask, fd)
556     fd_set* mask;
557     int         fd;
558 {
559     FD_SET(fd, mask);
560     return fd;
561 }
562 
563 int
_fs_is_bit_set(mask,fd)564 _fs_is_bit_set(mask, fd)
565     fd_set* mask;
566     int         fd;
567 {
568     return FD_ISSET(fd, mask);
569 }
570 
571 void
_fs_bit_clear(mask,fd)572 _fs_bit_clear(mask, fd)
573     fd_set* mask;
574     int         fd;
575 {
576     FD_CLR(fd, mask);
577 }
578 
579 int
_fs_any_bit_set(mask)580 _fs_any_bit_set(mask)
581     fd_set* mask;
582 {
583     return XFD_ANYSET(mask);
584 }
585 
586 int
_fs_or_bits(dst,m1,m2)587 _fs_or_bits(dst, m1, m2)
588     fd_set* dst;
589     fd_set* m1;
590     fd_set* m2;
591 {
592 #ifdef WIN32
593     int i;
594     if (dst != m1) {
595 	for (i = m1->fd_count; --i >= 0; ) {
596 	    if (!FD_ISSET(m1->fd_array[i], dst))
597 		FD_SET(m1->fd_array[i], dst);
598 	}
599     }
600     if (dst != m2) {
601 	for (i = m2->fd_count; --i >= 0; ) {
602 	    if (!FD_ISSET(m2->fd_array[i], dst))
603 		FD_SET(m2->fd_array[i], dst);
604 	}
605     }
606 #else
607     XFD_ORSET(dst, m1, m2);
608 #endif
609 
610     return 0;
611 }
612 
_fs_drain_bytes(conn,len)613 _fs_drain_bytes(conn, len)
614     FSFpePtr    conn;
615     int         len;
616 {
617     char        buf[128];
618 
619 #ifdef DEBUG
620     fprintf(stderr, "draining wire\n");
621 #endif
622 
623     while (len > 0) {
624 	if (_fs_read(conn, buf, (len < 128) ? len : 128) < 0)
625 	    return -1;
626 	len -= 128;
627     }
628     return 0;
629 }
630 
_fs_drain_bytes_pad(conn,len)631 _fs_drain_bytes_pad(conn, len)
632     FSFpePtr    conn;
633     int         len;
634 {
635     _fs_drain_bytes(conn, len);
636 
637     /* read the junk */
638     if (padlength[len & 3]) {
639 	_fs_drain_bytes(conn, padlength[len & 3]);
640     }
641 }
642 
_fs_eat_rest_of_error(conn,err)643 _fs_eat_rest_of_error(conn, err)
644     FSFpePtr    conn;
645     fsError    *err;
646 {
647     int         len = (err->length - (SIZEOF(fsGenericReply) >> 2)) << 2;
648 
649 #ifdef DEBUG
650     fprintf(stderr, "clearing error\n");
651 #endif
652 
653     _fs_drain_bytes(conn, len);
654 }
655