]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/lib/font/fc/fsio.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / lib / font / fc / fsio.c
diff --git a/Xserver/lib/font/fc/fsio.c b/Xserver/lib/font/fc/fsio.c
new file mode 100644 (file)
index 0000000..586e6ad
--- /dev/null
@@ -0,0 +1,652 @@
+/* $XConsortium: fsio.c,v 1.37 95/04/05 19:58:13 kaleb Exp $ */
+/* $XFree86: xc/lib/font/fc/fsio.c,v 3.5.2.1 1998/02/15 16:08:40 hohndel 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>
+#if !defined(WIN32) && !defined(AMOEBA) && !defined(_MINIX)
+#ifndef Lynx
+#include       <sys/socket.h>
+#else
+#include       <socket.h>
+#endif
+#endif
+#include       <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif 
+#ifdef WIN32
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef EINTR
+#define EINTR WSAEINTR
+#endif
+
+#ifdef MINIX
+#include <sys/nbio.h>
+#define select(n,r,w,x,t) nbio_select(n,r,w,x,t)
+#endif
+
+#ifdef __EMX__
+#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t)
+#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
+#ifdef ISC
+#define ECHECK(err) ((errno == err) || ETEST())
+#else
+#define ECHECK(err) (errno == err)
+#endif
+#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
+ */
+_fs_read(conn, data, size)
+    FSFpePtr    conn;
+    char       *data;
+    unsigned long size;
+{
+    long        bytes_read;
+#if defined(SVR4) && defined(i386)
+    int                num_failed_reads = 0;
+#endif
+
+    if (size == 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "tried to read 0 bytes \n");
+#endif
+
+       return 0;
+    }
+    ESET(0);
+    /*
+     * For SVR4 with a unix-domain connection, ETEST() after selecting
+     * readable means the server has died.  To do this here, we look for
+     * two consecutive reads returning ETEST().
+     */
+    while ((bytes_read = _FontTransRead(conn->trans_conn,
+       data, (int) size)) != size) {
+       if (bytes_read > 0) {
+           size -= bytes_read;
+           data += bytes_read;
+#if defined(SVR4) && defined(i386)
+           num_failed_reads = 0;
+#endif
+       } 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;
+           }
+#if defined(SVR4) && defined(i386)
+           num_failed_reads++;
+           if (num_failed_reads > 1) {
+               _fs_connection_died(conn);
+               ESET(EPIPE);
+               return -1;
+           }
+#endif
+           ESET(0);
+       } else if (ECHECK(EINTR)) {
+#if defined(SVR4) && defined(i386)
+           num_failed_reads = 0;
+#endif
+           continue;
+       } else {                /* something bad happened */
+           if (conn->fs_fd > 0)
+               _fs_connection_died(conn);
+           ESET(EPIPE);
+           return -1;
+       }
+    }
+    return 0;
+}
+
+_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;
+}
+
+_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;
+}
+
+_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;
+{
+#ifndef AMOEBA
+    fd_set r_mask;
+    fd_set e_mask;
+    int         result;
+
+#ifdef DEBUG
+    fprintf(stderr, "read would block\n");
+#endif
+
+    do {
+       FD_ZERO(&r_mask);
+#ifndef MINIX
+       FD_ZERO(&e_mask);
+#endif
+       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;
+#else
+    printf("fs_wait_for_readable(): fail\n");
+    return -1;
+#endif
+}
+
+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;
+{
+    XFD_ANYSET(mask);
+}
+
+int
+_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
+}
+
+_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;
+}
+
+_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]);
+    }
+}
+
+_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);
+}