2 * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of N.C.D. not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. N.C.D. makes no representations about the
11 * suitability of this software for any purpose. It is provided "as is"
12 * without express or implied warranty.
16 #ifdef HAVE_DIX_CONFIG_H
17 #include <dix-config.h>
21 #include <X11/Xwinsock.h>
27 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
38 #include <X11/Xpoll.h>
41 #include "dixstruct.h"
47 #include <netconfig.h>
58 #include <X11/Xdmcp.h>
60 #define X_INCLUDE_NETDB_H
61 #include <X11/Xos_r.h>
63 static const char *defaultDisplayClass
= COMPILEDDISPLAYCLASS
;
65 static int xdmcpSocket
, sessionSocket
;
66 static xdmcp_states state
;
68 #if defined(IPv6) && defined(AF_INET6)
69 static int xdmcpSocket6
;
70 static struct sockaddr_storage req_sockaddr
;
72 static struct sockaddr_in req_sockaddr
;
74 static int req_socklen
;
75 static CARD32 SessionID
;
76 static CARD32 timeOutTime
;
77 static int timeOutRtx
;
78 static CARD32 defaultKeepaliveDormancy
= XDM_DEF_DORMANCY
;
79 static CARD32 keepaliveDormancy
= XDM_DEF_DORMANCY
;
80 static CARD16 DisplayNumber
;
81 static xdmcp_states XDM_INIT_STATE
= XDM_OFF
;
84 static char *xdmAuthCookie
;
87 static XdmcpBuffer buffer
;
89 #if defined(IPv6) && defined(AF_INET6)
91 static struct addrinfo
*mgrAddr
;
92 static struct addrinfo
*mgrAddrFirst
;
94 #define SOCKADDR_TYPE struct sockaddr_storage
95 #define SOCKADDR_FAMILY(s) ((struct sockaddr *)&(s))->sa_family
98 #define SOCKLEN_FIELD(s) ((struct sockaddr *)&(s))->sa_len
99 #define SOCKLEN_TYPE unsigned char
101 #define SOCKLEN_TYPE unsigned int
106 #define SOCKADDR_TYPE struct sockaddr_in
107 #define SOCKADDR_FAMILY(s) (s).sin_family
110 #define SOCKLEN_FIELD(s) (s).sin_len
111 #define SOCKLEN_TYPE unsigned char
113 #define SOCKLEN_TYPE size_t
118 static SOCKADDR_TYPE ManagerAddress
;
119 static SOCKADDR_TYPE FromAddress
;
122 #define ManagerAddressLen SOCKLEN_FIELD(ManagerAddress)
123 #define FromAddressLen SOCKLEN_FIELD(FromAddress)
125 static SOCKLEN_TYPE ManagerAddressLen
, FromAddressLen
;
128 #if defined(IPv6) && defined(AF_INET6)
129 static struct multicastinfo
{
130 struct multicastinfo
*next
;
136 static void XdmcpAddHost(const struct sockaddr
*from
,
138 ARRAY8Ptr AuthenticationName
,
139 ARRAY8Ptr hostname
, ARRAY8Ptr status
);
141 static void XdmcpSelectHost(const struct sockaddr
*host_sockaddr
,
142 int host_len
, ARRAY8Ptr AuthenticationName
);
144 static void get_xdmcp_sock(void);
146 static void send_query_msg(void);
148 static void recv_willing_msg(struct sockaddr
* /*from */ ,
150 unsigned /*length */ );
152 static void send_request_msg(void);
154 static void recv_accept_msg(unsigned /*length */ );
156 static void recv_decline_msg(unsigned /*length */ );
158 static void send_manage_msg(void);
160 static void recv_refuse_msg(unsigned /*length */ );
162 static void recv_failed_msg(unsigned /*length */ );
164 static void send_keepalive_msg(void);
166 static void recv_alive_msg(unsigned /*length */ );
168 static void XdmcpFatal(const char * /*type */ ,
169 ARRAY8Ptr
/*status */ );
171 static void XdmcpWarning(const char * /*str */ );
173 static void get_manager_by_name(int /*argc */ ,
177 static void get_fromaddr_by_name(int /*argc */ , char ** /*argv */ ,
180 #if defined(IPv6) && defined(AF_INET6)
181 static int get_mcast_options(int /*argc */ , char ** /*argv */ , int /*i */ );
184 static void receive_packet(int /*socketfd */ );
186 static void send_packet(void);
188 static void timeout(void);
190 static void restart(void);
192 static void XdmcpBlockHandler(pointer
/*data */ ,
193 struct timeval
** /*wt */ ,
194 pointer
/*LastSelectMask */ );
196 static void XdmcpWakeupHandler(pointer
/*data */ ,
198 pointer
/*LastSelectMask */ );
201 * Register the Manufacturer display ID
204 static ARRAY8 ManufacturerDisplayID
;
207 XdmcpRegisterManufacturerDisplayID(const char *name
, int length
)
211 XdmcpDisposeARRAY8(&ManufacturerDisplayID
);
212 if (!XdmcpAllocARRAY8(&ManufacturerDisplayID
, length
))
214 for (i
= 0; i
< length
; i
++)
215 ManufacturerDisplayID
.data
[i
] = (CARD8
) name
[i
];
218 static unsigned short xdm_udp_port
= XDM_UDP_PORT
;
219 static Bool OneSession
= FALSE
;
220 static const char *xdm_from
= NULL
;
225 ErrorF("-query host-name contact named host for XDMCP\n");
226 ErrorF("-broadcast broadcast for XDMCP\n");
227 #if defined(IPv6) && defined(AF_INET6)
228 ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n");
230 ErrorF("-indirect host-name contact named host for indirect XDMCP\n");
231 ErrorF("-port port-num UDP port number to send messages to\n");
233 ("-from local-address specify the local address to connect from\n");
234 ErrorF("-once Terminate server after one session\n");
235 ErrorF("-class display-class specify display class to send in manage\n");
237 ErrorF("-cookie xdm-auth-bits specify the magic cookie for XDMCP\n");
239 ErrorF("-displayID display-id manufacturer display ID for request\n");
243 XdmcpOptions(int argc
, char **argv
, int i
)
245 if (strcmp(argv
[i
], "-query") == 0) {
246 get_manager_by_name(argc
, argv
, i
++);
247 XDM_INIT_STATE
= XDM_QUERY
;
251 if (strcmp(argv
[i
], "-broadcast") == 0) {
252 XDM_INIT_STATE
= XDM_BROADCAST
;
256 #if defined(IPv6) && defined(AF_INET6)
257 if (strcmp(argv
[i
], "-multicast") == 0) {
258 i
= get_mcast_options(argc
, argv
, ++i
);
259 XDM_INIT_STATE
= XDM_MULTICAST
;
264 if (strcmp(argv
[i
], "-indirect") == 0) {
265 get_manager_by_name(argc
, argv
, i
++);
266 XDM_INIT_STATE
= XDM_INDIRECT
;
270 if (strcmp(argv
[i
], "-port") == 0) {
272 FatalError("Xserver: missing port number in command line\n");
274 xdm_udp_port
= (unsigned short) atoi(argv
[i
]);
277 if (strcmp(argv
[i
], "-from") == 0) {
278 get_fromaddr_by_name(argc
, argv
, ++i
);
281 if (strcmp(argv
[i
], "-once") == 0) {
285 if (strcmp(argv
[i
], "-class") == 0) {
287 FatalError("Xserver: missing class name in command line\n");
289 defaultDisplayClass
= argv
[i
];
293 if (strcmp(argv
[i
], "-cookie") == 0) {
295 FatalError("Xserver: missing cookie data in command line\n");
297 xdmAuthCookie
= argv
[i
];
301 if (strcmp(argv
[i
], "-displayID") == 0) {
303 FatalError("Xserver: missing displayID in command line\n");
305 XdmcpRegisterManufacturerDisplayID(argv
[i
], strlen(argv
[i
]));
312 * This section is a collection of routines for
313 * registering server-specific data with the XDMCP
318 * Save all broadcast addresses away so BroadcastQuery
319 * packets get sent everywhere
322 #define MAX_BROADCAST 10
324 /* This stays sockaddr_in since IPv6 doesn't support broadcast */
325 static struct sockaddr_in BroadcastAddresses
[MAX_BROADCAST
];
326 static int NumBroadcastAddresses
;
329 XdmcpRegisterBroadcastAddress(const struct sockaddr_in
*addr
)
331 struct sockaddr_in
*bcast
;
333 if (NumBroadcastAddresses
>= MAX_BROADCAST
)
335 bcast
= &BroadcastAddresses
[NumBroadcastAddresses
++];
336 memset(bcast
, 0, sizeof(struct sockaddr_in
));
338 bcast
->sin_len
= addr
->sin_len
;
340 bcast
->sin_family
= addr
->sin_family
;
341 bcast
->sin_port
= htons(xdm_udp_port
);
342 bcast
->sin_addr
= addr
->sin_addr
;
346 * Each authentication type is registered here; Validator
347 * will be called to check all access attempts using
348 * the specified authentication type
351 static ARRAYofARRAY8 AuthenticationNames
, AuthenticationDatas
;
352 typedef struct _AuthenticationFuncs
{
353 ValidatorFunc Validator
;
354 GeneratorFunc Generator
;
355 AddAuthorFunc AddAuth
;
356 } AuthenticationFuncsRec
, *AuthenticationFuncsPtr
;
358 static AuthenticationFuncsPtr AuthenticationFuncsList
;
361 XdmcpRegisterAuthentication(const char *name
,
365 ValidatorFunc Validator
,
366 GeneratorFunc Generator
, AddAuthorFunc AddAuth
)
369 ARRAY8 AuthenticationName
, AuthenticationData
;
370 static AuthenticationFuncsPtr newFuncs
;
372 if (!XdmcpAllocARRAY8(&AuthenticationName
, namelen
))
374 if (!XdmcpAllocARRAY8(&AuthenticationData
, datalen
)) {
375 XdmcpDisposeARRAY8(&AuthenticationName
);
378 for (i
= 0; i
< namelen
; i
++)
379 AuthenticationName
.data
[i
] = name
[i
];
380 for (i
= 0; i
< datalen
; i
++)
381 AuthenticationData
.data
[i
] = data
[i
];
382 if (!(XdmcpReallocARRAYofARRAY8(&AuthenticationNames
,
383 AuthenticationNames
.length
+ 1) &&
384 XdmcpReallocARRAYofARRAY8(&AuthenticationDatas
,
385 AuthenticationDatas
.length
+ 1) &&
387 malloc((AuthenticationNames
.length
+
388 1) * sizeof(AuthenticationFuncsRec
))))) {
389 XdmcpDisposeARRAY8(&AuthenticationName
);
390 XdmcpDisposeARRAY8(&AuthenticationData
);
393 for (i
= 0; i
< AuthenticationNames
.length
- 1; i
++)
394 newFuncs
[i
] = AuthenticationFuncsList
[i
];
395 newFuncs
[AuthenticationNames
.length
- 1].Validator
= Validator
;
396 newFuncs
[AuthenticationNames
.length
- 1].Generator
= Generator
;
397 newFuncs
[AuthenticationNames
.length
- 1].AddAuth
= AddAuth
;
398 free(AuthenticationFuncsList
);
399 AuthenticationFuncsList
= newFuncs
;
400 AuthenticationNames
.data
[AuthenticationNames
.length
- 1] =
402 AuthenticationDatas
.data
[AuthenticationDatas
.length
- 1] =
407 * Select the authentication type to be used; this is
408 * set by the manager of the host to be connected to.
411 static ARRAY8 noAuthenticationName
= { (CARD16
) 0, (CARD8Ptr
) 0 };
412 static ARRAY8 noAuthenticationData
= { (CARD16
) 0, (CARD8Ptr
) 0 };
414 static ARRAY8Ptr AuthenticationName
= &noAuthenticationName
;
415 static ARRAY8Ptr AuthenticationData
= &noAuthenticationData
;
416 static AuthenticationFuncsPtr AuthenticationFuncs
;
419 XdmcpSetAuthentication(const ARRAY8Ptr name
)
423 for (i
= 0; i
< AuthenticationNames
.length
; i
++)
424 if (XdmcpARRAY8Equal(&AuthenticationNames
.data
[i
], name
)) {
425 AuthenticationName
= &AuthenticationNames
.data
[i
];
426 AuthenticationData
= &AuthenticationDatas
.data
[i
];
427 AuthenticationFuncs
= &AuthenticationFuncsList
[i
];
433 * Register the host address for the display
436 static ARRAY16 ConnectionTypes
;
437 static ARRAYofARRAY8 ConnectionAddresses
;
438 static long xdmcpGeneration
;
441 XdmcpRegisterConnection(int type
, const char *address
, int addrlen
)
446 if (xdmcpGeneration
!= serverGeneration
) {
447 XdmcpDisposeARRAY16(&ConnectionTypes
);
448 XdmcpDisposeARRAYofARRAY8(&ConnectionAddresses
);
449 xdmcpGeneration
= serverGeneration
;
451 if (xdm_from
!= NULL
) { /* Only register the requested address */
452 const void *regAddr
= address
;
453 const void *fromAddr
= NULL
;
454 int regAddrlen
= addrlen
;
456 if (addrlen
== sizeof(struct in_addr
)) {
457 if (SOCKADDR_FAMILY(FromAddress
) == AF_INET
) {
458 fromAddr
= &((struct sockaddr_in
*) &FromAddress
)->sin_addr
;
460 #if defined(IPv6) && defined(AF_INET6)
461 else if ((SOCKADDR_FAMILY(FromAddress
) == AF_INET6
) &&
462 IN6_IS_ADDR_V4MAPPED(&
463 ((struct sockaddr_in6
*)
464 &FromAddress
)->sin6_addr
)) {
466 &((struct sockaddr_in6
*) &FromAddress
)->sin6_addr
.
471 #if defined(IPv6) && defined(AF_INET6)
472 else if (addrlen
== sizeof(struct in6_addr
)) {
473 if (SOCKADDR_FAMILY(FromAddress
) == AF_INET6
) {
474 fromAddr
= &((struct sockaddr_in6
*) &FromAddress
)->sin6_addr
;
476 else if ((SOCKADDR_FAMILY(FromAddress
) == AF_INET
) &&
477 IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*) address
)) {
478 fromAddr
= &((struct sockaddr_in
*) &FromAddress
)->sin_addr
;
480 &((struct sockaddr_in6
*) &address
)->sin6_addr
.s6_addr
[12];
481 regAddrlen
= sizeof(struct in_addr
);
485 if (!fromAddr
|| memcmp(regAddr
, fromAddr
, regAddrlen
) != 0) {
489 if (ConnectionAddresses
.length
+ 1 == 256)
491 newAddress
= malloc(addrlen
* sizeof(CARD8
));
494 if (!XdmcpReallocARRAY16(&ConnectionTypes
, ConnectionTypes
.length
+ 1)) {
498 if (!XdmcpReallocARRAYofARRAY8(&ConnectionAddresses
,
499 ConnectionAddresses
.length
+ 1)) {
503 ConnectionTypes
.data
[ConnectionTypes
.length
- 1] = (CARD16
) type
;
504 for (i
= 0; i
< addrlen
; i
++)
505 newAddress
[i
] = address
[i
];
506 ConnectionAddresses
.data
[ConnectionAddresses
.length
- 1].data
= newAddress
;
507 ConnectionAddresses
.data
[ConnectionAddresses
.length
- 1].length
= addrlen
;
511 * Register an Authorization Name. XDMCP advertises this list
515 static ARRAYofARRAY8 AuthorizationNames
;
518 XdmcpRegisterAuthorizations(void)
520 XdmcpDisposeARRAYofARRAY8(&AuthorizationNames
);
521 RegisterAuthorizations();
525 XdmcpRegisterAuthorization(const char *name
, int namelen
)
530 authName
.data
= malloc(namelen
* sizeof(CARD8
));
533 if (!XdmcpReallocARRAYofARRAY8
534 (&AuthorizationNames
, AuthorizationNames
.length
+ 1)) {
538 for (i
= 0; i
< namelen
; i
++)
539 authName
.data
[i
] = (CARD8
) name
[i
];
540 authName
.length
= namelen
;
541 AuthorizationNames
.data
[AuthorizationNames
.length
- 1] = authName
;
545 * Register the DisplayClass string
548 static ARRAY8 DisplayClass
;
551 XdmcpRegisterDisplayClass(const char *name
, int length
)
555 XdmcpDisposeARRAY8(&DisplayClass
);
556 if (!XdmcpAllocARRAY8(&DisplayClass
, length
))
558 for (i
= 0; i
< length
; i
++)
559 DisplayClass
.data
[i
] = (CARD8
) name
[i
];
563 * initialize XDMCP; create the socket, compute the display
564 * number, set up the state machine
570 state
= XDM_INIT_STATE
;
573 XdmAuthenticationInit(xdmAuthCookie
, strlen(xdmAuthCookie
));
575 if (state
!= XDM_OFF
) {
576 XdmcpRegisterAuthorizations();
577 XdmcpRegisterDisplayClass(defaultDisplayClass
,
578 strlen(defaultDisplayClass
));
580 RegisterBlockAndWakeupHandlers(XdmcpBlockHandler
, XdmcpWakeupHandler
,
583 DisplayNumber
= (CARD16
) atoi(display
);
592 state
= XDM_INIT_STATE
;
593 if (state
!= XDM_OFF
) {
594 RegisterBlockAndWakeupHandlers(XdmcpBlockHandler
, XdmcpWakeupHandler
,
602 * Called whenever a new connection is created; notices the
603 * first connection and saves it to terminate the session
608 XdmcpOpenDisplay(int sock
)
610 if (state
!= XDM_AWAIT_MANAGE_RESPONSE
)
612 state
= XDM_RUN_SESSION
;
613 sessionSocket
= sock
;
617 XdmcpCloseDisplay(int sock
)
619 if ((state
!= XDM_RUN_SESSION
&& state
!= XDM_AWAIT_ALIVE_RESPONSE
)
620 || sessionSocket
!= sock
)
622 state
= XDM_INIT_STATE
;
624 dispatchException
|= DE_TERMINATE
;
626 dispatchException
|= DE_RESET
;
627 isItTimeToYield
= TRUE
;
631 * called before going to sleep, this routine
632 * may modify the timeout value about to be sent
633 * to select; in this way XDMCP can do appropriate things
634 * dynamically while starting up
637 /*ARGSUSED*/ static void
638 XdmcpBlockHandler(pointer data
, /* unused */
639 struct timeval
**wt
, pointer pReadmask
)
641 fd_set
*LastSelectMask
= (fd_set
*) pReadmask
;
644 if (state
== XDM_OFF
)
646 FD_SET(xdmcpSocket
, LastSelectMask
);
647 #if defined(IPv6) && defined(AF_INET6)
648 if (xdmcpSocket6
>= 0)
649 FD_SET(xdmcpSocket6
, LastSelectMask
);
651 if (timeOutTime
== 0)
653 millisToGo
= timeOutTime
- GetTimeInMillis();
654 if ((int) millisToGo
< 0)
656 AdjustWaitForDelay(wt
, millisToGo
);
660 * called after select returns; this routine will
661 * recognise when XDMCP packets await and
662 * process them appropriately
665 /*ARGSUSED*/ static void
666 XdmcpWakeupHandler(pointer data
, /* unused */
667 int i
, pointer pReadmask
)
669 fd_set
*LastSelectMask
= (fd_set
*) pReadmask
;
670 fd_set devicesReadable
;
672 if (state
== XDM_OFF
)
675 if (FD_ISSET(xdmcpSocket
, LastSelectMask
)) {
676 receive_packet(xdmcpSocket
);
677 FD_CLR(xdmcpSocket
, LastSelectMask
);
679 #if defined(IPv6) && defined(AF_INET6)
680 if (xdmcpSocket6
>= 0 && FD_ISSET(xdmcpSocket6
, LastSelectMask
)) {
681 receive_packet(xdmcpSocket6
);
682 FD_CLR(xdmcpSocket6
, LastSelectMask
);
685 XFD_ANDSET(&devicesReadable
, LastSelectMask
, &EnabledDevices
);
686 if (XFD_ANYSET(&devicesReadable
)) {
687 if (state
== XDM_AWAIT_USER_INPUT
)
689 else if (state
== XDM_RUN_SESSION
)
690 keepaliveDormancy
= defaultKeepaliveDormancy
;
692 if (XFD_ANYSET(&AllClients
) && state
== XDM_RUN_SESSION
)
693 timeOutTime
= GetTimeInMillis() + keepaliveDormancy
* 1000;
695 else if (timeOutTime
&& (int) (GetTimeInMillis() - timeOutTime
) >= 0) {
696 if (state
== XDM_RUN_SESSION
) {
697 state
= XDM_KEEPALIVE
;
706 * This routine should be called from the routine that drives the
707 * user's host menu when the user selects a host
711 XdmcpSelectHost(const struct sockaddr
*host_sockaddr
,
712 int host_len
, ARRAY8Ptr AuthenticationName
)
714 state
= XDM_START_CONNECTION
;
715 memmove(&req_sockaddr
, host_sockaddr
, host_len
);
716 req_socklen
= host_len
;
717 XdmcpSetAuthentication(AuthenticationName
);
722 * !!! this routine should be replaced by a routine that adds
723 * the host to the user's host menu. the current version just
724 * selects the first host to respond with willing message.
727 /*ARGSUSED*/ static void
728 XdmcpAddHost(const struct sockaddr
*from
,
730 ARRAY8Ptr AuthenticationName
, ARRAY8Ptr hostname
, ARRAY8Ptr status
)
732 XdmcpSelectHost(from
, fromlen
, AuthenticationName
);
736 * A message is queued on the socket; read it and
737 * do the appropriate thing
740 static ARRAY8 UnwillingMessage
= { (CARD8
) 14, (CARD8
*) "Host unwilling" };
743 receive_packet(int socketfd
)
745 #if defined(IPv6) && defined(AF_INET6)
746 struct sockaddr_storage from
;
748 struct sockaddr_in from
;
750 int fromlen
= sizeof(from
);
753 /* read message off socket */
754 if (!XdmcpFill(socketfd
, &buffer
, (XdmcpNetaddr
) &from
, &fromlen
))
757 /* reset retransmission backoff */
760 if (!XdmcpReadHeader(&buffer
, &header
))
763 if (header
.version
!= XDM_PROTOCOL_VERSION
)
766 switch (header
.opcode
) {
768 recv_willing_msg((struct sockaddr
*) &from
, fromlen
, header
.length
);
771 XdmcpFatal("Manager unwilling", &UnwillingMessage
);
774 recv_accept_msg(header
.length
);
777 recv_decline_msg(header
.length
);
780 recv_refuse_msg(header
.length
);
783 recv_failed_msg(header
.length
);
786 recv_alive_msg(header
.length
);
792 * send the appropriate message given the current state
804 #if defined(IPv6) && defined(AF_INET6)
809 case XDM_START_CONNECTION
:
816 send_keepalive_msg();
821 rtx
= (XDM_MIN_RTX
<< timeOutRtx
);
822 if (rtx
> XDM_MAX_RTX
)
824 timeOutTime
= GetTimeInMillis() + rtx
* 1000;
828 * The session is declared dead for some reason; too many
829 * timeouts, or Keepalive failure.
833 XdmcpDeadSession(const char *reason
)
835 ErrorF("XDM: %s, declaring session dead\n", reason
);
836 state
= XDM_INIT_STATE
;
837 isItTimeToYield
= TRUE
;
838 dispatchException
|= DE_RESET
;
845 * Timeout waiting for an XDMCP response.
852 if (state
== XDM_AWAIT_ALIVE_RESPONSE
&& timeOutRtx
>= XDM_KA_RTX_LIMIT
) {
853 XdmcpDeadSession("too many keepalive retransmissions");
856 else if (timeOutRtx
>= XDM_RTX_LIMIT
) {
857 /* Quit if "-once" specified, otherwise reset and try again. */
859 dispatchException
|= DE_TERMINATE
;
860 ErrorF("XDM: too many retransmissions\n");
863 XdmcpDeadSession("too many retransmissions");
868 #if defined(IPv6) && defined(AF_INET6)
869 if (state
== XDM_COLLECT_QUERY
|| state
== XDM_COLLECT_INDIRECT_QUERY
) {
870 /* Try next address */
871 for (mgrAddr
= mgrAddr
->ai_next
;; mgrAddr
= mgrAddr
->ai_next
) {
872 if (mgrAddr
== NULL
) {
873 mgrAddr
= mgrAddrFirst
;
875 if (mgrAddr
->ai_family
== AF_INET
|| mgrAddr
->ai_family
== AF_INET6
)
879 ManagerAddressLen
= mgrAddr
->ai_addrlen
;
881 memcpy(&ManagerAddress
, mgrAddr
->ai_addr
, mgrAddr
->ai_addrlen
);
886 case XDM_COLLECT_QUERY
:
889 case XDM_COLLECT_BROADCAST_QUERY
:
890 state
= XDM_BROADCAST
;
892 #if defined(IPv6) && defined(AF_INET6)
893 case XDM_COLLECT_MULTICAST_QUERY
:
894 state
= XDM_MULTICAST
;
897 case XDM_COLLECT_INDIRECT_QUERY
:
898 state
= XDM_INDIRECT
;
900 case XDM_AWAIT_REQUEST_RESPONSE
:
901 state
= XDM_START_CONNECTION
;
903 case XDM_AWAIT_MANAGE_RESPONSE
:
906 case XDM_AWAIT_ALIVE_RESPONSE
:
907 state
= XDM_KEEPALIVE
;
918 state
= XDM_INIT_STATE
;
924 XdmcpCheckAuthentication(ARRAY8Ptr Name
, ARRAY8Ptr Data
, int packet_type
)
926 return (XdmcpARRAY8Equal(Name
, AuthenticationName
) &&
927 (AuthenticationName
->length
== 0 ||
928 (*AuthenticationFuncs
->Validator
) (AuthenticationData
, Data
,
933 XdmcpAddAuthorization(ARRAY8Ptr name
, ARRAY8Ptr data
)
935 AddAuthorFunc AddAuth
;
937 if (AuthenticationFuncs
&& AuthenticationFuncs
->AddAuth
)
938 AddAuth
= AuthenticationFuncs
->AddAuth
;
940 AddAuth
= AddAuthorization
;
941 return (*AddAuth
) ((unsigned short) name
->length
,
943 (unsigned short) data
->length
, (char *) data
->data
);
947 * from here to the end of this file are routines private
948 * to the state machine.
955 struct netconfig
*nconf
;
957 if ((xdmcpSocket
= t_open("/dev/udp", O_RDWR
, 0)) < 0) {
958 XdmcpWarning("t_open() of /dev/udp failed");
962 if (t_bind(xdmcpSocket
, NULL
, NULL
) < 0) {
963 XdmcpWarning("UDP socket creation failed");
964 t_error("t_bind(xdmcpSocket) failed");
965 t_close(xdmcpSocket
);
970 * This part of the code looks contrived. It will actually fit in nicely
971 * when the CLTS part of Xtrans is implemented.
974 if ((nconf
= getnetconfigent("udp")) == NULL
) {
975 XdmcpWarning("UDP socket creation failed: getnetconfigent()");
976 t_unbind(xdmcpSocket
);
977 t_close(xdmcpSocket
);
981 if (netdir_options(nconf
, ND_SET_BROADCAST
, xdmcpSocket
, NULL
)) {
982 XdmcpWarning("UDP set broadcast option failed: netdir_options()");
983 freenetconfigent(nconf
);
984 t_unbind(xdmcpSocket
);
985 t_close(xdmcpSocket
);
989 freenetconfigent(nconf
);
993 #if defined(IPv6) && defined(AF_INET6)
994 if ((xdmcpSocket6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
995 XdmcpWarning("INET6 UDP socket creation failed");
997 if ((xdmcpSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
998 XdmcpWarning("UDP socket creation failed");
1000 else if (setsockopt(xdmcpSocket
, SOL_SOCKET
, SO_BROADCAST
, (char *) &soopts
,
1001 sizeof(soopts
)) < 0)
1002 XdmcpWarning("UDP set broadcast socket-option failed");
1003 #endif /* SO_BROADCAST */
1004 if (xdmcpSocket
>= 0 && xdm_from
!= NULL
) {
1005 if (bind(xdmcpSocket
, (struct sockaddr
*) &FromAddress
,
1006 FromAddressLen
) < 0) {
1007 FatalError("Xserver: failed to bind to -from address: %s\n",
1011 #endif /* STREAMSCONN */
1015 send_query_msg(void)
1018 Bool broadcast
= FALSE
;
1020 #if defined(IPv6) && defined(AF_INET6)
1021 Bool multicast
= FALSE
;
1024 int socketfd
= xdmcpSocket
;
1026 header
.version
= XDM_PROTOCOL_VERSION
;
1029 header
.opcode
= (CARD16
) QUERY
;
1030 state
= XDM_COLLECT_QUERY
;
1033 header
.opcode
= (CARD16
) BROADCAST_QUERY
;
1034 state
= XDM_COLLECT_BROADCAST_QUERY
;
1037 #if defined(IPv6) && defined(AF_INET6)
1039 header
.opcode
= (CARD16
) BROADCAST_QUERY
;
1040 state
= XDM_COLLECT_MULTICAST_QUERY
;
1045 header
.opcode
= (CARD16
) INDIRECT_QUERY
;
1046 state
= XDM_COLLECT_INDIRECT_QUERY
;
1052 for (i
= 0; i
< AuthenticationNames
.length
; i
++)
1053 header
.length
+= 2 + AuthenticationNames
.data
[i
].length
;
1055 XdmcpWriteHeader(&buffer
, &header
);
1056 XdmcpWriteARRAYofARRAY8(&buffer
, &AuthenticationNames
);
1060 for (i
= 0; i
< NumBroadcastAddresses
; i
++)
1061 XdmcpFlush(xdmcpSocket
, &buffer
,
1062 (XdmcpNetaddr
) &BroadcastAddresses
[i
],
1063 sizeof(struct sockaddr_in
));
1065 #if defined(IPv6) && defined(AF_INET6)
1066 else if (multicast
) {
1067 struct multicastinfo
*mcl
;
1068 struct addrinfo
*ai
;
1070 for (mcl
= mcastlist
; mcl
!= NULL
; mcl
= mcl
->next
) {
1071 for (ai
= mcl
->ai
; ai
!= NULL
; ai
= ai
->ai_next
) {
1072 if (ai
->ai_family
== AF_INET
) {
1073 unsigned char hopflag
= (unsigned char) mcl
->hops
;
1075 socketfd
= xdmcpSocket
;
1076 setsockopt(socketfd
, IPPROTO_IP
, IP_MULTICAST_TTL
,
1077 &hopflag
, sizeof(hopflag
));
1079 else if (ai
->ai_family
== AF_INET6
) {
1080 int hopflag6
= mcl
->hops
;
1082 socketfd
= xdmcpSocket6
;
1083 setsockopt(socketfd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
1084 &hopflag6
, sizeof(hopflag6
));
1089 XdmcpFlush(socketfd
, &buffer
,
1090 (XdmcpNetaddr
) ai
->ai_addr
, ai
->ai_addrlen
);
1097 #if defined(IPv6) && defined(AF_INET6)
1098 if (SOCKADDR_FAMILY(ManagerAddress
) == AF_INET6
)
1099 socketfd
= xdmcpSocket6
;
1101 XdmcpFlush(socketfd
, &buffer
, (XdmcpNetaddr
) &ManagerAddress
,
1107 recv_willing_msg(struct sockaddr
*from
, int fromlen
, unsigned length
)
1109 ARRAY8 authenticationName
;
1113 authenticationName
.data
= 0;
1116 if (XdmcpReadARRAY8(&buffer
, &authenticationName
) &&
1117 XdmcpReadARRAY8(&buffer
, &hostname
) &&
1118 XdmcpReadARRAY8(&buffer
, &status
)) {
1119 if (length
== 6 + authenticationName
.length
+
1120 hostname
.length
+ status
.length
) {
1122 case XDM_COLLECT_QUERY
:
1123 XdmcpSelectHost(from
, fromlen
, &authenticationName
);
1125 case XDM_COLLECT_BROADCAST_QUERY
:
1126 #if defined(IPv6) && defined(AF_INET6)
1127 case XDM_COLLECT_MULTICAST_QUERY
:
1129 case XDM_COLLECT_INDIRECT_QUERY
:
1130 XdmcpAddHost(from
, fromlen
, &authenticationName
, &hostname
,
1138 XdmcpDisposeARRAY8(&authenticationName
);
1139 XdmcpDisposeARRAY8(&hostname
);
1140 XdmcpDisposeARRAY8(&status
);
1144 send_request_msg(void)
1149 CARD16 XdmcpConnectionType
;
1150 ARRAY8 authenticationData
;
1151 int socketfd
= xdmcpSocket
;
1153 switch (SOCKADDR_FAMILY(ManagerAddress
)) {
1155 XdmcpConnectionType
= FamilyInternet
;
1157 #if defined(IPv6) && defined(AF_INET6)
1159 XdmcpConnectionType
= FamilyInternet6
;
1163 XdmcpConnectionType
= 0xffff;
1167 header
.version
= XDM_PROTOCOL_VERSION
;
1168 header
.opcode
= (CARD16
) REQUEST
;
1170 length
= 2; /* display number */
1171 length
+= 1 + 2 * ConnectionTypes
.length
; /* connection types */
1172 length
+= 1; /* connection addresses */
1173 for (i
= 0; i
< ConnectionAddresses
.length
; i
++)
1174 length
+= 2 + ConnectionAddresses
.data
[i
].length
;
1175 authenticationData
.length
= 0;
1176 authenticationData
.data
= 0;
1177 if (AuthenticationFuncs
) {
1178 (*AuthenticationFuncs
->Generator
) (AuthenticationData
,
1179 &authenticationData
, REQUEST
);
1181 length
+= 2 + AuthenticationName
->length
; /* authentication name */
1182 length
+= 2 + authenticationData
.length
; /* authentication data */
1183 length
+= 1; /* authorization names */
1184 for (i
= 0; i
< AuthorizationNames
.length
; i
++)
1185 length
+= 2 + AuthorizationNames
.data
[i
].length
;
1186 length
+= 2 + ManufacturerDisplayID
.length
; /* display ID */
1187 header
.length
= length
;
1189 if (!XdmcpWriteHeader(&buffer
, &header
)) {
1190 XdmcpDisposeARRAY8(&authenticationData
);
1193 XdmcpWriteCARD16(&buffer
, DisplayNumber
);
1194 XdmcpWriteCARD8(&buffer
, ConnectionTypes
.length
);
1196 /* The connection array is send reordered, so that connections of */
1197 /* the same address type as the XDMCP manager connection are send */
1198 /* first. This works around a bug in xdm. mario@klebsch.de */
1199 for (i
= 0; i
< (int) ConnectionTypes
.length
; i
++)
1200 if (ConnectionTypes
.data
[i
] == XdmcpConnectionType
)
1201 XdmcpWriteCARD16(&buffer
, ConnectionTypes
.data
[i
]);
1202 for (i
= 0; i
< (int) ConnectionTypes
.length
; i
++)
1203 if (ConnectionTypes
.data
[i
] != XdmcpConnectionType
)
1204 XdmcpWriteCARD16(&buffer
, ConnectionTypes
.data
[i
]);
1206 XdmcpWriteCARD8(&buffer
, ConnectionAddresses
.length
);
1207 for (i
= 0; i
< (int) ConnectionAddresses
.length
; i
++)
1208 if ((i
< ConnectionTypes
.length
) &&
1209 (ConnectionTypes
.data
[i
] == XdmcpConnectionType
))
1210 XdmcpWriteARRAY8(&buffer
, &ConnectionAddresses
.data
[i
]);
1211 for (i
= 0; i
< (int) ConnectionAddresses
.length
; i
++)
1212 if ((i
>= ConnectionTypes
.length
) ||
1213 (ConnectionTypes
.data
[i
] != XdmcpConnectionType
))
1214 XdmcpWriteARRAY8(&buffer
, &ConnectionAddresses
.data
[i
]);
1216 XdmcpWriteARRAY8(&buffer
, AuthenticationName
);
1217 XdmcpWriteARRAY8(&buffer
, &authenticationData
);
1218 XdmcpDisposeARRAY8(&authenticationData
);
1219 XdmcpWriteARRAYofARRAY8(&buffer
, &AuthorizationNames
);
1220 XdmcpWriteARRAY8(&buffer
, &ManufacturerDisplayID
);
1221 #if defined(IPv6) && defined(AF_INET6)
1222 if (SOCKADDR_FAMILY(req_sockaddr
) == AF_INET6
)
1223 socketfd
= xdmcpSocket6
;
1225 if (XdmcpFlush(socketfd
, &buffer
,
1226 (XdmcpNetaddr
) &req_sockaddr
, req_socklen
))
1227 state
= XDM_AWAIT_REQUEST_RESPONSE
;
1231 recv_accept_msg(unsigned length
)
1233 CARD32 AcceptSessionID
;
1234 ARRAY8 AcceptAuthenticationName
, AcceptAuthenticationData
;
1235 ARRAY8 AcceptAuthorizationName
, AcceptAuthorizationData
;
1237 if (state
!= XDM_AWAIT_REQUEST_RESPONSE
)
1239 AcceptAuthenticationName
.data
= 0;
1240 AcceptAuthenticationData
.data
= 0;
1241 AcceptAuthorizationName
.data
= 0;
1242 AcceptAuthorizationData
.data
= 0;
1243 if (XdmcpReadCARD32(&buffer
, &AcceptSessionID
) &&
1244 XdmcpReadARRAY8(&buffer
, &AcceptAuthenticationName
) &&
1245 XdmcpReadARRAY8(&buffer
, &AcceptAuthenticationData
) &&
1246 XdmcpReadARRAY8(&buffer
, &AcceptAuthorizationName
) &&
1247 XdmcpReadARRAY8(&buffer
, &AcceptAuthorizationData
)) {
1248 if (length
== 12 + AcceptAuthenticationName
.length
+
1249 AcceptAuthenticationData
.length
+
1250 AcceptAuthorizationName
.length
+ AcceptAuthorizationData
.length
) {
1251 if (!XdmcpCheckAuthentication(&AcceptAuthenticationName
,
1252 &AcceptAuthenticationData
, ACCEPT
)) {
1253 XdmcpFatal("Authentication Failure", &AcceptAuthenticationName
);
1255 /* permit access control manipulations from this host */
1256 AugmentSelf(&req_sockaddr
, req_socklen
);
1257 /* if the authorization specified in the packet fails
1258 * to be acceptable, enable the local addresses
1260 if (!XdmcpAddAuthorization(&AcceptAuthorizationName
,
1261 &AcceptAuthorizationData
)) {
1264 SessionID
= AcceptSessionID
;
1269 XdmcpDisposeARRAY8(&AcceptAuthenticationName
);
1270 XdmcpDisposeARRAY8(&AcceptAuthenticationData
);
1271 XdmcpDisposeARRAY8(&AcceptAuthorizationName
);
1272 XdmcpDisposeARRAY8(&AcceptAuthorizationData
);
1276 recv_decline_msg(unsigned length
)
1278 ARRAY8 status
, DeclineAuthenticationName
, DeclineAuthenticationData
;
1281 DeclineAuthenticationName
.data
= 0;
1282 DeclineAuthenticationData
.data
= 0;
1283 if (XdmcpReadARRAY8(&buffer
, &status
) &&
1284 XdmcpReadARRAY8(&buffer
, &DeclineAuthenticationName
) &&
1285 XdmcpReadARRAY8(&buffer
, &DeclineAuthenticationData
)) {
1286 if (length
== 6 + status
.length
+
1287 DeclineAuthenticationName
.length
+
1288 DeclineAuthenticationData
.length
&&
1289 XdmcpCheckAuthentication(&DeclineAuthenticationName
,
1290 &DeclineAuthenticationData
, DECLINE
)) {
1291 XdmcpFatal("Session declined", &status
);
1294 XdmcpDisposeARRAY8(&status
);
1295 XdmcpDisposeARRAY8(&DeclineAuthenticationName
);
1296 XdmcpDisposeARRAY8(&DeclineAuthenticationData
);
1300 send_manage_msg(void)
1303 int socketfd
= xdmcpSocket
;
1305 header
.version
= XDM_PROTOCOL_VERSION
;
1306 header
.opcode
= (CARD16
) MANAGE
;
1307 header
.length
= 8 + DisplayClass
.length
;
1309 if (!XdmcpWriteHeader(&buffer
, &header
))
1311 XdmcpWriteCARD32(&buffer
, SessionID
);
1312 XdmcpWriteCARD16(&buffer
, DisplayNumber
);
1313 XdmcpWriteARRAY8(&buffer
, &DisplayClass
);
1314 state
= XDM_AWAIT_MANAGE_RESPONSE
;
1315 #if defined(IPv6) && defined(AF_INET6)
1316 if (SOCKADDR_FAMILY(req_sockaddr
) == AF_INET6
)
1317 socketfd
= xdmcpSocket6
;
1319 XdmcpFlush(socketfd
, &buffer
, (XdmcpNetaddr
) &req_sockaddr
, req_socklen
);
1323 recv_refuse_msg(unsigned length
)
1325 CARD32 RefusedSessionID
;
1327 if (state
!= XDM_AWAIT_MANAGE_RESPONSE
)
1331 if (XdmcpReadCARD32(&buffer
, &RefusedSessionID
)) {
1332 if (RefusedSessionID
== SessionID
) {
1333 state
= XDM_START_CONNECTION
;
1340 recv_failed_msg(unsigned length
)
1342 CARD32 FailedSessionID
;
1345 if (state
!= XDM_AWAIT_MANAGE_RESPONSE
)
1348 if (XdmcpReadCARD32(&buffer
, &FailedSessionID
) &&
1349 XdmcpReadARRAY8(&buffer
, &status
)) {
1350 if (length
== 6 + status
.length
&& SessionID
== FailedSessionID
) {
1351 XdmcpFatal("Session failed", &status
);
1354 XdmcpDisposeARRAY8(&status
);
1358 send_keepalive_msg(void)
1361 int socketfd
= xdmcpSocket
;
1363 header
.version
= XDM_PROTOCOL_VERSION
;
1364 header
.opcode
= (CARD16
) KEEPALIVE
;
1367 XdmcpWriteHeader(&buffer
, &header
);
1368 XdmcpWriteCARD16(&buffer
, DisplayNumber
);
1369 XdmcpWriteCARD32(&buffer
, SessionID
);
1371 state
= XDM_AWAIT_ALIVE_RESPONSE
;
1372 #if defined(IPv6) && defined(AF_INET6)
1373 if (SOCKADDR_FAMILY(req_sockaddr
) == AF_INET6
)
1374 socketfd
= xdmcpSocket6
;
1376 XdmcpFlush(socketfd
, &buffer
, (XdmcpNetaddr
) &req_sockaddr
, req_socklen
);
1380 recv_alive_msg(unsigned length
)
1382 CARD8 SessionRunning
;
1383 CARD32 AliveSessionID
;
1385 if (state
!= XDM_AWAIT_ALIVE_RESPONSE
)
1389 if (XdmcpReadCARD8(&buffer
, &SessionRunning
) &&
1390 XdmcpReadCARD32(&buffer
, &AliveSessionID
)) {
1391 if (SessionRunning
&& AliveSessionID
== SessionID
) {
1392 /* backoff dormancy period */
1393 state
= XDM_RUN_SESSION
;
1394 if ((GetTimeInMillis() - LastEventTime(XIAllDevices
).milliseconds
) >
1395 keepaliveDormancy
* 1000) {
1396 keepaliveDormancy
<<= 1;
1397 if (keepaliveDormancy
> XDM_MAX_DORMANCY
)
1398 keepaliveDormancy
= XDM_MAX_DORMANCY
;
1400 timeOutTime
= GetTimeInMillis() + keepaliveDormancy
* 1000;
1403 XdmcpDeadSession("Alive response indicates session dead");
1409 XdmcpFatal(const char *type
, ARRAY8Ptr status
)
1411 FatalError("XDMCP fatal error: %s %*.*s\n", type
,
1412 status
->length
, status
->length
, status
->data
);
1416 XdmcpWarning(const char *str
)
1418 ErrorF("XDMCP warning: %s\n", str
);
1422 get_addr_by_name(const char *argtype
,
1423 const char *namestr
,
1425 int socktype
, SOCKADDR_TYPE
* addr
, SOCKLEN_TYPE
* addrlen
1426 #if defined(IPv6) && defined(AF_INET6)
1427 , struct addrinfo
**aip
, struct addrinfo
**aifirstp
1431 #if defined(IPv6) && defined(AF_INET6)
1432 struct addrinfo
*ai
;
1433 struct addrinfo hints
;
1435 char *pport
= portstr
;
1438 memset(&hints
, 0, sizeof(hints
));
1439 hints
.ai_socktype
= socktype
;
1444 else if (port
> 0 && port
< 65535) {
1445 snprintf(portstr
, sizeof(portstr
), "%d", port
);
1448 FatalError("Xserver: port out of range: %d\n", port
);
1451 if (*aifirstp
!= NULL
) {
1452 freeaddrinfo(*aifirstp
);
1456 if ((gaierr
= getaddrinfo(namestr
, pport
, &hints
, aifirstp
)) == 0) {
1457 for (ai
= *aifirstp
; ai
!= NULL
; ai
= ai
->ai_next
) {
1458 if (ai
->ai_family
== AF_INET
|| ai
->ai_family
== AF_INET6
)
1461 if ((ai
== NULL
) || (ai
->ai_addrlen
> sizeof(SOCKADDR_TYPE
))) {
1462 FatalError("Xserver: %s host %s not on supported network type\n",
1467 *addrlen
= ai
->ai_addrlen
;
1468 memcpy(addr
, ai
->ai_addr
, ai
->ai_addrlen
);
1472 FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr
), argtype
,
1476 struct hostent
*hep
;
1478 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1479 _Xgethostbynameparams hparams
;
1481 #if defined(WIN32) && defined(TCPCONN)
1482 _XSERVTransWSAStartup();
1484 if (!(hep
= _XGethostbyname(namestr
, hparams
))) {
1485 FatalError("Xserver: %s unknown host: %s\n", argtype
, namestr
);
1487 if (hep
->h_length
== sizeof(struct in_addr
)) {
1488 memmove(&addr
->sin_addr
, hep
->h_addr
, hep
->h_length
);
1489 *addrlen
= sizeof(struct sockaddr_in
);
1490 addr
->sin_family
= AF_INET
;
1491 addr
->sin_port
= htons(port
);
1494 FatalError("Xserver: %s host on strange network %s\n", argtype
,
1501 get_manager_by_name(int argc
, char **argv
, int i
)
1504 if ((i
+ 1) == argc
) {
1505 FatalError("Xserver: missing %s host name in command line\n", argv
[i
]);
1508 get_addr_by_name(argv
[i
], argv
[i
+ 1], xdm_udp_port
, SOCK_DGRAM
,
1509 &ManagerAddress
, &ManagerAddressLen
1510 #if defined(IPv6) && defined(AF_INET6)
1511 , &mgrAddr
, &mgrAddrFirst
1517 get_fromaddr_by_name(int argc
, char **argv
, int i
)
1519 #if defined(IPv6) && defined(AF_INET6)
1520 struct addrinfo
*ai
= NULL
;
1521 struct addrinfo
*aifirst
= NULL
;
1524 FatalError("Xserver: missing -from host name in command line\n");
1526 get_addr_by_name("-from", argv
[i
], 0, 0, &FromAddress
, &FromAddressLen
1527 #if defined(IPv6) && defined(AF_INET6)
1531 #if defined(IPv6) && defined(AF_INET6)
1532 if (aifirst
!= NULL
)
1533 freeaddrinfo(aifirst
);
1538 #if defined(IPv6) && defined(AF_INET6)
1540 get_mcast_options(int argc
, char **argv
, int i
)
1542 const char *address
= XDM_DEFAULT_MCAST_ADDR6
;
1544 struct addrinfo hints
;
1547 struct addrinfo
*ai
, *firstai
;
1549 if ((i
< argc
) && (argv
[i
][0] != '-') && (argv
[i
][0] != '+')) {
1550 address
= argv
[i
++];
1551 if ((i
< argc
) && (argv
[i
][0] != '-') && (argv
[i
][0] != '+')) {
1552 hopcount
= strtol(argv
[i
++], NULL
, 10);
1553 if ((hopcount
< 1) || (hopcount
> 255)) {
1554 FatalError("Xserver: multicast hop count out of range: %d\n",
1560 if (xdm_udp_port
> 0 && xdm_udp_port
< 65535) {
1561 snprintf(portstr
, sizeof(portstr
), "%d", xdm_udp_port
);
1564 FatalError("Xserver: port out of range: %d\n", xdm_udp_port
);
1566 memset(&hints
, 0, sizeof(hints
));
1567 hints
.ai_socktype
= SOCK_DGRAM
;
1569 if ((gaierr
= getaddrinfo(address
, portstr
, &hints
, &firstai
)) == 0) {
1570 for (ai
= firstai
; ai
!= NULL
; ai
= ai
->ai_next
) {
1571 if (((ai
->ai_family
== AF_INET
) &&
1572 IN_MULTICAST(((struct sockaddr_in
*) ai
->ai_addr
)
1574 || ((ai
->ai_family
== AF_INET6
) &&
1575 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6
*) ai
->ai_addr
)
1580 FatalError("Xserver: address not supported multicast type %s\n",
1584 struct multicastinfo
*mcastinfo
, *mcl
;
1586 mcastinfo
= malloc(sizeof(struct multicastinfo
));
1587 mcastinfo
->next
= NULL
;
1588 mcastinfo
->ai
= firstai
;
1589 mcastinfo
->hops
= hopcount
;
1591 if (mcastlist
== NULL
) {
1592 mcastlist
= mcastinfo
;
1595 for (mcl
= mcastlist
; mcl
->next
!= NULL
; mcl
= mcl
->next
) {
1596 /* Do nothing - just find end of list */
1598 mcl
->next
= mcastinfo
;
1603 FatalError("Xserver: %s: %s\n", gai_strerror(gaierr
), address
);
1610 static int xdmcp_non_empty
; /* avoid complaint by ranlib */