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 #define MAXSELECT 500
174 struct _ct_node
*next
;
179 struct _ct_node
*ct_head
[256];
182 InitConnectionTranslation(void)
184 memset(ct_head
, 0, sizeof(ct_head
));
188 GetConnectionTranslation(int conn
)
190 struct _ct_node
*node
= ct_head
[conn
& 0xff];
192 while (node
!= NULL
) {
193 if (node
->key
== conn
)
201 SetConnectionTranslation(int conn
, int client
)
203 struct _ct_node
**node
= ct_head
+ (conn
& 0xff);
205 if (client
== 0) { /* remove entry */
206 while (*node
!= NULL
) {
207 if ((*node
)->key
== conn
) {
208 struct _ct_node
*temp
= *node
;
210 *node
= (*node
)->next
;
214 node
= &((*node
)->next
);
219 while (*node
!= NULL
) {
220 if ((*node
)->key
== conn
) {
221 (*node
)->value
= client
;
224 node
= &((*node
)->next
);
226 *node
= malloc(sizeof(struct _ct_node
));
227 (*node
)->next
= NULL
;
229 (*node
)->value
= client
;
235 ClearConnectionTranslation(void)
239 for (i
= 0; i
< 256; i
++) {
240 struct _ct_node
*node
= ct_head
[i
];
242 while (node
!= NULL
) {
243 struct _ct_node
*temp
= node
;
252 static XtransConnInfo
*ListenTransConns
= NULL
;
253 static int *ListenTransFds
= NULL
;
254 static int ListenTransCount
;
256 static void ErrorConnMax(XtransConnInfo
/* trans_conn */ );
258 static XtransConnInfo
259 lookup_trans_conn(int fd
)
261 if (ListenTransFds
) {
264 for (i
= 0; i
< ListenTransCount
; i
++)
265 if (ListenTransFds
[i
] == fd
)
266 return ListenTransConns
[i
];
272 /* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */
275 InitConnectionLimits(void)
281 #if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
282 lastfdesc
= sysconf(_SC_OPEN_MAX
) - 1;
285 #ifdef HAVE_GETDTABLESIZE
287 lastfdesc
= getdtablesize() - 1;
292 lastfdesc
= _NFILE
- 1;
295 #endif /* __CYGWIN__ */
297 /* This is the fallback */
299 lastfdesc
= MAXSOCKS
;
301 if (lastfdesc
> MAXSELECT
)
302 lastfdesc
= MAXSELECT
;
304 if (lastfdesc
> MAXCLIENTS
) {
305 lastfdesc
= MAXCLIENTS
;
307 ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS
);
309 MaxClients
= lastfdesc
;
312 ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients
);
316 if (!ConnectionTranslation
)
317 ConnectionTranslation
= (int *) xnfalloc(sizeof(int) * (lastfdesc
+ 1));
319 InitConnectionTranslation();
324 * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
326 * a- The parent process is ignoring SIGUSR1
330 * b- The parent process is expecting a SIGUSR1
331 * when the server is ready to accept connections
333 * In the first case, the signal will be harmless, in the second case,
334 * the signal will be quite useful.
337 InitParentProcess(void)
340 OsSigHandlerPtr handler
;
342 handler
= OsSignal(SIGUSR1
, SIG_IGN
);
343 if (handler
== SIG_IGN
)
344 RunFromSmartParent
= TRUE
;
345 OsSignal(SIGUSR1
, handler
);
346 ParentProcess
= getppid();
351 NotifyParentProcess(void)
354 if (dynamic_display
[0]) {
355 write(displayfd
, dynamic_display
, strlen(dynamic_display
));
356 write(displayfd
, "\n", 1);
359 if (RunFromSmartParent
) {
360 if (ParentProcess
> 1) {
361 kill(ParentProcess
, SIGUSR1
);
364 if (RunFromSigStopParent
)
370 TryCreateSocket(int num
, int *partial
)
374 snprintf(port
, sizeof(port
), "%d", num
);
376 return (_XSERVTransMakeAllCOTSServerListeners(port
, partial
,
378 &ListenTransConns
) >= 0);
382 * CreateWellKnownSockets
383 * At initialization, create the sockets to listen on for new clients.
387 CreateWellKnownSockets(void)
392 FD_ZERO(&AllSockets
);
393 FD_ZERO(&AllClients
);
394 FD_ZERO(&LastSelectMask
);
395 FD_ZERO(&ClientsWithInput
);
398 for (i
= 0; i
< MaxClients
; i
++)
399 ConnectionTranslation
[i
] = 0;
401 ClearConnectionTranslation();
404 FD_ZERO(&WellKnownConnections
);
406 /* display is initialized to "0" by main(). It is then set to the display
407 * number if specified on the command line, or to NULL when the -displayfd
410 if (TryCreateSocket(atoi(display
), &partial
) &&
411 ListenTransCount
>= 1)
412 if (!PartialNetwork
&& partial
)
413 FatalError ("Failed to establish all listening sockets");
415 else { /* -displayfd */
417 for (i
= 0; i
< 65535 - X_TCP_PORT
; i
++) {
418 if (TryCreateSocket(i
, &partial
) && !partial
) {
423 CloseWellKnownConnections();
426 FatalError("Failed to find a socket to listen on");
427 snprintf(dynamic_display
, sizeof(dynamic_display
), "%d", i
);
428 display
= dynamic_display
;
431 ListenTransFds
= malloc(ListenTransCount
* sizeof (int));
433 for (i
= 0; i
< ListenTransCount
; i
++) {
434 int fd
= _XSERVTransGetConnectionNumber(ListenTransConns
[i
]);
436 ListenTransFds
[i
] = fd
;
437 FD_SET(fd
, &WellKnownConnections
);
439 if (!_XSERVTransIsLocal(ListenTransConns
[i
]))
443 if (!XFD_ANYSET(&WellKnownConnections
))
445 ("Cannot establish any listening sockets - Make sure an X server isn't already running");
447 OsSignal(SIGPIPE
, SIG_IGN
);
448 OsSignal(SIGHUP
, AutoResetServer
);
450 OsSignal(SIGINT
, GiveUp
);
451 OsSignal(SIGTERM
, GiveUp
);
452 XFD_COPYSET(&WellKnownConnections
, &AllSockets
);
463 ResetWellKnownSockets(void)
469 for (i
= 0; i
< ListenTransCount
; i
++) {
470 int status
= _XSERVTransResetListener(ListenTransConns
[i
]);
472 if (status
!= TRANS_RESET_NOOP
) {
473 if (status
== TRANS_RESET_FAILURE
) {
475 * ListenTransConns[i] freed by xtrans.
476 * Remove it from out list.
479 FD_CLR(ListenTransFds
[i
], &WellKnownConnections
);
480 ListenTransFds
[i
] = ListenTransFds
[ListenTransCount
- 1];
481 ListenTransConns
[i
] = ListenTransConns
[ListenTransCount
- 1];
482 ListenTransCount
-= 1;
485 else if (status
== TRANS_RESET_NEW_FD
) {
487 * A new file descriptor was allocated (the old one was closed)
490 int newfd
= _XSERVTransGetConnectionNumber(ListenTransConns
[i
]);
492 FD_CLR(ListenTransFds
[i
], &WellKnownConnections
);
493 ListenTransFds
[i
] = newfd
;
494 FD_SET(newfd
, &WellKnownConnections
);
499 ResetAuthorization();
510 CloseWellKnownConnections(void)
514 for (i
= 0; i
< ListenTransCount
; i
++)
515 _XSERVTransClose(ListenTransConns
[i
]);
519 AuthAudit(ClientPtr client
, Bool letin
,
520 struct sockaddr
*saddr
, int len
,
521 unsigned int proto_n
, char *auth_proto
, int auth_id
)
524 char client_uid_string
[64];
525 LocalClientCredRec
*lcc
;
527 #ifdef XSERVER_DTRACE
528 pid_t client_pid
= -1;
529 zoneid_t client_zid
= -1;
533 strlcpy(addr
, "local host", sizeof(addr
));
535 switch (saddr
->sa_family
) {
537 #if defined(UNIXCONN) || defined(LOCALCONN)
540 strlcpy(addr
, "local host", sizeof(addr
));
542 #if defined(TCPCONN) || defined(STREAMSCONN)
544 snprintf(addr
, sizeof(addr
), "IP %s",
545 inet_ntoa(((struct sockaddr_in
*) saddr
)->sin_addr
));
547 #if defined(IPv6) && defined(AF_INET6)
549 char ipaddr
[INET6_ADDRSTRLEN
];
551 inet_ntop(AF_INET6
, &((struct sockaddr_in6
*) saddr
)->sin6_addr
,
552 ipaddr
, sizeof(ipaddr
));
553 snprintf(addr
, sizeof(addr
), "IP %s", ipaddr
);
559 strlcpy(addr
, "unknown address", sizeof(addr
));
562 if (GetLocalClientCreds(client
, &lcc
) != -1) {
563 int slen
; /* length written to client_uid_string */
565 strcpy(client_uid_string
, " ( ");
568 if (lcc
->fieldsSet
& LCC_UID_SET
) {
569 snprintf(client_uid_string
+ slen
,
570 sizeof(client_uid_string
) - slen
,
571 "uid=%ld ", (long) lcc
->euid
);
572 slen
= strlen(client_uid_string
);
575 if (lcc
->fieldsSet
& LCC_GID_SET
) {
576 snprintf(client_uid_string
+ slen
,
577 sizeof(client_uid_string
) - slen
,
578 "gid=%ld ", (long) lcc
->egid
);
579 slen
= strlen(client_uid_string
);
582 if (lcc
->fieldsSet
& LCC_PID_SET
) {
583 #ifdef XSERVER_DTRACE
584 client_pid
= lcc
->pid
;
586 snprintf(client_uid_string
+ slen
,
587 sizeof(client_uid_string
) - slen
,
588 "pid=%ld ", (long) lcc
->pid
);
589 slen
= strlen(client_uid_string
);
592 if (lcc
->fieldsSet
& LCC_ZID_SET
) {
593 #ifdef XSERVER_DTRACE
594 client_zid
= lcc
->zoneid
;
596 snprintf(client_uid_string
+ slen
,
597 sizeof(client_uid_string
) - slen
,
598 "zoneid=%ld ", (long) lcc
->zoneid
);
599 slen
= strlen(client_uid_string
);
602 snprintf(client_uid_string
+ slen
, sizeof(client_uid_string
) - slen
,
604 FreeLocalClientCreds(lcc
);
607 client_uid_string
[0] = '\0';
610 #ifdef XSERVER_DTRACE
611 XSERVER_CLIENT_AUTH(client
->index
, addr
, client_pid
, client_zid
);
613 if (auditTrailLevel
> 1) {
615 AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n",
616 client
->index
, letin
? "connected" : "rejected", addr
,
617 client_uid_string
, (int) proto_n
, auth_proto
, auth_id
);
619 AuditF("client %d %s from %s%s\n",
620 client
->index
, letin
? "connected" : "rejected", addr
,
627 AuthorizationIDOfClient(ClientPtr client
)
629 if (client
->osPrivate
)
630 return ((OsCommPtr
) client
->osPrivate
)->auth_id
;
635 /*****************************************************************
638 * Sent by the client at connection setup:
639 * typedef struct _xConnClientPrefix {
642 * CARD16 majorVersion, minorVersion;
643 * CARD16 nbytesAuthProto;
644 * CARD16 nbytesAuthString;
645 * } xConnClientPrefix;
647 * It is hoped that eventually one protocol will be agreed upon. In the
648 * mean time, a server that implements a different protocol than the
649 * client expects, or a server that only implements the host-based
650 * mechanism, will simply ignore this information.
652 *****************************************************************/
655 ClientAuthorized(ClientPtr client
,
656 unsigned int proto_n
, char *auth_proto
,
657 unsigned int string_n
, char *auth_string
)
660 Xtransaddr
*from
= NULL
;
664 const char *reason
= NULL
;
665 XtransConnInfo trans_conn
;
667 priv
= (OsCommPtr
) client
->osPrivate
;
668 trans_conn
= priv
->trans_conn
;
670 /* Allow any client to connect without authorization on a launchd socket,
671 because it is securely created -- this prevents a race condition on launch */
672 if (trans_conn
->flags
& TRANS_NOXAUTH
) {
677 CheckAuthorization(proto_n
, auth_proto
, string_n
, auth_string
,
681 if (auth_id
== (XID
) ~0L) {
682 if (_XSERVTransGetPeerAddr(trans_conn
, &family
, &fromlen
, &from
) != -1) {
683 if (InvalidHost((struct sockaddr
*) from
, fromlen
, client
))
684 AuthAudit(client
, FALSE
, (struct sockaddr
*) from
,
685 fromlen
, proto_n
, auth_proto
, auth_id
);
688 #ifdef XSERVER_DTRACE
689 if ((auditTrailLevel
> 1) || XSERVER_CLIENT_AUTH_ENABLED())
691 if (auditTrailLevel
> 1)
693 AuthAudit(client
, TRUE
,
694 (struct sockaddr
*) from
, fromlen
,
695 proto_n
, auth_proto
, auth_id
);
701 if (auth_id
== (XID
) ~0L) {
705 return "Client is not authorized to connect to Server";
708 #ifdef XSERVER_DTRACE
709 else if ((auditTrailLevel
> 1) || XSERVER_CLIENT_AUTH_ENABLED())
711 else if (auditTrailLevel
> 1)
714 if (_XSERVTransGetPeerAddr(trans_conn
, &family
, &fromlen
, &from
) != -1) {
715 AuthAudit(client
, TRUE
, (struct sockaddr
*) from
, fromlen
,
716 proto_n
, auth_proto
, auth_id
);
721 priv
->auth_id
= auth_id
;
725 /* indicate to Xdmcp protocol that we've opened new client */
726 XdmcpOpenDisplay(priv
->fd
);
729 XaceHook(XACE_AUTH_AVAIL
, client
, auth_id
);
731 /* At this point, if the client is authorized to change the access control
732 * list, we should getpeername() information, and add the client to
733 * the selfhosts list. It's not really the host machine, but the
734 * true purpose of the selfhosts list is to see who may change the
735 * access control list.
737 return ((char *) NULL
);
741 AllocNewConnection(XtransConnInfo trans_conn
, int fd
, CARD32 conn_time
)
750 XFD_SETCOUNT(&AllClients
) >= MaxClients
754 oc
= malloc(sizeof(OsCommRec
));
757 oc
->trans_conn
= trans_conn
;
759 oc
->input
= (ConnectionInputPtr
) NULL
;
760 oc
->output
= (ConnectionOutputPtr
) NULL
;
762 oc
->conn_time
= conn_time
;
763 if (!(client
= NextAvailableClient((pointer
) oc
))) {
767 client
->local
= ComputeLocalClient(client
);
769 ConnectionTranslation
[fd
] = client
->index
;
771 SetConnectionTranslation(fd
, client
->index
);
773 if (GrabInProgress
) {
774 FD_SET(fd
, &SavedAllClients
);
775 FD_SET(fd
, &SavedAllSockets
);
778 FD_SET(fd
, &AllClients
);
779 FD_SET(fd
, &AllSockets
);
783 ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
786 #ifdef XSERVER_DTRACE
787 XSERVER_CLIENT_CONNECT(client
->index
, fd
);
794 * EstablishNewConnections
795 * If anyone is waiting on listened sockets, accept them.
796 * Returns a mask with indices of new clients. Updates AllClients
801 EstablishNewConnections(ClientPtr clientUnused
, pointer closure
)
803 fd_set readyconnections
; /* set of listeners that are ready */
804 int curconn
; /* fd of listener that's ready */
805 register int newconn
; /* fd of new client */
808 register ClientPtr client
;
809 register OsCommPtr oc
;
812 XFD_ANDSET(&tmask
, (fd_set
*) closure
, &WellKnownConnections
);
813 XFD_COPYSET(&tmask
, &readyconnections
);
814 if (!XFD_ANYSET(&readyconnections
))
816 connect_time
= GetTimeInMillis();
817 /* kill off stragglers */
818 for (i
= 1; i
< currentMaxClients
; i
++) {
819 if ((client
= clients
[i
])) {
820 oc
= (OsCommPtr
) (client
->osPrivate
);
821 if ((oc
&& (oc
->conn_time
!= 0) &&
822 (connect_time
- oc
->conn_time
) >= TimeOutValue
) ||
823 (client
->noClientException
!= Success
&& !client
->clientGone
))
824 CloseDownClient(client
);
828 for (i
= 0; i
< howmany(XFD_SETSIZE
, NFDBITS
); i
++) {
829 while (readyconnections
.fds_bits
[i
])
831 for (i
= 0; i
< XFD_SETCOUNT(&readyconnections
); i
++)
834 XtransConnInfo trans_conn
, new_trans_conn
;
838 curconn
= mffs(readyconnections
.fds_bits
[i
]) - 1;
839 readyconnections
.fds_bits
[i
] &= ~((fd_mask
) 1 << curconn
);
840 curconn
+= (i
* (sizeof(fd_mask
) * 8));
842 curconn
= XFD_FD(&readyconnections
, i
);
845 if ((trans_conn
= lookup_trans_conn(curconn
)) == NULL
)
848 if ((new_trans_conn
= _XSERVTransAccept(trans_conn
, &status
)) == NULL
)
851 newconn
= _XSERVTransGetConnectionNumber(new_trans_conn
);
853 if (newconn
< lastfdesc
) {
857 clientid
= ConnectionTranslation
[newconn
];
859 clientid
= GetConnectionTranslation(newconn
);
861 if (clientid
&& (client
= clients
[clientid
]))
862 CloseDownClient(client
);
865 _XSERVTransSetOption(new_trans_conn
, TRANS_NONBLOCKING
, 1);
867 if (trans_conn
->flags
& TRANS_NOXAUTH
)
868 new_trans_conn
->flags
= new_trans_conn
->flags
| TRANS_NOXAUTH
;
870 if (!AllocNewConnection(new_trans_conn
, newconn
, connect_time
)) {
871 ErrorConnMax(new_trans_conn
);
872 _XSERVTransClose(new_trans_conn
);
881 #define NOROOM "Maximum number of clients reached"
885 * Fail a connection due to lack of client or file descriptor space
888 #define BOTIMEOUT 200 /* in milliseconds */
891 ErrorConnMax(XtransConnInfo trans_conn
)
893 int fd
= _XSERVTransGetConnectionNumber(trans_conn
);
894 xConnSetupPrefix csp
;
895 char pad
[3] = { 0, 0, 0 };
899 struct timeval waittime
;
902 /* if these seems like a lot of trouble to go to, it probably is */
903 waittime
.tv_sec
= BOTIMEOUT
/ MILLI_PER_SECOND
;
904 waittime
.tv_usec
= (BOTIMEOUT
% MILLI_PER_SECOND
) *
905 (1000000 / MILLI_PER_SECOND
);
908 (void) Select(fd
+ 1, &mask
, NULL
, NULL
, &waittime
);
909 /* try to read the byte-order of the connection */
910 (void) _XSERVTransRead(trans_conn
, &order
, 1);
911 if (order
== 'l' || order
== 'B' || order
== 'r' || order
== 'R') {
912 csp
.success
= xFalse
;
913 csp
.lengthReason
= sizeof(NOROOM
) - 1;
914 csp
.length
= (sizeof(NOROOM
) + 2) >> 2;
915 csp
.majorVersion
= X_PROTOCOL
;
916 csp
.minorVersion
= X_PROTOCOL_REVISION
;
917 if (((*(char *) &whichbyte
) && (order
== 'B' || order
== 'R')) ||
918 (!(*(char *) &whichbyte
) && (order
== 'l' || order
== 'r'))) {
919 swaps(&csp
.majorVersion
);
920 swaps(&csp
.minorVersion
);
923 iov
[0].iov_len
= sz_xConnSetupPrefix
;
924 iov
[0].iov_base
= (char *) &csp
;
925 iov
[1].iov_len
= csp
.lengthReason
;
926 iov
[1].iov_base
= (void *) NOROOM
;
927 iov
[2].iov_len
= (4 - (csp
.lengthReason
& 3)) & 3;
928 iov
[2].iov_base
= pad
;
929 (void) _XSERVTransWritev(trans_conn
, iov
, 3);
934 * CloseDownFileDescriptor:
935 * Remove this file descriptor and it's I/O buffers, etc.
939 CloseDownFileDescriptor(OsCommPtr oc
)
941 int connection
= oc
->fd
;
943 if (oc
->trans_conn
) {
944 _XSERVTransDisconnect(oc
->trans_conn
);
945 _XSERVTransClose(oc
->trans_conn
);
948 ConnectionTranslation
[connection
] = 0;
950 SetConnectionTranslation(connection
, 0);
952 FD_CLR(connection
, &AllSockets
);
953 FD_CLR(connection
, &AllClients
);
954 FD_CLR(connection
, &ClientsWithInput
);
955 FD_CLR(connection
, &GrabImperviousClients
);
956 if (GrabInProgress
) {
957 FD_CLR(connection
, &SavedAllSockets
);
958 FD_CLR(connection
, &SavedAllClients
);
959 FD_CLR(connection
, &SavedClientsWithInput
);
961 FD_CLR(connection
, &ClientsWriteBlocked
);
962 if (!XFD_ANYSET(&ClientsWriteBlocked
))
963 AnyClientsWriteBlocked
= FALSE
;
964 FD_CLR(connection
, &OutputPending
);
969 * Some connection has died, go find which one and shut it down
970 * The file descriptor has been closed, but is still in AllClients.
971 * If would truly be wonderful if select() would put the bogus
972 * file descriptors in the exception mask, but nooooo. So we have
973 * to check each and every socket individually.
977 CheckConnections(void)
983 int curclient
, curoff
;
985 struct timeval notime
;
989 fd_set savedAllClients
;
996 for (i
= 0; i
< howmany(XFD_SETSIZE
, NFDBITS
); i
++) {
997 mask
= AllClients
.fds_bits
[i
];
999 curoff
= mffs(mask
) - 1;
1000 curclient
= curoff
+ (i
* (sizeof(fd_mask
) * 8));
1002 FD_SET(curclient
, &tmask
);
1004 r
= Select(curclient
+ 1, &tmask
, NULL
, NULL
, ¬ime
);
1005 } while (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
1007 if (ConnectionTranslation
[curclient
] > 0)
1008 CloseDownClient(clients
[ConnectionTranslation
[curclient
]]);
1009 mask
&= ~((fd_mask
) 1 << curoff
);
1013 XFD_COPYSET(&AllClients
, &savedAllClients
);
1014 for (i
= 0; i
< XFD_SETCOUNT(&savedAllClients
); i
++) {
1015 curclient
= XFD_FD(&savedAllClients
, i
);
1017 FD_SET(curclient
, &tmask
);
1019 r
= Select(curclient
+ 1, &tmask
, NULL
, NULL
, ¬ime
);
1020 } while (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
1022 if (GetConnectionTranslation(curclient
) > 0)
1023 CloseDownClient(clients
[GetConnectionTranslation(curclient
)]);
1029 * CloseDownConnection
1030 * Delete client from AllClients and free resources
1034 CloseDownConnection(ClientPtr client
)
1036 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1039 CallCallbacks(&FlushCallback
, NULL
);
1042 FlushClient(client
, oc
, (char *) NULL
, 0);
1044 XdmcpCloseDisplay(oc
->fd
);
1046 CloseDownFileDescriptor(oc
);
1048 free(client
->osPrivate
);
1049 client
->osPrivate
= (pointer
) NULL
;
1050 if (auditTrailLevel
> 1)
1051 AuditF("client %d disconnected\n", client
->index
);
1055 AddGeneralSocket(int fd
)
1057 FD_SET(fd
, &AllSockets
);
1059 FD_SET(fd
, &SavedAllSockets
);
1063 AddEnabledDevice(int fd
)
1065 FD_SET(fd
, &EnabledDevices
);
1066 AddGeneralSocket(fd
);
1070 RemoveGeneralSocket(int fd
)
1072 FD_CLR(fd
, &AllSockets
);
1074 FD_CLR(fd
, &SavedAllSockets
);
1078 RemoveEnabledDevice(int fd
)
1080 FD_CLR(fd
, &EnabledDevices
);
1081 RemoveGeneralSocket(fd
);
1085 * OnlyListenToOneClient:
1086 * Only accept requests from one client. Continue to handle new
1087 * connections, but don't take any protocol requests from the new
1088 * ones. Note that if GrabInProgress is set, EstablishNewConnections
1089 * needs to put new clients into SavedAllSockets and SavedAllClients.
1090 * Note also that there is no timeout for this in the protocol.
1091 * This routine is "undone" by ListenToAllClients()
1095 OnlyListenToOneClient(ClientPtr client
)
1097 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1098 int rc
, connection
= oc
->fd
;
1100 rc
= XaceHook(XACE_SERVER_ACCESS
, client
, DixGrabAccess
);
1104 if (!GrabInProgress
) {
1105 XFD_COPYSET(&ClientsWithInput
, &SavedClientsWithInput
);
1106 XFD_ANDSET(&ClientsWithInput
,
1107 &ClientsWithInput
, &GrabImperviousClients
);
1108 if (FD_ISSET(connection
, &SavedClientsWithInput
)) {
1109 FD_CLR(connection
, &SavedClientsWithInput
);
1110 FD_SET(connection
, &ClientsWithInput
);
1112 XFD_UNSET(&SavedClientsWithInput
, &GrabImperviousClients
);
1113 XFD_COPYSET(&AllSockets
, &SavedAllSockets
);
1114 XFD_COPYSET(&AllClients
, &SavedAllClients
);
1115 XFD_UNSET(&AllSockets
, &AllClients
);
1116 XFD_ANDSET(&AllClients
, &AllClients
, &GrabImperviousClients
);
1117 FD_SET(connection
, &AllClients
);
1118 XFD_ORSET(&AllSockets
, &AllSockets
, &AllClients
);
1119 GrabInProgress
= client
->index
;
1125 * ListenToAllClients:
1126 * Undoes OnlyListentToOneClient()
1130 ListenToAllClients(void)
1132 if (GrabInProgress
) {
1133 XFD_ORSET(&AllSockets
, &AllSockets
, &SavedAllSockets
);
1134 XFD_ORSET(&AllClients
, &AllClients
, &SavedAllClients
);
1135 XFD_ORSET(&ClientsWithInput
, &ClientsWithInput
, &SavedClientsWithInput
);
1142 * Removes one client from input masks.
1143 * Must have cooresponding call to AttendClient.
1147 IgnoreClient(ClientPtr client
)
1149 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1150 int connection
= oc
->fd
;
1152 client
->ignoreCount
++;
1153 if (client
->ignoreCount
> 1)
1156 isItTimeToYield
= TRUE
;
1157 if (!GrabInProgress
|| FD_ISSET(connection
, &AllClients
)) {
1158 if (FD_ISSET(connection
, &ClientsWithInput
))
1159 FD_SET(connection
, &IgnoredClientsWithInput
);
1161 FD_CLR(connection
, &IgnoredClientsWithInput
);
1162 FD_CLR(connection
, &ClientsWithInput
);
1163 FD_CLR(connection
, &AllSockets
);
1164 FD_CLR(connection
, &AllClients
);
1165 FD_CLR(connection
, &LastSelectMask
);
1168 if (FD_ISSET(connection
, &SavedClientsWithInput
))
1169 FD_SET(connection
, &IgnoredClientsWithInput
);
1171 FD_CLR(connection
, &IgnoredClientsWithInput
);
1172 FD_CLR(connection
, &SavedClientsWithInput
);
1173 FD_CLR(connection
, &SavedAllSockets
);
1174 FD_CLR(connection
, &SavedAllClients
);
1180 * Adds one client back into the input masks.
1184 AttendClient(ClientPtr client
)
1186 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1187 int connection
= oc
->fd
;
1189 client
->ignoreCount
--;
1190 if (client
->ignoreCount
)
1193 if (!GrabInProgress
|| GrabInProgress
== client
->index
||
1194 FD_ISSET(connection
, &GrabImperviousClients
)) {
1195 FD_SET(connection
, &AllClients
);
1196 FD_SET(connection
, &AllSockets
);
1197 FD_SET(connection
, &LastSelectMask
);
1198 if (FD_ISSET(connection
, &IgnoredClientsWithInput
))
1199 FD_SET(connection
, &ClientsWithInput
);
1202 FD_SET(connection
, &SavedAllClients
);
1203 FD_SET(connection
, &SavedAllSockets
);
1204 if (FD_ISSET(connection
, &IgnoredClientsWithInput
))
1205 FD_SET(connection
, &SavedClientsWithInput
);
1209 /* make client impervious to grabs; assume only executing client calls this */
1212 MakeClientGrabImpervious(ClientPtr client
)
1214 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1215 int connection
= oc
->fd
;
1217 FD_SET(connection
, &GrabImperviousClients
);
1219 if (ServerGrabCallback
) {
1220 ServerGrabInfoRec grabinfo
;
1222 grabinfo
.client
= client
;
1223 grabinfo
.grabstate
= CLIENT_IMPERVIOUS
;
1224 CallCallbacks(&ServerGrabCallback
, &grabinfo
);
1228 /* make client pervious to grabs; assume only executing client calls this */
1231 MakeClientGrabPervious(ClientPtr client
)
1233 OsCommPtr oc
= (OsCommPtr
) client
->osPrivate
;
1234 int connection
= oc
->fd
;
1236 FD_CLR(connection
, &GrabImperviousClients
);
1237 if (GrabInProgress
&& (GrabInProgress
!= client
->index
)) {
1238 if (FD_ISSET(connection
, &ClientsWithInput
)) {
1239 FD_SET(connection
, &SavedClientsWithInput
);
1240 FD_CLR(connection
, &ClientsWithInput
);
1242 FD_CLR(connection
, &AllSockets
);
1243 FD_CLR(connection
, &AllClients
);
1244 isItTimeToYield
= TRUE
;
1247 if (ServerGrabCallback
) {
1248 ServerGrabInfoRec grabinfo
;
1250 grabinfo
.client
= client
;
1251 grabinfo
.grabstate
= CLIENT_PERVIOUS
;
1252 CallCallbacks(&ServerGrabCallback
, &grabinfo
);
1257 /* Add a fd (from launchd) to our listeners */
1259 ListenOnOpenFD(int fd
, int noxauth
)
1262 XtransConnInfo ciptr
;
1263 const char *display_env
= getenv("DISPLAY");
1265 if (display_env
&& (strncmp(display_env
, "/tmp/launch", 11) == 0)) {
1266 /* Make the path the launchd socket if our DISPLAY is set right */
1267 strcpy(port
, display_env
);
1270 /* Just some default so things don't break and die. */
1271 snprintf(port
, sizeof(port
), ":%d", atoi(display
));
1274 /* Make our XtransConnInfo
1275 * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
1277 ciptr
= _XSERVTransReopenCOTSServer(5, fd
, port
);
1278 if (ciptr
== NULL
) {
1279 ErrorF("Got NULL while trying to Reopen launchd port.\n");
1284 ciptr
->flags
= ciptr
->flags
| TRANS_NOXAUTH
;
1286 /* Allocate space to store it */
1288 (int *) realloc(ListenTransFds
, (ListenTransCount
+ 1) * sizeof(int));
1290 (XtransConnInfo
*) realloc(ListenTransConns
,
1292 1) * sizeof(XtransConnInfo
));
1295 ListenTransConns
[ListenTransCount
] = ciptr
;
1296 ListenTransFds
[ListenTransCount
] = fd
;
1298 FD_SET(fd
, &WellKnownConnections
);
1299 FD_SET(fd
, &AllSockets
);
1301 /* Increment the count */
1304 /* This *might* not be needed... /shrug */
1305 ResetAuthorization();
1306 ResetHosts(display
);