summaryrefslogtreecommitdiff
path: root/src/fc/fsio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fc/fsio.c')
-rw-r--r--src/fc/fsio.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/src/fc/fsio.c b/src/fc/fsio.c
new file mode 100644
index 0000000..578d86a
--- /dev/null
+++ b/src/fc/fsio.c
@@ -0,0 +1,612 @@
+/* $Xorg: fsio.c,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */
+/*
+ * Copyright 1990 Network Computing Devices
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Network Computing Devices not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. Network Computing
+ * Devices makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+ * OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Dave Lemke, Network Computing Devices, Inc
+ */
+/*
+ * font server i/o routines
+ */
+
+#ifdef WIN32
+#define _WILLWINSOCK_
+#endif
+
+#include "FS.h"
+#include "FSproto.h"
+
+#include "X11/Xtrans.h"
+#include "X11/Xpoll.h"
+#include "fontmisc.h"
+#include "fsio.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+#ifdef WIN32
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef EINTR
+#define EINTR WSAEINTR
+#endif
+
+/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+ * systems are broken and return EWOULDBLOCK when they should return EAGAIN
+ */
+#ifdef WIN32
+#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+#if defined(EAGAIN) && defined(EWOULDBLOCK)
+#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
+#else
+#ifdef EAGAIN
+#define ETEST() (errno == EAGAIN)
+#else
+#define ETEST() (errno == EWOULDBLOCK)
+#endif
+#endif
+#endif
+#ifdef WIN32
+#define ECHECK(err) (WSAGetLastError() == err)
+#define ESET(val) WSASetLastError(val)
+#else
+#define ECHECK(err) (errno == err)
+#define ESET(val) errno = val
+#endif
+
+static int padlength[4] = {0, 3, 2, 1};
+fd_set _fs_fd_mask;
+
+int _fs_wait_for_readable();
+
+#ifdef SIGNALRETURNSINT
+#define SIGNAL_T int
+#else
+#define SIGNAL_T void
+#endif
+
+/* ARGSUSED */
+static SIGNAL_T
+_fs_alarm(foo)
+ int foo;
+{
+ return;
+}
+
+static XtransConnInfo
+_fs_connect(servername, timeout)
+ char *servername;
+ int timeout;
+{
+ XtransConnInfo trans_conn; /* transport connection object */
+ int ret = -1;
+#ifdef SIGALRM
+ unsigned oldTime;
+
+ SIGNAL_T(*oldAlarm) ();
+#endif
+
+ /*
+ * Open the network connection.
+ */
+ if( (trans_conn=_FontTransOpenCOTSClient(servername)) == NULL )
+ {
+ return (NULL);
+ }
+
+#ifdef SIGALRM
+ oldTime = alarm((unsigned) 0);
+ oldAlarm = signal(SIGALRM, _fs_alarm);
+ alarm((unsigned) timeout);
+#endif
+
+ ret = _FontTransConnect(trans_conn,servername);
+
+#ifdef SIGALRM
+ alarm((unsigned) 0);
+ signal(SIGALRM, oldAlarm);
+ alarm(oldTime);
+#endif
+
+ if (ret < 0)
+ {
+ _FontTransClose(trans_conn);
+ return (NULL);
+ }
+
+ /*
+ * Set the connection non-blocking since we use select() to block.
+ */
+
+ _FontTransSetOption(trans_conn, TRANS_NONBLOCKING, 1);
+
+ return trans_conn;
+}
+
+static int generationCount;
+
+/* ARGSUSED */
+static Bool
+_fs_setup_connection(conn, servername, timeout, copy_name_p)
+ FSFpePtr conn;
+ char *servername;
+ int timeout;
+ Bool copy_name_p;
+{
+ fsConnClientPrefix prefix;
+ fsConnSetup rep;
+ int setuplength;
+ fsConnSetupAccept conn_accept;
+ int endian;
+ int i;
+ int alt_len;
+ char *auth_data = NULL,
+ *vendor_string = NULL,
+ *alt_data = NULL,
+ *alt_dst;
+ FSFpeAltPtr alts;
+ int nalts;
+
+ if ((conn->trans_conn = _fs_connect(servername, 5)) == NULL)
+ return FALSE;
+
+ conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
+
+ conn->generation = ++generationCount;
+
+ /* send setup prefix */
+ endian = 1;
+ if (*(char *) &endian)
+ prefix.byteOrder = 'l';
+ else
+ prefix.byteOrder = 'B';
+
+ prefix.major_version = FS_PROTOCOL;
+ prefix.minor_version = FS_PROTOCOL_MINOR;
+
+/* XXX add some auth info here */
+ prefix.num_auths = 0;
+ prefix.auth_len = 0;
+
+ if (_fs_write(conn, (char *) &prefix, SIZEOF(fsConnClientPrefix)) == -1)
+ return FALSE;
+
+ /* read setup info */
+ if (_fs_read(conn, (char *) &rep, SIZEOF(fsConnSetup)) == -1)
+ return FALSE;
+
+ conn->fsMajorVersion = rep.major_version;
+ if (rep.major_version > FS_PROTOCOL)
+ return FALSE;
+
+ alts = 0;
+ /* parse alternate list */
+ if ((nalts = rep.num_alternates)) {
+ setuplength = rep.alternate_len << 2;
+ alts = (FSFpeAltPtr) xalloc(nalts * sizeof(FSFpeAltRec) +
+ setuplength);
+ if (!alts) {
+ _FontTransClose(conn->trans_conn);
+ errno = ENOMEM;
+ return FALSE;
+ }
+ alt_data = (char *) (alts + nalts);
+ if (_fs_read(conn, (char *) alt_data, setuplength) == -1) {
+ xfree(alts);
+ return FALSE;
+ }
+ alt_dst = alt_data;
+ for (i = 0; i < nalts; i++) {
+ alts[i].subset = alt_data[0];
+ alt_len = alt_data[1];
+ alts[i].name = alt_dst;
+ memmove(alt_dst, alt_data + 2, alt_len);
+ alt_dst[alt_len] = '\0';
+ alt_dst += (alt_len + 1);
+ alt_data += (2 + alt_len + padlength[(2 + alt_len) & 3]);
+ }
+ }
+ if (conn->alts)
+ xfree(conn->alts);
+ conn->alts = alts;
+ conn->numAlts = nalts;
+
+ setuplength = rep.auth_len << 2;
+ if (setuplength &&
+ !(auth_data = (char *) xalloc((unsigned int) setuplength))) {
+ _FontTransClose(conn->trans_conn);
+ errno = ENOMEM;
+ return FALSE;
+ }
+ if (_fs_read(conn, (char *) auth_data, setuplength) == -1) {
+ xfree(auth_data);
+ return FALSE;
+ }
+ if (rep.status != AuthSuccess) {
+ xfree(auth_data);
+ _FontTransClose(conn->trans_conn);
+ errno = EPERM;
+ return FALSE;
+ }
+ /* get rest */
+ if (_fs_read(conn, (char *) &conn_accept, (long) SIZEOF(fsConnSetupAccept)) == -1) {
+ xfree(auth_data);
+ return FALSE;
+ }
+ if ((vendor_string = (char *)
+ xalloc((unsigned) conn_accept.vendor_len + 1)) == NULL) {
+ xfree(auth_data);
+ _FontTransClose(conn->trans_conn);
+ errno = ENOMEM;
+ return FALSE;
+ }
+ if (_fs_read_pad(conn, (char *) vendor_string, conn_accept.vendor_len) == -1) {
+ xfree(vendor_string);
+ xfree(auth_data);
+ return FALSE;
+ }
+ xfree(auth_data);
+ xfree(vendor_string);
+
+ if (copy_name_p)
+ {
+ conn->servername = (char *) xalloc(strlen(servername) + 1);
+ if (conn->servername == NULL)
+ return FALSE;
+ strcpy(conn->servername, servername);
+ }
+ else
+ conn->servername = servername;
+
+ return TRUE;
+}
+
+static Bool
+_fs_try_alternates(conn, timeout)
+ FSFpePtr conn;
+ int timeout;
+{
+ int i;
+
+ for (i = 0; i < conn->numAlts; i++)
+ if (_fs_setup_connection(conn, conn->alts[i].name, timeout, TRUE))
+ return TRUE;
+ return FALSE;
+}
+
+#define FS_OPEN_TIMEOUT 30
+#define FS_REOPEN_TIMEOUT 10
+
+FSFpePtr
+_fs_open_server(servername)
+ char *servername;
+{
+ FSFpePtr conn;
+
+ conn = (FSFpePtr) xalloc(sizeof(FSFpeRec));
+ if (!conn) {
+ errno = ENOMEM;
+ return (FSFpePtr) NULL;
+ }
+ bzero((char *) conn, sizeof(FSFpeRec));
+ if (!_fs_setup_connection(conn, servername, FS_OPEN_TIMEOUT, TRUE)) {
+ if (!_fs_try_alternates(conn, FS_OPEN_TIMEOUT)) {
+ xfree(conn->alts);
+ xfree(conn);
+ return (FSFpePtr) NULL;
+ }
+ }
+ return conn;
+}
+
+Bool
+_fs_reopen_server(conn)
+ FSFpePtr conn;
+{
+ if (_fs_setup_connection(conn, conn->servername, FS_REOPEN_TIMEOUT, FALSE))
+ return TRUE;
+ if (_fs_try_alternates(conn, FS_REOPEN_TIMEOUT))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * expects everything to be here. *not* to be called when reading huge
+ * numbers of replies, but rather to get each chunk
+ */
+int
+_fs_read(conn, data, size)
+ FSFpePtr conn;
+ char *data;
+ unsigned long size;
+{
+ long bytes_read;
+
+ if (size == 0) {
+
+#ifdef DEBUG
+ fprintf(stderr, "tried to read 0 bytes \n");
+#endif
+
+ return 0;
+ }
+ ESET(0);
+ while ((bytes_read = _FontTransRead(conn->trans_conn,
+ data, (int) size)) != size) {
+ if (bytes_read > 0) {
+ size -= bytes_read;
+ data += bytes_read;
+ } else if (ETEST()) {
+ /* in a perfect world, this shouldn't happen */
+ /* ... but then, its less than perfect... */
+ if (_fs_wait_for_readable(conn) == -1) { /* check for error */
+ _fs_connection_died(conn);
+ ESET(EPIPE);
+ return -1;
+ }
+ ESET(0);
+ } else if (ECHECK(EINTR)) {
+ continue;
+ } else { /* something bad happened */
+ if (conn->fs_fd > 0)
+ _fs_connection_died(conn);
+ ESET(EPIPE);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+_fs_write(conn, data, size)
+ FSFpePtr conn;
+ char *data;
+ unsigned long size;
+{
+ long bytes_written;
+
+ if (size == 0) {
+
+#ifdef DEBUG
+ fprintf(stderr, "tried to write 0 bytes \n");
+#endif
+
+ return 0;
+ }
+
+ /* XXX - hack. The right fix is to remember that the font server
+ has gone away when we first discovered it. */
+ if (!conn->trans_conn)
+ return -1;
+
+ ESET(0);
+ while ((bytes_written = _FontTransWrite(conn->trans_conn,
+ data, (int) size)) != size) {
+ if (bytes_written > 0) {
+ size -= bytes_written;
+ data += bytes_written;
+ } else if (ETEST()) {
+ /* XXX -- we assume this can't happen */
+
+#ifdef DEBUG
+ fprintf(stderr, "fs_write blocking\n");
+#endif
+ } else if (ECHECK(EINTR)) {
+ continue;
+ } else { /* something bad happened */
+ _fs_connection_died(conn);
+ ESET(EPIPE);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+_fs_read_pad(conn, data, len)
+ FSFpePtr conn;
+ char *data;
+ int len;
+{
+ char pad[3];
+
+ if (_fs_read(conn, data, len) == -1)
+ return -1;
+
+ /* read the junk */
+ if (padlength[len & 3]) {
+ return _fs_read(conn, pad, padlength[len & 3]);
+ }
+ return 0;
+}
+
+int
+_fs_write_pad(conn, data, len)
+ FSFpePtr conn;
+ char *data;
+ int len;
+{
+ static char pad[3];
+
+ if (_fs_write(conn, data, len) == -1)
+ return -1;
+
+ /* write the pad */
+ if (padlength[len & 3]) {
+ return _fs_write(conn, pad, padlength[len & 3]);
+ }
+ return 0;
+}
+
+/*
+ * returns the amount of data waiting to be read
+ */
+int
+_fs_data_ready(conn)
+ FSFpePtr conn;
+{
+ BytesReadable_t readable;
+
+ if (_FontTransBytesReadable(conn->trans_conn, &readable) < 0)
+ return -1;
+ return readable;
+}
+
+int
+_fs_wait_for_readable(conn)
+ FSFpePtr conn;
+{
+ fd_set r_mask;
+ fd_set e_mask;
+ int result;
+
+#ifdef DEBUG
+ fprintf(stderr, "read would block\n");
+#endif
+
+ do {
+ FD_ZERO(&r_mask);
+ FD_ZERO(&e_mask);
+ FD_SET(conn->fs_fd, &r_mask);
+ FD_SET(conn->fs_fd, &e_mask);
+ result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, NULL);
+ if (result == -1) {
+ if (ECHECK(EINTR) || ECHECK(EAGAIN))
+ continue;
+ else
+ return -1;
+ }
+ if (result && FD_ISSET(conn->fs_fd, &e_mask))
+ return -1;
+ } while (result <= 0);
+
+ return 0;
+}
+
+int
+_fs_set_bit(mask, fd)
+ fd_set* mask;
+ int fd;
+{
+ FD_SET(fd, mask);
+ return fd;
+}
+
+int
+_fs_is_bit_set(mask, fd)
+ fd_set* mask;
+ int fd;
+{
+ return FD_ISSET(fd, mask);
+}
+
+void
+_fs_bit_clear(mask, fd)
+ fd_set* mask;
+ int fd;
+{
+ FD_CLR(fd, mask);
+}
+
+int
+_fs_any_bit_set(mask)
+ fd_set* mask;
+{
+ return XFD_ANYSET(mask);
+}
+
+void
+_fs_or_bits(dst, m1, m2)
+ fd_set* dst;
+ fd_set* m1;
+ fd_set* m2;
+{
+#ifdef WIN32
+ int i;
+ if (dst != m1) {
+ for (i = m1->fd_count; --i >= 0; ) {
+ if (!FD_ISSET(m1->fd_array[i], dst))
+ FD_SET(m1->fd_array[i], dst);
+ }
+ }
+ if (dst != m2) {
+ for (i = m2->fd_count; --i >= 0; ) {
+ if (!FD_ISSET(m2->fd_array[i], dst))
+ FD_SET(m2->fd_array[i], dst);
+ }
+ }
+#else
+ XFD_ORSET(dst, m1, m2);
+#endif
+}
+
+int
+_fs_drain_bytes(conn, len)
+ FSFpePtr conn;
+ int len;
+{
+ char buf[128];
+
+#ifdef DEBUG
+ fprintf(stderr, "draining wire\n");
+#endif
+
+ while (len > 0) {
+ if (_fs_read(conn, buf, (len < 128) ? len : 128) < 0)
+ return -1;
+ len -= 128;
+ }
+ return 0;
+}
+
+void
+_fs_drain_bytes_pad(conn, len)
+ FSFpePtr conn;
+ int len;
+{
+ _fs_drain_bytes(conn, len);
+
+ /* read the junk */
+ if (padlength[len & 3]) {
+ _fs_drain_bytes(conn, padlength[len & 3]);
+ }
+}
+
+void
+_fs_eat_rest_of_error(conn, err)
+ FSFpePtr conn;
+ fsError *err;
+{
+ int len = (err->length - (SIZEOF(fsGenericReply) >> 2)) << 2;
+
+#ifdef DEBUG
+ fprintf(stderr, "clearing error\n");
+#endif
+
+ _fs_drain_bytes(conn, len);
+}