1 /***********************************************************
3 Copyright 1987, 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 ******************************************************************/
46 /*****************************************************************
47 * Stuff to create connections --- OS dependent
49 * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
50 * CloseDownConnection, CheckConnections, AddEnabledDevice,
51 * RemoveEnabledDevice, OnlyListToOneClient,
54 * (WaitForSomething is in its own file)
56 * In this implementation, a client socket table is not kept.
57 * Instead, what would be the index into the table is just the
58 * file descriptor of the socket. This won't work for if the
59 * socket ids aren't small nums (0 - 2^8)
61 *****************************************************************/
63 #ifdef HAVE_DIX_CONFIG_H
64 #include <dix-config.h>
68 #include <X11/Xwinsock.h>
71 #include <X11/Xproto.h>
75 #include <X11/Xtrans/Xtrans.h>
76 #include <X11/Xtrans/Xtransint.h>
83 #include <sys/socket.h>
85 #if defined(TCPCONN) || defined(STREAMSCONN)
86 #include <netinet/in.h>
87 #include <arpa/inet.h>
90 #include <netinet/tcp.h>
94 #include <sys/param.h>
96 #include <netinet/tcp.h>
98 #include <arpa/inet.h>
104 #include "misc.h" /* for typedef of pointer */
106 #include <X11/Xpoll.h>
108 #include "dixstruct.h"
113 #ifdef HAVE_GETPEERUCRED
118 #ifdef XSERVER_DTRACE
119 #include <sys/types.h>
120 typedef const char *string;
122 #ifndef HAVE_GETPEERUCRED
125 #include "../dix/Xserver-dtrace.h"
128 static int lastfdesc; /* maximum file descriptor */
130 fd_set WellKnownConnections; /* Listener mask */
131 fd_set EnabledDevices; /* mask for input devices that are on */
132 fd_set AllSockets; /* select on this */
133 fd_set AllClients; /* available clients */
134 fd_set LastSelectMask; /* mask returned from last select call */
135 fd_set ClientsWithInput; /* clients with FULL requests in buffer */
136 fd_set ClientsWriteBlocked; /* clients who cannot receive output */
137 fd_set OutputPending; /* clients with reply/event data ready to go */
139 Bool NewOutputPending; /* not yet attempted to write some new output */
140 Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
142 static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
143 Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or
144 equivalent) will send SIGCONT back. */
145 static char dynamic_display[7]; /* display name */
146 Bool PartialNetwork; /* continue even if unable to bind all addrs */
147 static Pid_t ParentProcess;
149 static Bool debug_conns = FALSE;
151 fd_set IgnoredClientsWithInput;
152 static fd_set GrabImperviousClients;
153 static fd_set SavedAllClients;
154 static fd_set SavedAllSockets;
155 static fd_set SavedClientsWithInput;
156 int GrabInProgress = 0;
159 int *ConnectionTranslation = NULL;
162 * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
163 * not even a known maximum value, so use something quite arbitrary for now.
164 * Do storage is a hash table of size 256. Collisions are handled in a linked
171 #ifdef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
172 #define MAXSELECT 1024
174 #define MAXSELECT 500
178 struct _ct_node *next;
183 struct _ct_node *ct_head[256];
186 InitConnectionTranslation(void)
188 memset(ct_head, 0, sizeof(ct_head));
192 GetConnectionTranslation(int conn)
194 struct _ct_node *node = ct_head[conn & 0xff];
196 while (node != NULL) {
197 if (node->key == conn)
205 SetConnectionTranslation(int conn, int client)
207 struct _ct_node **node = ct_head + (conn & 0xff);
209 if (client == 0) { /* remove entry */
210 while (*node != NULL) {
211 if ((*node)->key == conn) {
212 struct _ct_node *temp = *node;
214 *node = (*node)->next;
218 node = &((*node)->next);
223 while (*node != NULL) {
224 if ((*node)->key == conn) {
225 (*node)->value = client;
228 node = &((*node)->next);
230 *node = malloc(sizeof(struct _ct_node));
231 (*node)->next = NULL;
233 (*node)->value = client;
239 ClearConnectionTranslation(void)
243 for (i = 0; i < 256; i++) {
244 struct _ct_node *node = ct_head[i];
246 while (node != NULL) {
247 struct _ct_node *temp = node;
256 static XtransConnInfo *ListenTransConns = NULL;
257 static int *ListenTransFds = NULL;
258 static int ListenTransCount;
260 static void ErrorConnMax(XtransConnInfo /* trans_conn */ );
262 static XtransConnInfo
263 lookup_trans_conn(int fd)
265 if (ListenTransFds) {
268 for (i = 0; i < ListenTransCount; i++)
269 if (ListenTransFds[i] == fd)
270 return ListenTransConns[i];
276 /* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */
279 InitConnectionLimits(void)
285 #if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
286 lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
289 #ifdef HAVE_GETDTABLESIZE
291 lastfdesc = getdtablesize() - 1;
296 lastfdesc = _NFILE - 1;
299 #endif /* __CYGWIN__ */
301 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
302 /* This is the fallback */
304 lastfdesc = MAXSOCKS;
306 if (lastfdesc > MAXSELECT)
307 lastfdesc = MAXSELECT;
309 if (lastfdesc > MAXCLIENTS) {
310 lastfdesc = MAXCLIENTS;
312 ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS);
314 MaxClients = lastfdesc;
316 lastfdesc = MAXSELECT;
317 MaxClients = MAXCLIENTS;
321 ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
325 if (!ConnectionTranslation)
326 ConnectionTranslation = (int *) xnfalloc(sizeof(int) * (lastfdesc + 1));
328 InitConnectionTranslation();
333 * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
335 * a- The parent process is ignoring SIGUSR1
339 * b- The parent process is expecting a SIGUSR1
340 * when the server is ready to accept connections
342 * In the first case, the signal will be harmless, in the second case,
343 * the signal will be quite useful.
346 InitParentProcess(void)
349 OsSigHandlerPtr handler;
351 handler = OsSignal(SIGUSR1, SIG_IGN);
352 if (handler == SIG_IGN)
353 RunFromSmartParent = TRUE;
354 OsSignal(SIGUSR1, handler);
355 ParentProcess = getppid();
360 NotifyParentProcess(void)
363 if (dynamic_display[0]) {
364 write(displayfd, dynamic_display, strlen(dynamic_display));
365 write(displayfd, "\n", 1);
368 if (RunFromSmartParent) {
369 if (ParentProcess > 1) {
370 kill(ParentProcess, SIGUSR1);
373 if (RunFromSigStopParent)
379 TryCreateSocket(int num, int *partial)
383 snprintf(port, sizeof(port), "%d", num);
385 return (_XSERVTransMakeAllCOTSServerListeners(port, partial,
387 &ListenTransConns) >= 0);
391 * CreateWellKnownSockets
392 * At initialization, create the sockets to listen on for new clients.
396 CreateWellKnownSockets(void)
401 FD_ZERO(&AllSockets);
402 FD_ZERO(&AllClients);
403 FD_ZERO(&LastSelectMask);
404 FD_ZERO(&ClientsWithInput);
407 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
408 for (i = 0; i < MaxClients; i++)
410 for (i = 0; i < lastfdesc; i++)
412 ConnectionTranslation[i] = 0;
414 ClearConnectionTranslation();
417 FD_ZERO(&WellKnownConnections);
419 /* display is initialized to "0" by main(). It is then set to the display
420 * number if specified on the command line, or to NULL when the -displayfd
423 if (TryCreateSocket(atoi(display), &partial) &&
424 ListenTransCount >= 1)
425 if (!PartialNetwork && partial)
426 FatalError ("Failed to establish all listening sockets");
428 else { /* -displayfd */
430 for (i = 0; i < 65535 - X_TCP_PORT; i++) {
431 if (TryCreateSocket(i, &partial) && !partial) {
436 CloseWellKnownConnections();
439 FatalError("Failed to find a socket to listen on");
440 snprintf(dynamic_display, sizeof(dynamic_display), "%d", i);
441 display = dynamic_display;
444 ListenTransFds = malloc(ListenTransCount * sizeof (int));
446 for (i = 0; i < ListenTransCount; i++) {
447 int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
449 ListenTransFds[i] = fd;
450 FD_SET(fd, &WellKnownConnections);
452 if (!_XSERVTransIsLocal(ListenTransConns[i]))
456 if (!XFD_ANYSET(&WellKnownConnections))
458 ("Cannot establish any listening sockets - Make sure an X server isn't already running");
460 OsSignal(SIGPIPE, SIG_IGN);
461 OsSignal(SIGHUP, AutoResetServer);
463 OsSignal(SIGINT, GiveUp);
464 OsSignal(SIGTERM, GiveUp);
465 XFD_COPYSET(&WellKnownConnections, &AllSockets);
476 ResetWellKnownSockets(void)
482 for (i = 0; i < ListenTransCount; i++) {
483 int status = _XSERVTransResetListener(ListenTransConns[i]);
485 if (status != TRANS_RESET_NOOP) {
486 if (status == TRANS_RESET_FAILURE) {
488 * ListenTransConns[i] freed by xtrans.
489 * Remove it from out list.
492 FD_CLR(ListenTransFds[i], &WellKnownConnections);
493 ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
494 ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
495 ListenTransCount -= 1;
498 else if (status == TRANS_RESET_NEW_FD) {
500 * A new file descriptor was allocated (the old one was closed)
503 int newfd = _XSERVTransGetConnectionNumber(ListenTransConns[i]);
505 FD_CLR(ListenTransFds[i], &WellKnownConnections);
506 ListenTransFds[i] = newfd;
507 FD_SET(newfd, &WellKnownConnections);
512 ResetAuthorization();
523 CloseWellKnownConnections(void)
527 for (i = 0; i < ListenTransCount; i++)
528 _XSERVTransClose(ListenTransConns[i]);
532 AuthAudit(ClientPtr client, Bool letin,
533 struct sockaddr *saddr, int len,
534 unsigned int proto_n, char *auth_proto, int auth_id)
537 char client_uid_string[64];
538 LocalClientCredRec *lcc;
540 #ifdef XSERVER_DTRACE
541 pid_t client_pid = -1;
542 zoneid_t client_zid = -1;
546 strlcpy(addr, "local host", sizeof(addr));
548 switch (saddr->sa_family) {
550 #if defined(UNIXCONN) || defined(LOCALCONN)
553 strlcpy(addr, "local host", sizeof(addr));
555 #if defined(TCPCONN) || defined(STREAMSCONN)
557 snprintf(addr, sizeof(addr), "IP %s",
558 inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
560 #if defined(IPv6) && defined(AF_INET6)
562 char ipaddr[INET6_ADDRSTRLEN];
564 inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
565 ipaddr, sizeof(ipaddr));
566 snprintf(addr, sizeof(addr), "IP %s", ipaddr);
572 strlcpy(addr, "unknown address", sizeof(addr));
575 if (GetLocalClientCreds(client, &lcc) != -1) {
576 int slen; /* length written to client_uid_string */
578 strcpy(client_uid_string, " ( ");
581 if (lcc->fieldsSet & LCC_UID_SET) {
582 snprintf(client_uid_string + slen,
583 sizeof(client_uid_string) - slen,
584 "uid=%ld ", (long) lcc->euid);
585 slen = strlen(client_uid_string);
588 if (lcc->fieldsSet & LCC_GID_SET) {
589 snprintf(client_uid_string + slen,
590 sizeof(client_uid_string) - slen,
591 "gid=%ld ", (long) lcc->egid);
592 slen = strlen(client_uid_string);
595 if (lcc->fieldsSet & LCC_PID_SET) {
596 #ifdef XSERVER_DTRACE
597 client_pid = lcc->pid;
599 snprintf(client_uid_string + slen,
600 sizeof(client_uid_string) - slen,
601 "pid=%ld ", (long) lcc->pid);
602 slen = strlen(client_uid_string);
605 if (lcc->fieldsSet & LCC_ZID_SET) {
606 #ifdef XSERVER_DTRACE
607 client_zid = lcc->zoneid;
609 snprintf(client_uid_string + slen,
610 sizeof(client_uid_string) - slen,
611 "zoneid=%ld ", (long) lcc->zoneid);
612 slen = strlen(client_uid_string);
615 snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
617 FreeLocalClientCreds(lcc);
620 client_uid_string[0] = '\0';
623 #ifdef XSERVER_DTRACE
624 XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
626 if (auditTrailLevel > 1) {
628 AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n",
629 client->index, letin ? "connected" : "rejected", addr,
630 client_uid_string, (int) proto_n, auth_proto, auth_id);
632 AuditF("client %d %s from %s%s\n",
633 client->index, letin ? "connected" : "rejected", addr,
640 AuthorizationIDOfClient(ClientPtr client)
642 if (client->osPrivate)
643 return ((OsCommPtr) client->osPrivate)->auth_id;
648 /*****************************************************************
651 * Sent by the client at connection setup:
652 * typedef struct _xConnClientPrefix {
655 * CARD16 majorVersion, minorVersion;
656 * CARD16 nbytesAuthProto;
657 * CARD16 nbytesAuthString;
658 * } xConnClientPrefix;
660 * It is hoped that eventually one protocol will be agreed upon. In the
661 * mean time, a server that implements a different protocol than the
662 * client expects, or a server that only implements the host-based
663 * mechanism, will simply ignore this information.
665 *****************************************************************/
668 ClientAuthorized(ClientPtr client,
669 unsigned int proto_n, char *auth_proto,
670 unsigned int string_n, char *auth_string)
673 Xtransaddr *from = NULL;
677 const char *reason = NULL;
678 XtransConnInfo trans_conn;
680 priv = (OsCommPtr) client->osPrivate;
681 trans_conn = priv->trans_conn;
683 /* Allow any client to connect without authorization on a launchd socket,
684 because it is securely created -- this prevents a race condition on launch */
685 if (trans_conn->flags & TRANS_NOXAUTH) {
690 CheckAuthorization(proto_n, auth_proto, string_n, auth_string,
694 if (auth_id == (XID) ~0L) {
695 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
696 if (InvalidHost((struct sockaddr *) from, fromlen, client))
697 AuthAudit(client, FALSE, (struct sockaddr *) from,
698 fromlen, proto_n, auth_proto, auth_id);
701 #ifdef XSERVER_DTRACE
702 if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
704 if (auditTrailLevel > 1)
706 AuthAudit(client, TRUE,
707 (struct sockaddr *) from, fromlen,
708 proto_n, auth_proto, auth_id);
714 if (auth_id == (XID) ~0L) {
718 return "Client is not authorized to connect to Server";
721 #ifdef XSERVER_DTRACE
722 else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
724 else if (auditTrailLevel > 1)
727 if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) {
728 AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
729 proto_n, auth_proto, auth_id);
734 priv->auth_id = auth_id;
738 /* indicate to Xdmcp protocol that we've opened new client */
739 XdmcpOpenDisplay(priv->fd);
742 XaceHook(XACE_AUTH_AVAIL, client, auth_id);
744 /* At this point, if the client is authorized to change the access control
745 * list, we should getpeername() information, and add the client to
746 * the selfhosts list. It's not really the host machine, but the
747 * true purpose of the selfhosts list is to see who may change the
748 * access control list.
750 return ((char *) NULL);
754 AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
763 XFD_SETCOUNT(&AllClients) >= MaxClients
767 oc = malloc(sizeof(OsCommRec));
770 oc->trans_conn = trans_conn;
772 oc->input = (ConnectionInputPtr) NULL;
773 oc->output = (ConnectionOutputPtr) NULL;
775 oc->conn_time = conn_time;
776 if (!(client = NextAvailableClient((pointer) oc))) {
780 oc->local_client = ComputeLocalClient(client);
782 ConnectionTranslation[fd] = client->index;
784 SetConnectionTranslation(fd, client->index);
786 if (GrabInProgress) {
787 FD_SET(fd, &SavedAllClients);
788 FD_SET(fd, &SavedAllSockets);
791 FD_SET(fd, &AllClients);
792 FD_SET(fd, &AllSockets);
796 ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
799 #ifdef XSERVER_DTRACE
800 XSERVER_CLIENT_CONNECT(client->index, fd);
807 * EstablishNewConnections
808 * If anyone is waiting on listened sockets, accept them.
809 * Returns a mask with indices of new clients. Updates AllClients
814 EstablishNewConnections(ClientPtr clientUnused, pointer closure)
816 fd_set readyconnections; /* set of listeners that are ready */
817 int curconn; /* fd of listener that's ready */
818 register int newconn; /* fd of new client */
821 register ClientPtr client;
822 register OsCommPtr oc;
825 XFD_ANDSET(&tmask, (fd_set *) closure, &WellKnownConnections);
826 XFD_COPYSET(&tmask, &readyconnections);
827 if (!XFD_ANYSET(&readyconnections))
829 connect_time = GetTimeInMillis();
830 /* kill off stragglers */
831 for (i = 1; i < currentMaxClients; i++) {
832 if ((client = clients[i])) {
833 oc = (OsCommPtr) (client->osPrivate);
834 if ((oc && (oc->conn_time != 0) &&
835 (connect_time - oc->conn_time) >= TimeOutValue) ||
836 (client->noClientException != Success && !client->clientGone))
837 CloseDownClient(client);
841 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
842 while (readyconnections.fds_bits[i])
844 for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
847 XtransConnInfo trans_conn, new_trans_conn;
851 curconn = mffs(readyconnections.fds_bits[i]) - 1;
852 readyconnections.fds_bits[i] &= ~((fd_mask) 1 << curconn);
853 curconn += (i * (sizeof(fd_mask) * 8));
855 curconn = XFD_FD(&readyconnections, i);
858 if ((trans_conn = lookup_trans_conn(curconn)) == NULL)
861 if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL)
864 newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
866 if (newconn < lastfdesc) {
870 clientid = ConnectionTranslation[newconn];
872 clientid = GetConnectionTranslation(newconn);
874 if (clientid && (client = clients[clientid]))
875 CloseDownClient(client);
878 _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
880 if (trans_conn->flags & TRANS_NOXAUTH)
881 new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
883 if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) {
884 ErrorConnMax(new_trans_conn);
885 _XSERVTransClose(new_trans_conn);
894 #define NOROOM "Maximum number of clients reached"
898 * Fail a connection due to lack of client or file descriptor space
901 #define BOTIMEOUT 200 /* in milliseconds */
904 ErrorConnMax(XtransConnInfo trans_conn)
906 int fd = _XSERVTransGetConnectionNumber(trans_conn);
907 xConnSetupPrefix csp;
908 char pad[3] = { 0, 0, 0 };
912 struct timeval waittime;
915 /* if these seems like a lot of trouble to go to, it probably is */
916 waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
917 waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
918 (1000000 / MILLI_PER_SECOND);
921 (void) Select(fd + 1, &mask, NULL, NULL, &waittime);
922 /* try to read the byte-order of the connection */
923 (void) _XSERVTransRead(trans_conn, &byteOrder, 1);
924 if ((byteOrder == 'l') || (byteOrder == 'B')) {
925 csp.success = xFalse;
926 csp.lengthReason = sizeof(NOROOM) - 1;
927 csp.length = (sizeof(NOROOM) + 2) >> 2;
928 csp.majorVersion = X_PROTOCOL;
929 csp.minorVersion = X_PROTOCOL_REVISION;
930 if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
931 (!(*(char *) &whichbyte) && (byteOrder == 'l'))) {
932 swaps(&csp.majorVersion);
933 swaps(&csp.minorVersion);
936 iov[0].iov_len = sz_xConnSetupPrefix;
937 iov[0].iov_base = (char *) &csp;
938 iov[1].iov_len = csp.lengthReason;
939 iov[1].iov_base = NOROOM;
940 iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
941 iov[2].iov_base = pad;
942 (void) _XSERVTransWritev(trans_conn, iov, 3);
947 * CloseDownFileDescriptor:
948 * Remove this file descriptor and it's I/O buffers, etc.
952 CloseDownFileDescriptor(OsCommPtr oc)
954 int connection = oc->fd;
956 if (oc->trans_conn) {
957 _XSERVTransDisconnect(oc->trans_conn);
958 _XSERVTransClose(oc->trans_conn);
961 ConnectionTranslation[connection] = 0;
963 SetConnectionTranslation(connection, 0);
965 FD_CLR(connection, &AllSockets);
966 FD_CLR(connection, &AllClients);
967 FD_CLR(connection, &ClientsWithInput);
968 FD_CLR(connection, &GrabImperviousClients);
969 if (GrabInProgress) {
970 FD_CLR(connection, &SavedAllSockets);
971 FD_CLR(connection, &SavedAllClients);
972 FD_CLR(connection, &SavedClientsWithInput);
974 FD_CLR(connection, &ClientsWriteBlocked);
975 if (!XFD_ANYSET(&ClientsWriteBlocked))
976 AnyClientsWriteBlocked = FALSE;
977 FD_CLR(connection, &OutputPending);
982 * Some connection has died, go find which one and shut it down
983 * The file descriptor has been closed, but is still in AllClients.
984 * If would truly be wonderful if select() would put the bogus
985 * file descriptors in the exception mask, but nooooo. So we have
986 * to check each and every socket individually.
990 CheckConnections(void)
996 int curclient, curoff;
998 struct timeval notime;
1002 fd_set savedAllClients;
1009 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
1010 mask = AllClients.fds_bits[i];
1012 curoff = mffs(mask) - 1;
1013 curclient = curoff + (i * (sizeof(fd_mask) * 8));
1015 FD_SET(curclient, &tmask);
1017 r = Select(curclient + 1, &tmask, NULL, NULL, ¬ime);
1018 } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1020 if (ConnectionTranslation[curclient] > 0)
1021 CloseDownClient(clients[ConnectionTranslation[curclient]]);
1022 mask &= ~((fd_mask) 1 << curoff);
1026 XFD_COPYSET(&AllClients, &savedAllClients);
1027 for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) {
1028 curclient = XFD_FD(&savedAllClients, i);
1030 FD_SET(curclient, &tmask);
1032 r = Select(curclient + 1, &tmask, NULL, NULL, ¬ime);
1033 } while (r < 0 && (errno == EINTR || errno == EAGAIN));
1035 if (GetConnectionTranslation(curclient) > 0)
1036 CloseDownClient(clients[GetConnectionTranslation(curclient)]);
1042 * CloseDownConnection
1043 * Delete client from AllClients and free resources
1047 CloseDownConnection(ClientPtr client)
1049 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1052 CallCallbacks(&FlushCallback, NULL);
1054 if (oc->output && oc->output->count)
1055 FlushClient(client, oc, (char *) NULL, 0);
1057 XdmcpCloseDisplay(oc->fd);
1059 CloseDownFileDescriptor(oc);
1061 free(client->osPrivate);
1062 client->osPrivate = (pointer) NULL;
1063 if (auditTrailLevel > 1)
1064 AuditF("client %d disconnected\n", client->index);
1068 AddGeneralSocket(int fd)
1070 FD_SET(fd, &AllSockets);
1072 FD_SET(fd, &SavedAllSockets);
1076 AddEnabledDevice(int fd)
1078 FD_SET(fd, &EnabledDevices);
1079 AddGeneralSocket(fd);
1083 RemoveGeneralSocket(int fd)
1085 FD_CLR(fd, &AllSockets);
1087 FD_CLR(fd, &SavedAllSockets);
1091 RemoveEnabledDevice(int fd)
1093 FD_CLR(fd, &EnabledDevices);
1094 RemoveGeneralSocket(fd);
1098 * OnlyListenToOneClient:
1099 * Only accept requests from one client. Continue to handle new
1100 * connections, but don't take any protocol requests from the new
1101 * ones. Note that if GrabInProgress is set, EstablishNewConnections
1102 * needs to put new clients into SavedAllSockets and SavedAllClients.
1103 * Note also that there is no timeout for this in the protocol.
1104 * This routine is "undone" by ListenToAllClients()
1108 OnlyListenToOneClient(ClientPtr client)
1110 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1111 int rc, connection = oc->fd;
1113 rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
1117 if (!GrabInProgress) {
1118 XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
1119 XFD_ANDSET(&ClientsWithInput,
1120 &ClientsWithInput, &GrabImperviousClients);
1121 if (FD_ISSET(connection, &SavedClientsWithInput)) {
1122 FD_CLR(connection, &SavedClientsWithInput);
1123 FD_SET(connection, &ClientsWithInput);
1125 XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
1126 XFD_COPYSET(&AllSockets, &SavedAllSockets);
1127 XFD_COPYSET(&AllClients, &SavedAllClients);
1128 XFD_UNSET(&AllSockets, &AllClients);
1129 XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
1130 FD_SET(connection, &AllClients);
1131 XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
1132 GrabInProgress = client->index;
1138 * ListenToAllClients:
1139 * Undoes OnlyListentToOneClient()
1143 ListenToAllClients(void)
1145 if (GrabInProgress) {
1146 XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
1147 XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
1148 XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
1155 * Removes one client from input masks.
1156 * Must have cooresponding call to AttendClient.
1160 IgnoreClient(ClientPtr client)
1162 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1163 int connection = oc->fd;
1165 client->ignoreCount++;
1166 if (client->ignoreCount > 1)
1169 isItTimeToYield = TRUE;
1170 if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
1171 if (FD_ISSET(connection, &ClientsWithInput))
1172 FD_SET(connection, &IgnoredClientsWithInput);
1174 FD_CLR(connection, &IgnoredClientsWithInput);
1175 FD_CLR(connection, &ClientsWithInput);
1176 FD_CLR(connection, &AllSockets);
1177 FD_CLR(connection, &AllClients);
1178 FD_CLR(connection, &LastSelectMask);
1181 if (FD_ISSET(connection, &SavedClientsWithInput))
1182 FD_SET(connection, &IgnoredClientsWithInput);
1184 FD_CLR(connection, &IgnoredClientsWithInput);
1185 FD_CLR(connection, &SavedClientsWithInput);
1186 FD_CLR(connection, &SavedAllSockets);
1187 FD_CLR(connection, &SavedAllClients);
1193 * Adds one client back into the input masks.
1197 AttendClient(ClientPtr client)
1199 #ifdef _F_CHECK_NULL_CLIENT_
1203 if (client == NULL ||client->osPrivate == NULL)
1206 oc = (OsCommPtr)client->osPrivate;
1207 connection = oc->fd;
1209 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1210 int connection = oc->fd;
1212 client->ignoreCount--;
1213 if (client->ignoreCount)
1216 if (!GrabInProgress || GrabInProgress == client->index ||
1217 FD_ISSET(connection, &GrabImperviousClients)) {
1218 FD_SET(connection, &AllClients);
1219 FD_SET(connection, &AllSockets);
1220 FD_SET(connection, &LastSelectMask);
1221 if (FD_ISSET(connection, &IgnoredClientsWithInput))
1222 FD_SET(connection, &ClientsWithInput);
1225 FD_SET(connection, &SavedAllClients);
1226 FD_SET(connection, &SavedAllSockets);
1227 if (FD_ISSET(connection, &IgnoredClientsWithInput))
1228 FD_SET(connection, &SavedClientsWithInput);
1232 /* make client impervious to grabs; assume only executing client calls this */
1235 MakeClientGrabImpervious(ClientPtr client)
1237 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1238 int connection = oc->fd;
1240 FD_SET(connection, &GrabImperviousClients);
1242 if (ServerGrabCallback) {
1243 ServerGrabInfoRec grabinfo;
1245 grabinfo.client = client;
1246 grabinfo.grabstate = CLIENT_IMPERVIOUS;
1247 CallCallbacks(&ServerGrabCallback, &grabinfo);
1251 /* make client pervious to grabs; assume only executing client calls this */
1254 MakeClientGrabPervious(ClientPtr client)
1256 OsCommPtr oc = (OsCommPtr) client->osPrivate;
1257 int connection = oc->fd;
1259 FD_CLR(connection, &GrabImperviousClients);
1260 if (GrabInProgress && (GrabInProgress != client->index)) {
1261 if (FD_ISSET(connection, &ClientsWithInput)) {
1262 FD_SET(connection, &SavedClientsWithInput);
1263 FD_CLR(connection, &ClientsWithInput);
1265 FD_CLR(connection, &AllSockets);
1266 FD_CLR(connection, &AllClients);
1267 isItTimeToYield = TRUE;
1270 if (ServerGrabCallback) {
1271 ServerGrabInfoRec grabinfo;
1273 grabinfo.client = client;
1274 grabinfo.grabstate = CLIENT_PERVIOUS;
1275 CallCallbacks(&ServerGrabCallback, &grabinfo);
1280 /* Add a fd (from launchd) to our listeners */
1282 ListenOnOpenFD(int fd, int noxauth)
1285 XtransConnInfo ciptr;
1286 const char *display_env = getenv("DISPLAY");
1288 if (display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
1289 /* Make the path the launchd socket if our DISPLAY is set right */
1290 strcpy(port, display_env);
1293 /* Just some default so things don't break and die. */
1294 snprintf(port, sizeof(port), ":%d", atoi(display));
1297 /* Make our XtransConnInfo
1298 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
1300 ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
1301 if (ciptr == NULL) {
1302 ErrorF("Got NULL while trying to Reopen launchd port.\n");
1307 ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
1309 /* Allocate space to store it */
1311 (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof(int));
1313 (XtransConnInfo *) realloc(ListenTransConns,
1315 1) * sizeof(XtransConnInfo));
1318 ListenTransConns[ListenTransCount] = ciptr;
1319 ListenTransFds[ListenTransCount] = fd;
1321 FD_SET(fd, &WellKnownConnections);
1322 FD_SET(fd, &AllSockets);
1324 /* Increment the count */
1327 /* This *might* not be needed... /shrug */
1328 ResetAuthorization();
1329 ResetHosts(display);