summaryrefslogtreecommitdiff
path: root/os/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/connection.c')
-rw-r--r--os/connection.c1281
1 files changed, 1281 insertions, 0 deletions
diff --git a/os/connection.c b/os/connection.c
new file mode 100644
index 000000000..7c4b9fef3
--- /dev/null
+++ b/os/connection.c
@@ -0,0 +1,1281 @@
+/* $Xorg: connection.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */
+/***********************************************************
+
+Copyright 1987, 1989, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+/*****************************************************************
+ * Stuff to create connections --- OS dependent
+ *
+ * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
+ * CloseDownConnection, CheckConnections, AddEnabledDevice,
+ * RemoveEnabledDevice, OnlyListToOneClient,
+ * ListenToAllClients,
+ *
+ * (WaitForSomething is in its own file)
+ *
+ * In this implementation, a client socket table is not kept.
+ * Instead, what would be the index into the table is just the
+ * file descriptor of the socket. This won't work for if the
+ * socket ids aren't small nums (0 - 2^8)
+ *
+ *****************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include "X.h"
+#include "Xproto.h"
+#include <X11/Xtrans.h>
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+
+#ifdef hpux
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#endif
+
+#ifdef AIXV3
+#include <sys/ioctl.h>
+#endif
+
+#if defined(TCPCONN) || defined(STREAMSCONN)
+# include <netinet/in.h>
+# ifndef hpux
+# ifdef apollo
+# ifndef NO_TCP_H
+# include <netinet/tcp.h>
+# endif
+# else
+# include <netinet/tcp.h>
+# endif
+# endif
+#endif
+
+#include <sys/uio.h>
+#endif /* WIN32 */
+#include "misc.h" /* for typedef of pointer */
+#include <X11/Xpoll.h>
+#include "osdep.h"
+#include "opaque.h"
+#include "dixstruct.h"
+#ifdef XAPPGROUP
+#include "extensions/Xagsrv.h"
+#endif
+#ifdef XCSECURITY
+#define _SECURITY_SERVER
+#include "extensions/security.h"
+#endif
+#ifdef LBX
+#include "lbxserve.h"
+#endif
+
+#ifdef X_NOT_POSIX
+#define Pid_t int
+#else
+#define Pid_t pid_t
+#endif
+
+#ifdef DNETCONN
+#include <netdnet/dn.h>
+#endif /* DNETCONN */
+
+extern char *display; /* The display number */
+int lastfdesc; /* maximum file descriptor */
+
+fd_set WellKnownConnections; /* Listener mask */
+fd_set EnabledDevices; /* mask for input devices that are on */
+fd_set AllSockets; /* select on this */
+fd_set AllClients; /* available clients */
+fd_set LastSelectMask; /* mask returned from last select call */
+fd_set ClientsWithInput; /* clients with FULL requests in buffer */
+fd_set ClientsWriteBlocked; /* clients who cannot receive output */
+fd_set OutputPending; /* clients with reply/event data ready to go */
+#ifndef _SC_OPEN_MAX
+int MaxClients = MAXSOCKS; /* use MAXSOCKS if sysconf(_SC_OPEN_MAX) is not supported */
+#else
+int MaxClients = 0;
+#endif
+Bool NewOutputPending; /* not yet attempted to write some new output */
+Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
+
+Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
+Bool PartialNetwork; /* continue even if unable to bind all addrs */
+static Pid_t ParentProcess;
+
+static Bool debug_conns = FALSE;
+
+fd_set IgnoredClientsWithInput;
+static fd_set GrabImperviousClients;
+static fd_set SavedAllClients;
+static fd_set SavedAllSockets;
+static fd_set SavedClientsWithInput;
+int GrabInProgress = 0;
+
+#ifndef WIN32
+int ConnectionTranslation[MAXSOCKS];
+#else
+/* SPAM ALERT !!!
+ * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
+ * not even a known maximum value, so use something quite arbitrary for now.
+ * This is clearly boggus and another form of storage which doesn't use the fd
+ * as a direct index should really be implemented for NT.
+ */
+#define MAXFD 500
+int ConnectionTranslation[MAXFD];
+#endif
+
+XtransConnInfo *ListenTransConns = NULL;
+int *ListenTransFds = NULL;
+int ListenTransCount;
+
+extern int auditTrailLevel;
+
+static void ErrorConnMax(
+#if NeedFunctionPrototypes
+XtransConnInfo /* trans_conn */
+#endif
+);
+
+#ifndef LBX
+static
+#endif
+void CloseDownFileDescriptor(
+#if NeedFunctionPrototypes
+#ifdef LBX
+ ClientPtr client
+#else
+ register OsCommPtr /*oc*/
+#endif
+#endif
+);
+
+#ifdef LBX
+extern int LbxFlushClient();
+extern void LbxCloseClient();
+#endif /* LBX */
+
+static XtransConnInfo
+lookup_trans_conn (fd)
+ int fd;
+{
+ if (ListenTransFds)
+ {
+ int i;
+ for (i = 0; i < ListenTransCount; i++)
+ if (ListenTransFds[i] == fd)
+ return ListenTransConns[i];
+ }
+
+ return (NULL);
+}
+
+#ifdef XDMCP
+void XdmcpOpenDisplay(), XdmcpInit(), XdmcpReset(), XdmcpCloseDisplay();
+#endif
+
+/*****************
+ * CreateWellKnownSockets
+ * At initialization, create the sockets to listen on for new clients.
+ *****************/
+
+void
+CreateWellKnownSockets()
+{
+ int request, i;
+ int partial;
+ char port[20];
+
+ FD_ZERO(&AllSockets);
+ FD_ZERO(&AllClients);
+ FD_ZERO(&LastSelectMask);
+ FD_ZERO(&ClientsWithInput);
+
+#ifndef WIN32
+ for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = 0;
+#else
+ for (i=0; i<MAXFD; i++) ConnectionTranslation[i] = 0;
+#endif
+#ifdef XNO_SYSCONF /* should only be on FreeBSD 1.x and NetBSD 0.x */
+#undef _SC_OPEN_MAX
+#endif
+#ifdef _SC_OPEN_MAX
+ lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
+#else
+#ifdef hpux
+ lastfdesc = _NFILE - 1;
+#else
+ lastfdesc = getdtablesize() - 1;
+#endif
+#endif
+
+ if (lastfdesc > MAXSOCKS)
+ {
+ lastfdesc = MAXSOCKS;
+ }
+
+ FD_ZERO (&WellKnownConnections);
+
+ sprintf (port, "%d", atoi (display));
+
+ if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial,
+ &ListenTransCount, &ListenTransConns) >= 0) &&
+ (ListenTransCount >= 1))
+ {
+ if (!PartialNetwork && partial)
+ {
+ FatalError ("Failed to establish all listening sockets");
+ }
+ else
+ {
+ ListenTransFds = (int *) malloc (ListenTransCount * sizeof (int));
+
+ for (i = 0; i < ListenTransCount; i++)
+ {
+ int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
+
+ ListenTransFds[i] = fd;
+ FD_SET (fd, &WellKnownConnections);
+
+ if (!_XSERVTransIsLocal (ListenTransConns[i]))
+ {
+ DefineSelf (fd);
+ }
+ }
+ }
+ }
+
+ if (!XFD_ANYSET (&WellKnownConnections))
+ FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running");
+#ifndef WIN32
+ OsSignal (SIGPIPE, SIG_IGN);
+ OsSignal (SIGHUP, AutoResetServer);
+#endif
+ OsSignal (SIGINT, GiveUp);
+ OsSignal (SIGTERM, GiveUp);
+ XFD_COPYSET (&WellKnownConnections, &AllSockets);
+ ResetHosts(display);
+ /*
+ * Magic: If SIGUSR1 was set to SIG_IGN when
+ * the server started, assume that either
+ *
+ * a- The parent process is ignoring SIGUSR1
+ *
+ * or
+ *
+ * b- The parent process is expecting a SIGUSR1
+ * when the server is ready to accept connections
+ *
+ * In the first case, the signal will be harmless,
+ * in the second case, the signal will be quite
+ * useful
+ */
+#ifndef WIN32
+ if (OsSignal (SIGUSR1, SIG_IGN) == SIG_IGN)
+ RunFromSmartParent = TRUE;
+ ParentProcess = getppid ();
+ if (RunFromSmartParent) {
+ if (ParentProcess > 0) {
+ kill (ParentProcess, SIGUSR1);
+ }
+ }
+#endif
+#ifdef XDMCP
+ XdmcpInit ();
+#endif
+}
+
+void
+ResetWellKnownSockets ()
+{
+ int i;
+
+ ResetOsBuffers();
+
+ for (i = 0; i < ListenTransCount; i++)
+ {
+ int status = _XSERVTransResetListener (ListenTransConns[i]);
+
+ if (status != TRANS_RESET_NOOP)
+ {
+ if (status == TRANS_RESET_FAILURE)
+ {
+ /*
+ * ListenTransConns[i] freed by xtrans.
+ * Remove it from out list.
+ */
+
+ FD_CLR (ListenTransFds[i], &WellKnownConnections);
+ ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
+ ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
+ ListenTransCount -= 1;
+ i -= 1;
+ }
+ else if (status == TRANS_RESET_NEW_FD)
+ {
+ /*
+ * A new file descriptor was allocated (the old one was closed)
+ */
+
+ int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
+
+ FD_CLR (ListenTransFds[i], &WellKnownConnections);
+ ListenTransFds[i] = newfd;
+ FD_SET(newfd, &WellKnownConnections);
+ }
+ }
+ }
+
+ ResetAuthorization ();
+ ResetHosts(display);
+ /*
+ * See above in CreateWellKnownSockets about SIGUSR1
+ */
+#ifndef WIN32
+ if (RunFromSmartParent) {
+ if (ParentProcess > 0) {
+ kill (ParentProcess, SIGUSR1);
+ }
+ }
+#endif
+ /*
+ * restart XDMCP
+ */
+#ifdef XDMCP
+ XdmcpReset ();
+#endif
+}
+
+static void
+AuthAudit (client, letin, saddr, len, proto_n, auth_proto, auth_id)
+ ClientPtr client;
+ Bool letin;
+ struct sockaddr *saddr;
+ int len;
+ unsigned short proto_n;
+ char *auth_proto;
+ int auth_id;
+{
+ char addr[128];
+ char *out = addr;
+
+ if (!((OsCommPtr)client->osPrivate)->trans_conn) {
+ strcpy(addr, "LBX proxy at ");
+ out += strlen(addr);
+ }
+ if (!len)
+ strcpy(out, "local host");
+ else
+ switch (saddr->sa_family)
+ {
+ case AF_UNSPEC:
+#if defined(UNIXCONN) || defined(LOCALCONN)
+ case AF_UNIX:
+#endif
+ strcpy(out, "local host");
+ break;
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ case AF_INET:
+ sprintf(out, "IP %s port %d",
+ inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr),
+ ((struct sockaddr_in *) saddr)->sin_port);
+ break;
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ sprintf(out, "DN %s",
+ dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add));
+ break;
+#endif
+ default:
+ strcpy(out, "unknown address");
+ }
+ if (letin)
+ AuditF("client %d connected from %s\n", client->index, addr);
+ else
+ AuditF("client %d rejected from %s\n", client->index, addr);
+ if (proto_n)
+ AuditF(" Auth name: %.*s ID: %d\n", proto_n, auth_proto, auth_id);
+}
+
+XID
+AuthorizationIDOfClient(client)
+ ClientPtr client;
+{
+ if (client->osPrivate)
+ return ((OsCommPtr)client->osPrivate)->auth_id;
+ else
+ return None;
+}
+
+
+/*****************************************************************
+ * ClientAuthorized
+ *
+ * Sent by the client at connection setup:
+ * typedef struct _xConnClientPrefix {
+ * CARD8 byteOrder;
+ * BYTE pad;
+ * CARD16 majorVersion, minorVersion;
+ * CARD16 nbytesAuthProto;
+ * CARD16 nbytesAuthString;
+ * } xConnClientPrefix;
+ *
+ * It is hoped that eventually one protocol will be agreed upon. In the
+ * mean time, a server that implements a different protocol than the
+ * client expects, or a server that only implements the host-based
+ * mechanism, will simply ignore this information.
+ *
+ *****************************************************************/
+
+char *
+ClientAuthorized(client, proto_n, auth_proto, string_n, auth_string)
+ ClientPtr client;
+ char *auth_proto, *auth_string;
+ unsigned int proto_n, string_n;
+{
+ register OsCommPtr priv;
+ Xtransaddr *from = NULL;
+ int family;
+ int fromlen;
+ XID auth_id;
+ char *reason = NULL;
+ XtransConnInfo trans_conn;
+ int restore_trans_conn = 0;
+ ClientPtr lbxpc;
+
+ priv = (OsCommPtr)client->osPrivate;
+ trans_conn = priv->trans_conn;
+
+#ifdef LBX
+ if (!trans_conn) {
+ /*
+ * Since trans_conn is NULL, this must be a proxy's client for
+ * which we have NO address. Therefore, we will temporarily
+ * set the client's trans_conn to the proxy's trans_conn and
+ * after CheckAuthorization the client's trans_conn will be
+ * restored.
+ *
+ * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization
+ * will eventually call XdmAuthorizationValidate and this
+ * later function may use the client's trans_conn to get the
+ * client's address. Since a XDM-AUTH-1 auth string includes
+ * the client's address, this address is compared to the address
+ * in the client's trans_conn. If the proxy and client are
+ * on the same host, the comparison will fail; otherwise the
+ * comparison will fail and the client will not be authorized
+ * to connect to the server.
+ *
+ * The basis for this additional code is to prevent a
+ * NULL pointer dereference of the client's trans_conn.
+ * The fundamental problem - the fact that the client's
+ * trans_conn is NULL - is because the NewClient
+ * request in version 1.0 of the LBX protocol does not
+ * send the client's address to the server. When the
+ * spec is changed and the client's address is sent to
+ * server in the NewClient request, this additional code
+ * should be removed.
+ *
+ * See defect number XWSog08218 for more information.
+ */
+ lbxpc = LbxProxyClient(priv->proxy);
+ trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn;
+ priv->trans_conn = trans_conn;
+ restore_trans_conn = 1;
+ }
+#endif
+
+ auth_id = CheckAuthorization (proto_n, auth_proto,
+ string_n, auth_string, client, &reason);
+
+#ifdef LBX
+ if (restore_trans_conn) {
+ /*
+ * Restore client's trans_conn state
+ */
+ priv = (OsCommPtr)client->osPrivate;
+ priv->trans_conn = NULL;
+
+ trans_conn = NULL;
+ }
+
+#endif
+
+#ifdef LBX
+ if (!trans_conn) {
+ /*
+ * Use the proxy's trans_conn
+ */
+ trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn;
+ if (auth_id == (XID) ~0L && !GetAccessControl())
+ auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id;
+#ifdef XCSECURITY
+ else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) {
+ auth_id = (XID) ~0L;
+ reason = "Client trust level differs from that of LBX Proxy";
+ }
+#endif
+ }
+#endif
+ if (auth_id == (XID) ~0L)
+ {
+ if (
+#ifdef XCSECURITY
+ (proto_n == 0 ||
+ strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) &&
+#endif
+ _XSERVTransGetPeerAddr (trans_conn,
+ &family, &fromlen, &from) != -1)
+ {
+ if (
+#ifdef LBX
+ !priv->trans_conn ||
+#endif
+ InvalidHost ((struct sockaddr *) from, fromlen))
+ AuthAudit(client, FALSE, (struct sockaddr *) from,
+ fromlen, proto_n, auth_proto, auth_id);
+ else
+ {
+ auth_id = (XID) 0;
+ if (auditTrailLevel > 1)
+ AuthAudit(client, TRUE,
+ (struct sockaddr *) from, fromlen,
+ proto_n, auth_proto, auth_id);
+ }
+
+ free ((char *) from);
+ }
+
+ if (auth_id == (XID) ~0L)
+ if (reason)
+ return reason;
+ else
+ return "Client is not authorized to connect to Server";
+ }
+ else if (auditTrailLevel > 1)
+ {
+ if (_XSERVTransGetPeerAddr (trans_conn,
+ &family, &fromlen, &from) != -1)
+ {
+ AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
+ proto_n, auth_proto, auth_id);
+
+ free ((char *) from);
+ }
+ }
+ priv->auth_id = auth_id;
+ priv->conn_time = 0;
+
+#ifdef XDMCP
+ /* indicate to Xdmcp protocol that we've opened new client */
+ XdmcpOpenDisplay(priv->fd);
+#endif /* XDMCP */
+#ifdef XAPPGROUP
+ if (ClientStateCallback)
+ XagCallClientStateChange (client);
+#endif
+ /* At this point, if the client is authorized to change the access control
+ * list, we should getpeername() information, and add the client to
+ * the selfhosts list. It's not really the host machine, but the
+ * true purpose of the selfhosts list is to see who may change the
+ * access control list.
+ */
+ return((char *)NULL);
+}
+
+static ClientPtr
+#ifdef LBX
+AllocNewConnection (trans_conn, fd, conn_time, Flush, Close, proxy)
+#else
+AllocNewConnection (trans_conn, fd, conn_time)
+#endif
+ XtransConnInfo trans_conn;
+ int fd;
+ CARD32 conn_time;
+#ifdef LBX
+ int (*Flush)();
+ void (*Close)();
+ LbxProxyPtr proxy;
+#endif
+{
+ OsCommPtr oc;
+ ClientPtr client;
+
+ if (
+#ifdef LBX
+ trans_conn &&
+#endif
+#ifndef WIN32
+ fd >= lastfdesc
+#else
+ XFD_SETCOUNT(&AllClients) >= MaxClients
+#endif
+ )
+ return NullClient;
+ oc = (OsCommPtr)xalloc(sizeof(OsCommRec));
+ if (!oc)
+ return NullClient;
+ oc->trans_conn = trans_conn;
+ oc->fd = fd;
+ oc->input = (ConnectionInputPtr)NULL;
+ oc->output = (ConnectionOutputPtr)NULL;
+ oc->auth_id = None;
+ oc->conn_time = conn_time;
+#ifdef LBX
+ oc->proxy = proxy;
+ oc->Flush = Flush;
+ oc->Close = Close;
+ oc->largereq = (ConnectionInputPtr) NULL;
+#endif
+ if (!(client = NextAvailableClient((pointer)oc)))
+ {
+ xfree (oc);
+ return NullClient;
+ }
+#ifdef LBX
+ if (trans_conn)
+#endif
+ {
+ ConnectionTranslation[fd] = client->index;
+ if (GrabInProgress)
+ {
+ FD_SET(fd, &SavedAllClients);
+ FD_SET(fd, &SavedAllSockets);
+ }
+ else
+ {
+ FD_SET(fd, &AllClients);
+ FD_SET(fd, &AllSockets);
+ }
+ }
+ return client;
+}
+
+#ifdef LBX
+
+int
+ClientConnectionNumber (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ return oc->fd;
+}
+
+ClientPtr
+AllocLbxClientConnection (client, proxy)
+ ClientPtr client;
+ LbxProxyPtr proxy;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(),
+ LbxFlushClient, LbxCloseClient, proxy);
+}
+
+void
+LbxProxyConnection (client, proxy)
+ ClientPtr client;
+ LbxProxyPtr proxy;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ FlushClient(client, oc, (char *)NULL, 0);
+ oc->proxy = proxy;
+ oc->Flush = LbxFlushClient;
+ oc->Close = LbxCloseClient;
+ LbxPrimeInput(client, proxy);
+}
+
+#endif
+
+/*****************
+ * EstablishNewConnections
+ * If anyone is waiting on listened sockets, accept them.
+ * Returns a mask with indices of new clients. Updates AllClients
+ * and AllSockets.
+ *****************/
+
+/*ARGSUSED*/
+Bool
+EstablishNewConnections(clientUnused, closure)
+ ClientPtr clientUnused;
+ pointer closure;
+{
+#ifndef WIN32
+ fd_mask readyconnections; /* mask of listeners that are ready */
+#else
+ fd_set readyconnections; /* set of listeners that are ready */
+#endif
+ int curconn; /* fd of listener that's ready */
+ register int newconn; /* fd of new client */
+ CARD32 connect_time;
+ register int i;
+ register ClientPtr client;
+ register OsCommPtr oc;
+ fd_set tmask;
+
+ XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections);
+#ifndef WIN32
+ readyconnections = tmask.fds_bits[0];
+ if (!readyconnections)
+ return TRUE;
+#else
+ XFD_COPYSET(&tmask, &readyconnections);
+ if (!XFD_ANYSET(&readyconnections))
+ return TRUE;
+#endif
+ connect_time = GetTimeInMillis();
+ /* kill off stragglers */
+ for (i=1; i<currentMaxClients; i++)
+ {
+ if (client = clients[i])
+ {
+ oc = (OsCommPtr)(client->osPrivate);
+ if (oc && (oc->conn_time != 0) &&
+ (connect_time - oc->conn_time) >= TimeOutValue ||
+ client->noClientException != Success && !client->clientGone)
+ CloseDownClient(client);
+ }
+ }
+#ifndef WIN32
+ while (readyconnections)
+#else
+ for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
+#endif
+ {
+ XtransConnInfo trans_conn, new_trans_conn;
+ int status;
+
+#ifndef WIN32
+ curconn = ffs (readyconnections) - 1;
+ readyconnections &= ~(1 << curconn);
+#else
+ curconn = XFD_FD(&readyconnections, i);
+#endif
+
+ if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
+ continue;
+
+ if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL)
+ continue;
+
+ newconn = _XSERVTransGetConnectionNumber (new_trans_conn);
+
+ if (newconn < lastfdesc)
+ {
+ int clientid;
+ clientid = ConnectionTranslation[newconn];
+ if(clientid && (client = clients[clientid]))
+ CloseDownClient(client);
+ }
+
+ _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
+
+ if (!AllocNewConnection (new_trans_conn, newconn, connect_time
+#ifdef LBX
+ , StandardFlushClient,
+ CloseDownFileDescriptor, (LbxProxyPtr)NULL
+#endif
+ ))
+ {
+ ErrorConnMax(new_trans_conn);
+ _XSERVTransClose(new_trans_conn);
+ }
+ }
+ return TRUE;
+}
+
+#define NOROOM "Maximum number of clients reached"
+
+/************
+ * ErrorConnMax
+ * Fail a connection due to lack of client or file descriptor space
+ ************/
+
+static void
+ErrorConnMax(trans_conn)
+XtransConnInfo trans_conn;
+{
+ register int fd = _XSERVTransGetConnectionNumber (trans_conn);
+ xConnSetupPrefix csp;
+ char pad[3];
+ struct iovec iov[3];
+ char byteOrder = 0;
+ int whichbyte = 1;
+ struct timeval waittime;
+ fd_set mask;
+
+ /* if these seems like a lot of trouble to go to, it probably is */
+ waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
+ waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ FD_ZERO(&mask);
+ FD_SET(fd, &mask);
+ (void)Select(fd + 1, &mask, NULL, NULL, &waittime);
+ /* try to read the byte-order of the connection */
+ (void)_XSERVTransRead(trans_conn, &byteOrder, 1);
+ if ((byteOrder == 'l') || (byteOrder == 'B'))
+ {
+ csp.success = xFalse;
+ csp.lengthReason = sizeof(NOROOM) - 1;
+ csp.length = (sizeof(NOROOM) + 2) >> 2;
+ csp.majorVersion = X_PROTOCOL;
+ csp.minorVersion = X_PROTOCOL_REVISION;
+ if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
+ (!(*(char *) &whichbyte) && (byteOrder == 'l')))
+ {
+ swaps(&csp.majorVersion, whichbyte);
+ swaps(&csp.minorVersion, whichbyte);
+ swaps(&csp.length, whichbyte);
+ }
+ iov[0].iov_len = sz_xConnSetupPrefix;
+ iov[0].iov_base = (char *) &csp;
+ iov[1].iov_len = csp.lengthReason;
+ iov[1].iov_base = NOROOM;
+ iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
+ iov[2].iov_base = pad;
+ (void)_XSERVTransWritev(trans_conn, iov, 3);
+ }
+}
+
+/************
+ * CloseDownFileDescriptor:
+ * Remove this file descriptor and it's I/O buffers, etc.
+ ************/
+
+#ifdef LBX
+void
+CloseDownFileDescriptor(client)
+ ClientPtr client;
+#else
+static void
+CloseDownFileDescriptor(oc)
+ register OsCommPtr oc;
+#endif
+{
+#ifdef LBX
+ register OsCommPtr oc = (OsCommPtr) client->osPrivate;
+#endif
+ int connection = oc->fd;
+
+ if (oc->trans_conn) {
+ _XSERVTransDisconnect(oc->trans_conn);
+ _XSERVTransClose(oc->trans_conn);
+ }
+#ifdef LBX
+ ConnectionTranslation[connection] = 0;
+#else
+ FreeOsBuffers(oc);
+#endif
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ FD_CLR(connection, &ClientsWithInput);
+ FD_CLR(connection, &GrabImperviousClients);
+ if (GrabInProgress)
+ {
+ FD_CLR(connection, &SavedAllSockets);
+ FD_CLR(connection, &SavedAllClients);
+ FD_CLR(connection, &SavedClientsWithInput);
+ }
+ FD_CLR(connection, &ClientsWriteBlocked);
+ if (!XFD_ANYSET(&ClientsWriteBlocked))
+ AnyClientsWriteBlocked = FALSE;
+ FD_CLR(connection, &OutputPending);
+#ifndef LBX
+ xfree(oc);
+#endif
+}
+
+/*****************
+ * CheckConections
+ * Some connection has died, go find which one and shut it down
+ * The file descriptor has been closed, but is still in AllClients.
+ * If would truly be wonderful if select() would put the bogus
+ * file descriptors in the exception mask, but nooooo. So we have
+ * to check each and every socket individually.
+ *****************/
+
+void
+CheckConnections()
+{
+#ifndef WIN32
+ fd_mask mask;
+#endif
+ fd_set tmask;
+ register int curclient, curoff;
+ int i;
+ struct timeval notime;
+ int r;
+#ifdef WIN32
+ fd_set savedAllClients;
+#endif
+
+ notime.tv_sec = 0;
+ notime.tv_usec = 0;
+
+#ifndef WIN32
+ for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
+ {
+ mask = AllClients.fds_bits[i];
+ while (mask)
+ {
+ curoff = ffs (mask) - 1;
+ curclient = curoff + (i << 5);
+ FD_ZERO(&tmask);
+ FD_SET(curclient, &tmask);
+ r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
+ if (r < 0)
+ CloseDownClient(clients[ConnectionTranslation[curclient]]);
+ mask &= ~(1 << curoff);
+ }
+ }
+#else
+ XFD_COPYSET(&AllClients, &savedAllClients);
+ for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++)
+ {
+ curclient = XFD_FD(&savedAllClients, i);
+ FD_ZERO(&tmask);
+ FD_SET(curclient, &tmask);
+ r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
+ if (r < 0)
+ CloseDownClient(clients[ConnectionTranslation[curclient]]);
+ }
+#endif
+}
+
+
+/*****************
+ * CloseDownConnection
+ * Delete client from AllClients and free resources
+ *****************/
+
+void
+CloseDownConnection(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+
+ if (oc->output && oc->output->count)
+ FlushClient(client, oc, (char *)NULL, 0);
+#ifdef XDMCP
+ XdmcpCloseDisplay(oc->fd);
+#endif
+#ifndef LBX
+ CloseDownFileDescriptor(oc);
+#else
+ (*oc->Close) (client);
+ FreeOsBuffers(oc);
+ xfree(oc);
+#endif
+ client->osPrivate = (pointer)NULL;
+ if (auditTrailLevel > 1)
+ AuditF("client %d disconnected\n", client->index);
+}
+
+
+AddEnabledDevice(fd)
+ int fd;
+{
+ FD_SET(fd, &EnabledDevices);
+ FD_SET(fd, &AllSockets);
+}
+
+
+RemoveEnabledDevice(fd)
+ int fd;
+{
+ FD_CLR(fd, &EnabledDevices);
+ FD_CLR(fd, &AllSockets);
+}
+
+/*****************
+ * OnlyListenToOneClient:
+ * Only accept requests from one client. Continue to handle new
+ * connections, but don't take any protocol requests from the new
+ * ones. Note that if GrabInProgress is set, EstablishNewConnections
+ * needs to put new clients into SavedAllSockets and SavedAllClients.
+ * Note also that there is no timeout for this in the protocol.
+ * This routine is "undone" by ListenToAllClients()
+ *****************/
+
+OnlyListenToOneClient(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ if (! GrabInProgress)
+ {
+ XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
+ XFD_ANDSET(&ClientsWithInput,
+ &ClientsWithInput, &GrabImperviousClients);
+ if (FD_ISSET(connection, &SavedClientsWithInput))
+ {
+ FD_CLR(connection, &SavedClientsWithInput);
+ FD_SET(connection, &ClientsWithInput);
+ }
+ XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
+ XFD_COPYSET(&AllSockets, &SavedAllSockets);
+ XFD_COPYSET(&AllClients, &SavedAllClients);
+ XFD_UNSET(&AllSockets, &AllClients);
+ XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
+ FD_SET(connection, &AllClients);
+ XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
+ GrabInProgress = client->index;
+ }
+}
+
+/****************
+ * ListenToAllClients:
+ * Undoes OnlyListentToOneClient()
+ ****************/
+
+ListenToAllClients()
+{
+ if (GrabInProgress)
+ {
+ XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
+ XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
+ XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
+ GrabInProgress = 0;
+ }
+}
+
+/****************
+ * IgnoreClient
+ * Removes one client from input masks.
+ * Must have cooresponding call to AttendClient.
+ ****************/
+
+IgnoreClient (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+#ifdef LBX
+ LbxClientPtr lbxClient = LbxClient(client);
+#endif
+
+ isItTimeToYield = TRUE;
+#ifdef LBX
+ if (lbxClient) {
+ lbxClient->ignored = TRUE;
+ return;
+ }
+#endif
+ if (!GrabInProgress || FD_ISSET(connection, &AllClients))
+ {
+ if (FD_ISSET (connection, &ClientsWithInput))
+ FD_SET(connection, &IgnoredClientsWithInput);
+ else
+ FD_CLR(connection, &IgnoredClientsWithInput);
+ FD_CLR(connection, &ClientsWithInput);
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ FD_CLR(connection, &LastSelectMask);
+ }
+ else
+ {
+ if (FD_ISSET (connection, &SavedClientsWithInput))
+ FD_SET(connection, &IgnoredClientsWithInput);
+ else
+ FD_CLR(connection, &IgnoredClientsWithInput);
+ FD_CLR(connection, &SavedClientsWithInput);
+ FD_CLR(connection, &SavedAllSockets);
+ FD_CLR(connection, &SavedAllClients);
+ }
+}
+
+/****************
+ * AttendClient
+ * Adds one client back into the input masks.
+ ****************/
+
+AttendClient (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+#ifdef LBX
+ LbxClientPtr lbxClient = LbxClient(client);
+
+ if (lbxClient) {
+ lbxClient->ignored = FALSE;
+ return;
+ }
+#endif
+ if (!GrabInProgress || GrabInProgress == client->index ||
+ FD_ISSET(connection, &GrabImperviousClients))
+ {
+ FD_SET(connection, &AllClients);
+ FD_SET(connection, &AllSockets);
+ FD_SET(connection, &LastSelectMask);
+ if (FD_ISSET (connection, &IgnoredClientsWithInput))
+ FD_SET(connection, &ClientsWithInput);
+ }
+ else
+ {
+ FD_SET(connection, &SavedAllClients);
+ FD_SET(connection, &SavedAllSockets);
+ if (FD_ISSET(connection, &IgnoredClientsWithInput))
+ FD_SET(connection, &SavedClientsWithInput);
+ }
+}
+
+/* make client impervious to grabs; assume only executing client calls this */
+
+MakeClientGrabImpervious(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ FD_SET(connection, &GrabImperviousClients);
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = CLIENT_IMPERVIOUS;
+ CallCallbacks(&ServerGrabCallback, &grabinfo);
+ }
+}
+
+/* make client pervious to grabs; assume only executing client calls this */
+
+MakeClientGrabPervious(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ FD_CLR(connection, &GrabImperviousClients);
+ if (GrabInProgress && (GrabInProgress != client->index))
+ {
+ if (FD_ISSET(connection, &ClientsWithInput))
+ {
+ FD_SET(connection, &SavedClientsWithInput);
+ FD_CLR(connection, &ClientsWithInput);
+ }
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ isItTimeToYield = TRUE;
+ }
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = CLIENT_PERVIOUS;
+ CallCallbacks(&ServerGrabCallback, &grabinfo);
+ }
+}
+
+#ifdef AIXV3
+
+static fd_set pendingActiveClients;
+static BOOL reallyGrabbed;
+
+/****************
+* DontListenToAnybody:
+* Don't listen to requests from any clients. Continue to handle new
+* connections, but don't take any protocol requests from anybody.
+* We have to take care if there is already a grab in progress, though.
+* Undone by PayAttentionToClientsAgain. We also have to be careful
+* not to accept any more input from the currently dispatched client.
+* we do this be telling dispatch it is time to yield.
+
+* We call this when the server loses access to the glass
+* (user hot-keys away). This looks like a grab by the
+* server itself, but gets a little tricky if there is already
+* a grab in progress.
+******************/
+
+void
+DontListenToAnybody()
+{
+ if (!GrabInProgress)
+ {
+ XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
+ XFD_COPYSET(&AllSockets, &SavedAllSockets);
+ XFD_COPYSET(&AllClients, &SavedAllClients);
+ GrabInProgress = TRUE;
+ reallyGrabbed = FALSE;
+ }
+ else
+ {
+ XFD_COPYSET(&AllClients, &pendingActiveClients);
+ reallyGrabbed = TRUE;
+ }
+ FD_ZERO(&ClientsWithInput);
+ XFD_UNSET(&AllSockets, &AllClients);
+ FD_ZERO(&AllClients);
+ isItTimeToYield = TRUE;
+}
+
+void
+PayAttentionToClientsAgain()
+{
+ if (reallyGrabbed)
+ {
+ XFD_ORSET(&AllSockets, &AllSockets, &pendingActiveClients);
+ XFD_ORSET(&AllClients, &AllClients, &pendingActiveClients);
+ }
+ else
+ {
+ ListenToAllClients();
+ }
+ reallyGrabbed = FALSE;
+}
+
+#endif