xdmcp.c revision 4642e01f
1/*
2 * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
3 *
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.
13 *
14 */
15
16#ifdef HAVE_DIX_CONFIG_H
17#include <dix-config.h>
18#endif
19
20#ifdef WIN32
21#include <X11/Xwinsock.h>
22#endif
23
24#include <X11/Xos.h>
25
26#if !defined(WIN32)
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <netdb.h>
31#endif
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <X11/X.h>
36#include <X11/Xmd.h>
37#include "misc.h"
38#include <X11/Xpoll.h>
39#include "osdep.h"
40#include "input.h"
41#include "dixstruct.h"
42#include "opaque.h"
43#include "site.h"
44
45#ifdef STREAMSCONN
46#include <tiuser.h>
47#include <netconfig.h>
48#include <netdir.h>
49#endif
50
51#ifdef XDMCP
52#undef REQUEST
53
54#ifdef XDMCP_NO_IPV6
55#undef IPv6
56#endif
57
58#include <X11/Xdmcp.h>
59
60#define X_INCLUDE_NETDB_H
61#include <X11/Xos_r.h>
62
63static char *defaultDisplayClass = COMPILEDDISPLAYCLASS;
64
65static int		    xdmcpSocket, sessionSocket;
66static xdmcp_states	    state;
67#if defined(IPv6) && defined(AF_INET6)
68static int		    xdmcpSocket6;
69static struct sockaddr_storage req_sockaddr;
70#else
71static struct sockaddr_in   req_sockaddr;
72#endif
73static int		    req_socklen;
74static CARD32		    SessionID;
75static CARD32		    timeOutTime;
76static int		    timeOutRtx;
77static CARD32		    defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
78static CARD32		    keepaliveDormancy = XDM_DEF_DORMANCY;
79static CARD16		    DisplayNumber;
80static xdmcp_states	    XDM_INIT_STATE = XDM_OFF;
81#ifdef HASXDMAUTH
82static char		    *xdmAuthCookie;
83#endif
84
85static XdmcpBuffer	    buffer;
86
87#if defined(IPv6) && defined(AF_INET6)
88
89static struct addrinfo *mgrAddr;
90static struct addrinfo *mgrAddrFirst;
91
92#define SOCKADDR_TYPE		struct sockaddr_storage
93#define SOCKADDR_FAMILY(s)	((struct sockaddr *)&(s))->sa_family
94
95#ifdef BSD44SOCKETS
96#define SOCKLEN_FIELD(s)	((struct sockaddr *)&(s))->sa_len
97#define SOCKLEN_TYPE 		unsigned char
98#else
99#define SOCKLEN_TYPE 		unsigned int
100#endif
101
102#else
103
104#define SOCKADDR_TYPE		struct sockaddr_in
105#define SOCKADDR_FAMILY(s)	(s).sin_family
106
107#ifdef BSD44SOCKETS
108#define SOCKLEN_FIELD(s)	(s).sin_len
109#define SOCKLEN_TYPE		unsigned char
110#else
111#define SOCKLEN_TYPE		size_t
112#endif
113
114#endif
115
116static SOCKADDR_TYPE		ManagerAddress;
117static SOCKADDR_TYPE		FromAddress;
118
119#ifdef SOCKLEN_FIELD
120#define ManagerAddressLen	SOCKLEN_FIELD(ManagerAddress)
121#define FromAddressLen		SOCKLEN_FIELD(FromAddress)
122#else
123static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen;
124#endif
125
126#if defined(IPv6) && defined(AF_INET6)
127static struct multicastinfo {
128    struct multicastinfo	*next;
129    struct addrinfo		*ai;
130    int				 hops;
131} *mcastlist;
132#endif
133
134static void XdmcpAddHost(
135    struct sockaddr    *from,
136    int			fromlen,
137    ARRAY8Ptr		AuthenticationName,
138    ARRAY8Ptr		hostname,
139    ARRAY8Ptr		status);
140
141static void XdmcpSelectHost(
142    struct sockaddr	*host_sockaddr,
143    int			host_len,
144    ARRAY8Ptr		AuthenticationName);
145
146static void get_xdmcp_sock(void);
147
148static void send_query_msg(void);
149
150static void recv_willing_msg(
151    struct sockaddr * /*from*/,
152    int /*fromlen*/,
153    unsigned /*length*/);
154
155static void send_request_msg(void);
156
157static void recv_accept_msg(unsigned /*length*/);
158
159static void recv_decline_msg(unsigned /*length*/);
160
161static void send_manage_msg(void);
162
163static void recv_refuse_msg(unsigned /*length*/);
164
165static void recv_failed_msg(unsigned /*length*/);
166
167static void send_keepalive_msg(void);
168
169static void recv_alive_msg(unsigned /*length*/);
170
171static void XdmcpFatal(
172    char * /*type*/,
173    ARRAY8Ptr /*status*/);
174
175static void XdmcpWarning(char * /*str*/);
176
177static void get_manager_by_name(
178    int /*argc*/,
179    char ** /*argv*/,
180    int /*i*/);
181
182static void get_fromaddr_by_name(int /*argc*/, char ** /*argv*/, int /*i*/);
183
184#if defined(IPv6) && defined(AF_INET6)
185static int get_mcast_options(int /*argc*/, char ** /*argv*/, int /*i*/);
186#endif
187
188static void receive_packet(int /*socketfd*/);
189
190static void send_packet(void);
191
192static void timeout(void);
193
194static void restart(void);
195
196static void XdmcpBlockHandler(
197    pointer /*data*/,
198    struct timeval ** /*wt*/,
199    pointer /*LastSelectMask*/);
200
201static void XdmcpWakeupHandler(
202    pointer /*data*/,
203    int /*i*/,
204    pointer /*LastSelectMask*/);
205
206/*
207 * Register the Manufacturer display ID
208 */
209
210static ARRAY8 ManufacturerDisplayID;
211
212static void
213XdmcpRegisterManufacturerDisplayID (char *name, int length)
214{
215    int	    i;
216
217    XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
218    if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
219	return;
220    for (i = 0; i < length; i++)
221	ManufacturerDisplayID.data[i] = (CARD8) name[i];
222}
223
224static unsigned short	xdm_udp_port = XDM_UDP_PORT;
225static Bool	OneSession = FALSE;
226static const char 	*xdm_from = NULL;
227
228void
229XdmcpUseMsg (void)
230{
231    ErrorF("-query host-name       contact named host for XDMCP\n");
232    ErrorF("-broadcast             broadcast for XDMCP\n");
233#if defined(IPv6) && defined(AF_INET6)
234    ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n");
235#endif
236    ErrorF("-indirect host-name    contact named host for indirect XDMCP\n");
237    ErrorF("-port port-num         UDP port number to send messages to\n");
238    ErrorF("-from local-address    specify the local address to connect from\n");
239    ErrorF("-once                  Terminate server after one session\n");
240    ErrorF("-class display-class   specify display class to send in manage\n");
241#ifdef HASXDMAUTH
242    ErrorF("-cookie xdm-auth-bits  specify the magic cookie for XDMCP\n");
243#endif
244    ErrorF("-displayID display-id  manufacturer display ID for request\n");
245}
246
247int
248XdmcpOptions(int argc, char **argv, int i)
249{
250    if (strcmp(argv[i], "-query") == 0) {
251	get_manager_by_name(argc, argv, i++);
252	XDM_INIT_STATE = XDM_QUERY;
253	AccessUsingXdmcp ();
254	return (i + 1);
255    }
256    if (strcmp(argv[i], "-broadcast") == 0) {
257	XDM_INIT_STATE = XDM_BROADCAST;
258	AccessUsingXdmcp ();
259	return (i + 1);
260    }
261#if defined(IPv6) && defined(AF_INET6)
262    if (strcmp(argv[i], "-multicast") == 0) {
263	i = get_mcast_options(argc, argv, ++i);
264	XDM_INIT_STATE = XDM_MULTICAST;
265	AccessUsingXdmcp ();
266	return (i + 1);
267    }
268#endif
269    if (strcmp(argv[i], "-indirect") == 0) {
270	get_manager_by_name(argc, argv, i++);
271	XDM_INIT_STATE = XDM_INDIRECT;
272	AccessUsingXdmcp ();
273	return (i + 1);
274    }
275    if (strcmp(argv[i], "-port") == 0) {
276        if (++i == argc)  {
277	    FatalError("Xserver: missing port number in command line\n");
278	}
279	xdm_udp_port = (unsigned short) atoi(argv[i]);
280	return (i + 1);
281    }
282    if (strcmp(argv[i], "-from") == 0) {
283	get_fromaddr_by_name(argc, argv, ++i);
284	return (i + 1);
285    }
286    if (strcmp(argv[i], "-once") == 0) {
287	OneSession = TRUE;
288	return (i + 1);
289    }
290    if (strcmp(argv[i], "-class") == 0) {
291        if (++i == argc)  {
292	    FatalError("Xserver: missing class name in command line\n");
293	}
294	defaultDisplayClass = argv[i];
295	return (i + 1);
296    }
297#ifdef HASXDMAUTH
298    if (strcmp(argv[i], "-cookie") == 0) {
299        if (++i == argc)  {
300	    FatalError("Xserver: missing cookie data in command line\n");
301	}
302	xdmAuthCookie = argv[i];
303	return (i + 1);
304    }
305#endif
306    if (strcmp(argv[i], "-displayID") == 0) {
307        if (++i == argc)  {
308	    FatalError("Xserver: missing displayID in command line\n");
309	}
310	XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
311	return (i + 1);
312    }
313    return (i);
314}
315
316/*
317 * This section is a collection of routines for
318 * registering server-specific data with the XDMCP
319 * state machine.
320 */
321
322
323/*
324 * Save all broadcast addresses away so BroadcastQuery
325 * packets get sent everywhere
326 */
327
328#define MAX_BROADCAST	10
329
330/* This stays sockaddr_in since IPv6 doesn't support broadcast */
331static struct sockaddr_in   BroadcastAddresses[MAX_BROADCAST];
332static int		    NumBroadcastAddresses;
333
334void
335XdmcpRegisterBroadcastAddress (struct sockaddr_in *addr)
336{
337    struct sockaddr_in	*bcast;
338    if (NumBroadcastAddresses >= MAX_BROADCAST)
339	return;
340    bcast = &BroadcastAddresses[NumBroadcastAddresses++];
341    bzero (bcast, sizeof (struct sockaddr_in));
342#ifdef BSD44SOCKETS
343    bcast->sin_len = addr->sin_len;
344#endif
345    bcast->sin_family = addr->sin_family;
346    bcast->sin_port = htons (xdm_udp_port);
347    bcast->sin_addr = addr->sin_addr;
348}
349
350/*
351 * Each authentication type is registered here; Validator
352 * will be called to check all access attempts using
353 * the specified authentication type
354 */
355
356static ARRAYofARRAY8	AuthenticationNames, AuthenticationDatas;
357typedef struct _AuthenticationFuncs {
358    ValidatorFunc    Validator;
359    GeneratorFunc    Generator;
360    AddAuthorFunc    AddAuth;
361} AuthenticationFuncsRec, *AuthenticationFuncsPtr;
362
363static AuthenticationFuncsPtr	AuthenticationFuncsList;
364
365void
366XdmcpRegisterAuthentication (
367    char    *name,
368    int	    namelen,
369    char    *data,
370    int	    datalen,
371    ValidatorFunc Validator,
372    GeneratorFunc Generator,
373    AddAuthorFunc AddAuth)
374{
375    int	    i;
376    ARRAY8  AuthenticationName, AuthenticationData;
377    static AuthenticationFuncsPtr	newFuncs;
378
379    if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
380	return;
381    if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
382    {
383	XdmcpDisposeARRAY8 (&AuthenticationName);
384	return;
385    }
386    for (i = 0; i < namelen; i++)
387	AuthenticationName.data[i] = name[i];
388    for (i = 0; i < datalen; i++)
389	AuthenticationData.data[i] = data[i];
390    if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
391				     AuthenticationNames.length + 1) &&
392	  XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
393				     AuthenticationDatas.length + 1) &&
394	  (newFuncs = (AuthenticationFuncsPtr) xalloc (
395			(AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
396    {
397	XdmcpDisposeARRAY8 (&AuthenticationName);
398	XdmcpDisposeARRAY8 (&AuthenticationData);
399	return;
400    }
401    for (i = 0; i < AuthenticationNames.length - 1; i++)
402	newFuncs[i] = AuthenticationFuncsList[i];
403    newFuncs[AuthenticationNames.length-1].Validator = Validator;
404    newFuncs[AuthenticationNames.length-1].Generator = Generator;
405    newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
406    xfree (AuthenticationFuncsList);
407    AuthenticationFuncsList = newFuncs;
408    AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
409    AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
410}
411
412/*
413 * Select the authentication type to be used; this is
414 * set by the manager of the host to be connected to.
415 */
416
417static ARRAY8		noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
418static ARRAY8		noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
419static ARRAY8Ptr	AuthenticationName = &noAuthenticationName;
420static ARRAY8Ptr	AuthenticationData = &noAuthenticationData;
421static AuthenticationFuncsPtr	AuthenticationFuncs;
422
423static void
424XdmcpSetAuthentication (ARRAY8Ptr name)
425{
426    int	i;
427
428    for (i = 0; i < AuthenticationNames.length; i++)
429	if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
430	{
431	    AuthenticationName = &AuthenticationNames.data[i];
432	    AuthenticationData = &AuthenticationDatas.data[i];
433	    AuthenticationFuncs = &AuthenticationFuncsList[i];
434	    break;
435	}
436}
437
438/*
439 * Register the host address for the display
440 */
441
442static ARRAY16		ConnectionTypes;
443static ARRAYofARRAY8	ConnectionAddresses;
444static long		xdmcpGeneration;
445
446void
447XdmcpRegisterConnection (
448    int	    type,
449    char    *address,
450    int	    addrlen)
451{
452    int	    i;
453    CARD8   *newAddress;
454
455    if (xdmcpGeneration != serverGeneration)
456    {
457	XdmcpDisposeARRAY16 (&ConnectionTypes);
458	XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
459	xdmcpGeneration = serverGeneration;
460    }
461    if (xdm_from != NULL) {	/* Only register the requested address */
462	const void *regAddr = address;
463	const void *fromAddr = NULL;
464	int regAddrlen = addrlen;
465
466	if (addrlen == sizeof(struct in_addr)) {
467	    if (SOCKADDR_FAMILY(FromAddress) == AF_INET) {
468		fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr;
469	    }
470#if defined(IPv6) && defined(AF_INET6)
471	    else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) &&
472	      IN6_IS_ADDR_V4MAPPED(
473		  &((struct sockaddr_in6 *)&FromAddress)->sin6_addr)) {
474		fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr.s6_addr[12];
475	    }
476#endif
477	}
478#if defined(IPv6) && defined(AF_INET6)
479	else if (addrlen == sizeof(struct in6_addr)) {
480	    if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) {
481		fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr;
482	    } else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) &&
483	      IN6_IS_ADDR_V4MAPPED((struct in6_addr *) address)) {
484		fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr;
485		regAddr = &((struct sockaddr_in6 *)&address)->sin6_addr.s6_addr[12];
486		regAddrlen = sizeof(struct in_addr);
487	    }
488	}
489#endif
490	if (fromAddr && memcmp(regAddr, fromAddr, regAddrlen) != 0) {
491	    return;
492	}
493    }
494    newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8));
495    if (!newAddress)
496	return;
497    if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
498    {
499	xfree (newAddress);
500	return;
501    }
502    if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
503				    ConnectionAddresses.length +  1))
504    {
505	xfree (newAddress);
506	return;
507    }
508    ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
509    for (i = 0; i < addrlen; i++)
510	newAddress[i] = address[i];
511    ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
512    ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
513}
514
515/*
516 * Register an Authorization Name.  XDMCP advertises this list
517 * to the manager.
518 */
519
520static ARRAYofARRAY8	AuthorizationNames;
521
522void
523XdmcpRegisterAuthorizations (void)
524{
525    XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
526    RegisterAuthorizations ();
527}
528
529void
530XdmcpRegisterAuthorization (char *name, int namelen)
531{
532    ARRAY8  authName;
533    int	    i;
534
535    authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
536    if (!authName.data)
537	return;
538    if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
539    {
540	xfree (authName.data);
541	return;
542    }
543    for (i = 0; i < namelen; i++)
544	authName.data[i] = (CARD8) name[i];
545    authName.length = namelen;
546    AuthorizationNames.data[AuthorizationNames.length-1] = authName;
547}
548
549/*
550 * Register the DisplayClass string
551 */
552
553static ARRAY8	DisplayClass;
554
555static void
556XdmcpRegisterDisplayClass (char *name, int length)
557{
558    int	    i;
559
560    XdmcpDisposeARRAY8 (&DisplayClass);
561    if (!XdmcpAllocARRAY8 (&DisplayClass, length))
562	return;
563    for (i = 0; i < length; i++)
564	DisplayClass.data[i] = (CARD8) name[i];
565}
566
567/*
568 * initialize XDMCP; create the socket, compute the display
569 * number, set up the state machine
570 */
571
572void
573XdmcpInit(void)
574{
575    state = XDM_INIT_STATE;
576#ifdef HASXDMAUTH
577    if (xdmAuthCookie)
578	XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
579#endif
580    if (state != XDM_OFF)
581    {
582	XdmcpRegisterAuthorizations();
583	XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
584	AccessUsingXdmcp();
585	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
586				        (pointer) 0);
587    	timeOutRtx = 0;
588    	DisplayNumber = (CARD16) atoi(display);
589    	get_xdmcp_sock();
590    	send_packet();
591    }
592}
593
594void
595XdmcpReset (void)
596{
597    state = XDM_INIT_STATE;
598    if (state != XDM_OFF)
599    {
600	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
601				        (pointer) 0);
602    	timeOutRtx = 0;
603    	send_packet();
604    }
605}
606
607/*
608 * Called whenever a new connection is created; notices the
609 * first connection and saves it to terminate the session
610 * when it is closed
611 */
612
613void
614XdmcpOpenDisplay(int sock)
615{
616    if (state != XDM_AWAIT_MANAGE_RESPONSE)
617	return;
618    state = XDM_RUN_SESSION;
619    sessionSocket = sock;
620}
621
622void
623XdmcpCloseDisplay(int sock)
624{
625    if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
626	|| sessionSocket != sock)
627	    return;
628    state = XDM_INIT_STATE;
629    if (OneSession)
630	dispatchException |= DE_TERMINATE;
631    else
632	dispatchException |= DE_RESET;
633    isItTimeToYield = TRUE;
634}
635
636/*
637 * called before going to sleep, this routine
638 * may modify the timeout value about to be sent
639 * to select; in this way XDMCP can do appropriate things
640 * dynamically while starting up
641 */
642
643/*ARGSUSED*/
644static void
645XdmcpBlockHandler(
646    pointer	    data,   /* unused */
647    struct timeval  **wt,
648    pointer	    pReadmask)
649{
650    fd_set *LastSelectMask = (fd_set*)pReadmask;
651    CARD32 millisToGo;
652
653    if (state == XDM_OFF)
654	return;
655    FD_SET(xdmcpSocket, LastSelectMask);
656#if defined(IPv6) && defined(AF_INET6)
657    if (xdmcpSocket6 >= 0)
658	FD_SET(xdmcpSocket6, LastSelectMask);
659#endif
660    if (timeOutTime == 0)
661	return;
662    millisToGo = timeOutTime - GetTimeInMillis();
663    if ((int) millisToGo < 0)
664	millisToGo = 0;
665    AdjustWaitForDelay (wt, millisToGo);
666}
667
668/*
669 * called after select returns; this routine will
670 * recognise when XDMCP packets await and
671 * process them appropriately
672 */
673
674/*ARGSUSED*/
675static void
676XdmcpWakeupHandler(
677    pointer data,   /* unused */
678    int	    i,
679    pointer pReadmask)
680{
681    fd_set* LastSelectMask = (fd_set*)pReadmask;
682    fd_set   devicesReadable;
683
684    if (state == XDM_OFF)
685	return;
686    if (i > 0)
687    {
688	if (FD_ISSET(xdmcpSocket, LastSelectMask))
689	{
690	    receive_packet(xdmcpSocket);
691	    FD_CLR(xdmcpSocket, LastSelectMask);
692	}
693#if defined(IPv6) && defined(AF_INET6)
694	if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask))
695	{
696	    receive_packet(xdmcpSocket6);
697	    FD_CLR(xdmcpSocket6, LastSelectMask);
698	}
699#endif
700	XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
701	if (XFD_ANYSET(&devicesReadable))
702	{
703	    if (state == XDM_AWAIT_USER_INPUT)
704		restart();
705	    else if (state == XDM_RUN_SESSION)
706		keepaliveDormancy = defaultKeepaliveDormancy;
707	}
708	if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
709	    timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
710    }
711    else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0)
712    {
713    	if (state == XDM_RUN_SESSION)
714    	{
715	    state = XDM_KEEPALIVE;
716	    send_packet();
717    	}
718    	else
719	    timeout();
720    }
721}
722
723/*
724 * This routine should be called from the routine that drives the
725 * user's host menu when the user selects a host
726 */
727
728static void
729XdmcpSelectHost(
730    struct sockaddr	*host_sockaddr,
731    int			host_len,
732    ARRAY8Ptr		AuthenticationName)
733{
734    state = XDM_START_CONNECTION;
735    memmove(&req_sockaddr, host_sockaddr, host_len);
736    req_socklen = host_len;
737    XdmcpSetAuthentication (AuthenticationName);
738    send_packet();
739}
740
741/*
742 * !!! this routine should be replaced by a routine that adds
743 * the host to the user's host menu. the current version just
744 * selects the first host to respond with willing message.
745 */
746
747/*ARGSUSED*/
748static void
749XdmcpAddHost(
750    struct sockaddr    *from,
751    int			fromlen,
752    ARRAY8Ptr		AuthenticationName,
753    ARRAY8Ptr		hostname,
754    ARRAY8Ptr		status)
755{
756    XdmcpSelectHost(from, fromlen, AuthenticationName);
757}
758
759/*
760 * A message is queued on the socket; read it and
761 * do the appropriate thing
762 */
763
764static ARRAY8	UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
765
766static void
767receive_packet(int socketfd)
768{
769#if defined(IPv6) && defined(AF_INET6)
770    struct sockaddr_storage from;
771#else
772    struct sockaddr_in from;
773#endif
774    int fromlen = sizeof(from);
775    XdmcpHeader	header;
776
777    /* read message off socket */
778    if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &from, &fromlen))
779	return;
780
781    /* reset retransmission backoff */
782    timeOutRtx = 0;
783
784    if (!XdmcpReadHeader (&buffer, &header))
785	return;
786
787    if (header.version != XDM_PROTOCOL_VERSION)
788	return;
789
790    switch (header.opcode) {
791    case WILLING:
792	recv_willing_msg((struct sockaddr *) &from, fromlen, header.length);
793	break;
794    case UNWILLING:
795	XdmcpFatal("Manager unwilling", &UnwillingMessage);
796	break;
797    case ACCEPT:
798	recv_accept_msg(header.length);
799	break;
800    case DECLINE:
801	recv_decline_msg(header.length);
802	break;
803    case REFUSE:
804	recv_refuse_msg(header.length);
805	break;
806    case FAILED:
807	recv_failed_msg(header.length);
808	break;
809    case ALIVE:
810	recv_alive_msg(header.length);
811	break;
812    }
813}
814
815/*
816 * send the appropriate message given the current state
817 */
818
819static void
820send_packet(void)
821{
822    int rtx;
823    switch (state) {
824    case XDM_QUERY:
825    case XDM_BROADCAST:
826    case XDM_INDIRECT:
827#if defined(IPv6)  && defined(AF_INET6)
828    case XDM_MULTICAST:
829#endif
830	send_query_msg();
831	break;
832    case XDM_START_CONNECTION:
833	send_request_msg();
834	break;
835    case XDM_MANAGE:
836	send_manage_msg();
837	break;
838    case XDM_KEEPALIVE:
839	send_keepalive_msg();
840	break;
841    default:
842	break;
843    }
844    rtx = (XDM_MIN_RTX << timeOutRtx);
845    if (rtx > XDM_MAX_RTX)
846	rtx = XDM_MAX_RTX;
847    timeOutTime = GetTimeInMillis() + rtx * 1000;
848}
849
850/*
851 * The session is declared dead for some reason; too many
852 * timeouts, or Keepalive failure.
853 */
854
855static void
856XdmcpDeadSession (char *reason)
857{
858    ErrorF ("XDM: %s, declaring session dead\n", reason);
859    state = XDM_INIT_STATE;
860    isItTimeToYield = TRUE;
861    dispatchException |= DE_RESET;
862    timeOutTime = 0;
863    timeOutRtx = 0;
864    send_packet();
865}
866
867/*
868 * Timeout waiting for an XDMCP response.
869 */
870
871static void
872timeout(void)
873{
874    timeOutRtx++;
875    if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
876    {
877	XdmcpDeadSession ("too many keepalive retransmissions");
878	return;
879    }
880    else if (timeOutRtx >= XDM_RTX_LIMIT)
881    {
882	/* Quit if "-once" specified, otherwise reset and try again. */
883        if (OneSession) {
884	    dispatchException |= DE_TERMINATE;
885	    ErrorF("XDM: too many retransmissions\n");
886	} else {
887	    XdmcpDeadSession("too many retransmissions");
888	}
889	return;
890    }
891
892#if defined(IPv6) && defined(AF_INET6)
893    if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) {
894	/* Try next address */
895	for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) {
896	    if (mgrAddr == NULL) {
897		mgrAddr = mgrAddrFirst;
898	    }
899	    if (mgrAddr->ai_family == AF_INET
900	      || mgrAddr->ai_family == AF_INET6)
901		break;
902	}
903#ifndef SIN6_LEN
904	ManagerAddressLen = mgrAddr->ai_addrlen;
905#endif
906	memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen);
907    }
908#endif
909
910    switch (state) {
911    case XDM_COLLECT_QUERY:
912	state = XDM_QUERY;
913	break;
914    case XDM_COLLECT_BROADCAST_QUERY:
915	state = XDM_BROADCAST;
916	break;
917#if defined(IPv6) && defined(AF_INET6)
918    case XDM_COLLECT_MULTICAST_QUERY:
919	state = XDM_MULTICAST;
920	break;
921#endif
922    case XDM_COLLECT_INDIRECT_QUERY:
923	state = XDM_INDIRECT;
924	break;
925    case XDM_AWAIT_REQUEST_RESPONSE:
926	state = XDM_START_CONNECTION;
927	break;
928    case XDM_AWAIT_MANAGE_RESPONSE:
929	state = XDM_MANAGE;
930	break;
931    case XDM_AWAIT_ALIVE_RESPONSE:
932	state = XDM_KEEPALIVE;
933	break;
934    default:
935	break;
936    }
937    send_packet();
938}
939
940static void
941restart(void)
942{
943    state = XDM_INIT_STATE;
944    timeOutRtx = 0;
945    send_packet();
946}
947
948static int
949XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type)
950{
951    return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
952	    (AuthenticationName->length == 0 ||
953	     (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
954}
955
956static int
957XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data)
958{
959    AddAuthorFunc AddAuth;
960
961    if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
962	AddAuth = AuthenticationFuncs->AddAuth;
963    else
964	AddAuth = AddAuthorization;
965    return (*AddAuth) ((unsigned short)name->length,
966		       (char *)name->data,
967		       (unsigned short)data->length,
968		       (char *)data->data);
969}
970
971/*
972 * from here to the end of this file are routines private
973 * to the state machine.
974 */
975
976static void
977get_xdmcp_sock(void)
978{
979#ifdef STREAMSCONN
980    struct netconfig *nconf;
981
982    if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
983	XdmcpWarning("t_open() of /dev/udp failed");
984	return;
985    }
986
987    if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) {
988	XdmcpWarning("UDP socket creation failed");
989	t_error("t_bind(xdmcpSocket) failed" );
990	t_close(xdmcpSocket);
991	return;
992    }
993
994    /*
995     * This part of the code looks contrived. It will actually fit in nicely
996     * when the CLTS part of Xtrans is implemented.
997     */
998
999    if( (nconf=getnetconfigent("udp")) == NULL ) {
1000	XdmcpWarning("UDP socket creation failed: getnetconfigent()");
1001	t_unbind(xdmcpSocket);
1002	t_close(xdmcpSocket);
1003	return;
1004    }
1005
1006    if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) {
1007	XdmcpWarning("UDP set broadcast option failed: netdir_options()");
1008	freenetconfigent(nconf);
1009	t_unbind(xdmcpSocket);
1010	t_close(xdmcpSocket);
1011	return;
1012    }
1013
1014    freenetconfigent(nconf);
1015#else
1016    int soopts = 1;
1017
1018#if defined(IPv6) && defined(AF_INET6)
1019    if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1020	XdmcpWarning("INET6 UDP socket creation failed");
1021#endif
1022    if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1023	XdmcpWarning("UDP socket creation failed");
1024#ifdef SO_BROADCAST
1025    else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
1026	sizeof(soopts)) < 0)
1027	    XdmcpWarning("UDP set broadcast socket-option failed");
1028#endif /* SO_BROADCAST */
1029    if (xdmcpSocket >= 0 && xdm_from != NULL) {
1030	if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress,
1031		 FromAddressLen) < 0) {
1032	    FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from);
1033	}
1034    }
1035#endif /* STREAMSCONN */
1036}
1037
1038static void
1039send_query_msg(void)
1040{
1041    XdmcpHeader	header;
1042    Bool	broadcast = FALSE;
1043#if defined(IPv6) && defined(AF_INET6)
1044    Bool	multicast = FALSE;
1045#endif
1046    int		i;
1047    int 	socketfd = xdmcpSocket;
1048
1049    header.version = XDM_PROTOCOL_VERSION;
1050    switch(state){
1051    case XDM_QUERY:
1052	header.opcode = (CARD16) QUERY;
1053	state = XDM_COLLECT_QUERY;
1054	break;
1055    case XDM_BROADCAST:
1056	header.opcode = (CARD16) BROADCAST_QUERY;
1057	state = XDM_COLLECT_BROADCAST_QUERY;
1058	broadcast = TRUE;
1059	break;
1060#if defined(IPv6) && defined(AF_INET6)
1061    case XDM_MULTICAST:
1062	header.opcode = (CARD16) BROADCAST_QUERY;
1063	state = XDM_COLLECT_MULTICAST_QUERY;
1064	multicast = TRUE;
1065	break;
1066#endif
1067    case XDM_INDIRECT:
1068	header.opcode = (CARD16) INDIRECT_QUERY;
1069	state = XDM_COLLECT_INDIRECT_QUERY;
1070	break;
1071    default:
1072	break;
1073    }
1074    header.length = 1;
1075    for (i = 0; i < AuthenticationNames.length; i++)
1076	header.length += 2 + AuthenticationNames.data[i].length;
1077
1078    XdmcpWriteHeader (&buffer, &header);
1079    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
1080    if (broadcast)
1081    {
1082	int i;
1083
1084	for (i = 0; i < NumBroadcastAddresses; i++)
1085	    XdmcpFlush (xdmcpSocket, &buffer, (XdmcpNetaddr) &BroadcastAddresses[i],
1086			sizeof (struct sockaddr_in));
1087    }
1088#if defined(IPv6) && defined(AF_INET6)
1089    else if (multicast)
1090    {
1091	struct multicastinfo *mcl;
1092	struct addrinfo *ai;
1093
1094	for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) {
1095	    for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) {
1096		if (ai->ai_family == AF_INET) {
1097		    unsigned char hopflag = (unsigned char) mcl->hops;
1098		    socketfd = xdmcpSocket;
1099		    setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
1100		      &hopflag, sizeof(hopflag));
1101		} else if (ai->ai_family == AF_INET6) {
1102		    int hopflag6 = mcl->hops;
1103		    socketfd = xdmcpSocket6;
1104		    setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1105		      &hopflag6, sizeof(hopflag6));
1106		} else {
1107		    continue;
1108		}
1109		XdmcpFlush (socketfd, &buffer,
1110		  	    (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
1111		break;
1112	    }
1113	}
1114    }
1115#endif
1116    else
1117    {
1118#if defined(IPv6) && defined(AF_INET6)
1119	if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
1120	    socketfd = xdmcpSocket6;
1121#endif
1122	XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress,
1123		    ManagerAddressLen);
1124    }
1125}
1126
1127static void
1128recv_willing_msg(
1129    struct sockaddr	*from,
1130    int			fromlen,
1131    unsigned		length)
1132{
1133    ARRAY8	authenticationName;
1134    ARRAY8	hostname;
1135    ARRAY8	status;
1136
1137    authenticationName.data = 0;
1138    hostname.data = 0;
1139    status.data = 0;
1140    if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
1141	XdmcpReadARRAY8 (&buffer, &hostname) &&
1142	XdmcpReadARRAY8 (&buffer, &status))
1143    {
1144    	if (length == 6 + authenticationName.length +
1145		      hostname.length + status.length)
1146    	{
1147	    switch (state)
1148	    {
1149	    case XDM_COLLECT_QUERY:
1150	    	XdmcpSelectHost(from, fromlen, &authenticationName);
1151	    	break;
1152	    case XDM_COLLECT_BROADCAST_QUERY:
1153#if defined(IPv6) && defined(AF_INET6)
1154	    case XDM_COLLECT_MULTICAST_QUERY:
1155#endif
1156	    case XDM_COLLECT_INDIRECT_QUERY:
1157	    	XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
1158	    	break;
1159	    default:
1160		break;
1161    	    }
1162    	}
1163    }
1164    XdmcpDisposeARRAY8 (&authenticationName);
1165    XdmcpDisposeARRAY8 (&hostname);
1166    XdmcpDisposeARRAY8 (&status);
1167}
1168
1169static void
1170send_request_msg(void)
1171{
1172    XdmcpHeader	    header;
1173    int		    length;
1174    int		    i;
1175    CARD16	    XdmcpConnectionType;
1176    ARRAY8	    authenticationData;
1177    int		    socketfd = xdmcpSocket;
1178
1179    switch (SOCKADDR_FAMILY(ManagerAddress))
1180    {
1181    case AF_INET:	XdmcpConnectionType=FamilyInternet; break;
1182#if defined(IPv6) && defined(AF_INET6)
1183    case AF_INET6:	XdmcpConnectionType=FamilyInternet6; break;
1184#endif
1185    default:		XdmcpConnectionType=0xffff; break;
1186    }
1187
1188    header.version = XDM_PROTOCOL_VERSION;
1189    header.opcode = (CARD16) REQUEST;
1190
1191    length = 2;					    /* display number */
1192    length += 1 + 2 * ConnectionTypes.length;	    /* connection types */
1193    length += 1;				    /* connection addresses */
1194    for (i = 0; i < ConnectionAddresses.length; i++)
1195	length += 2 + ConnectionAddresses.data[i].length;
1196    authenticationData.length = 0;
1197    authenticationData.data = 0;
1198    if (AuthenticationFuncs)
1199    {
1200	(*AuthenticationFuncs->Generator) (AuthenticationData,
1201					   &authenticationData,
1202 					   REQUEST);
1203    }
1204    length += 2 + AuthenticationName->length;	    /* authentication name */
1205    length += 2 + authenticationData.length;	    /* authentication data */
1206    length += 1;				    /* authorization names */
1207    for (i = 0; i < AuthorizationNames.length; i++)
1208	length += 2 + AuthorizationNames.data[i].length;
1209    length += 2 + ManufacturerDisplayID.length;	    /* display ID */
1210    header.length = length;
1211
1212    if (!XdmcpWriteHeader (&buffer, &header))
1213    {
1214	XdmcpDisposeARRAY8 (&authenticationData);
1215	return;
1216    }
1217    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1218    XdmcpWriteCARD8 (&buffer, ConnectionTypes.length);
1219
1220    /* The connection array is send reordered, so that connections of	*/
1221    /* the same address type as the XDMCP manager connection are send	*/
1222    /* first. This works around a bug in xdm. mario@klebsch.de 		*/
1223    for (i = 0; i < (int)ConnectionTypes.length; i++)
1224	if (ConnectionTypes.data[i]==XdmcpConnectionType)
1225	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1226    for (i = 0; i < (int)ConnectionTypes.length; i++)
1227	if (ConnectionTypes.data[i]!=XdmcpConnectionType)
1228	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1229
1230    XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length);
1231    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1232	if ( (i<ConnectionTypes.length) &&
1233	     (ConnectionTypes.data[i]==XdmcpConnectionType) )
1234	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1235    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1236	if ( (i>=ConnectionTypes.length) ||
1237	     (ConnectionTypes.data[i]!=XdmcpConnectionType) )
1238	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1239
1240    XdmcpWriteARRAY8 (&buffer, AuthenticationName);
1241    XdmcpWriteARRAY8 (&buffer, &authenticationData);
1242    XdmcpDisposeARRAY8 (&authenticationData);
1243    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
1244    XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
1245#if defined(IPv6) && defined(AF_INET6)
1246    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1247	socketfd = xdmcpSocket6;
1248#endif
1249    if (XdmcpFlush (socketfd, &buffer,
1250			(XdmcpNetaddr) &req_sockaddr, req_socklen))
1251	state = XDM_AWAIT_REQUEST_RESPONSE;
1252}
1253
1254static void
1255recv_accept_msg(unsigned length)
1256{
1257    CARD32  AcceptSessionID;
1258    ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
1259    ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
1260
1261    if (state != XDM_AWAIT_REQUEST_RESPONSE)
1262	return;
1263    AcceptAuthenticationName.data = 0;
1264    AcceptAuthenticationData.data = 0;
1265    AcceptAuthorizationName.data = 0;
1266    AcceptAuthorizationData.data = 0;
1267    if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
1268	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
1269	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
1270	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
1271	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
1272    {
1273    	if (length == 12 + AcceptAuthenticationName.length +
1274		      	   AcceptAuthenticationData.length +
1275		      	   AcceptAuthorizationName.length +
1276 		      	   AcceptAuthorizationData.length)
1277    	{
1278	    if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
1279				      &AcceptAuthenticationData, ACCEPT))
1280	    {
1281		XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
1282	    }
1283	    /* permit access control manipulations from this host */
1284	    AugmentSelf (&req_sockaddr, req_socklen);
1285	    /* if the authorization specified in the packet fails
1286	     * to be acceptable, enable the local addresses
1287	     */
1288	    if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
1289					&AcceptAuthorizationData))
1290	    {
1291		AddLocalHosts ();
1292	    }
1293	    SessionID = AcceptSessionID;
1294    	    state = XDM_MANAGE;
1295    	    send_packet();
1296    	}
1297    }
1298    XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
1299    XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
1300    XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
1301    XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
1302}
1303
1304static void
1305recv_decline_msg(unsigned length)
1306{
1307    ARRAY8  status, DeclineAuthenticationName, DeclineAuthenticationData;
1308
1309    status.data = 0;
1310    DeclineAuthenticationName.data = 0;
1311    DeclineAuthenticationData.data = 0;
1312    if (XdmcpReadARRAY8 (&buffer, &status) &&
1313	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
1314	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
1315    {
1316    	if (length == 6 + status.length +
1317		      	  DeclineAuthenticationName.length +
1318 		      	  DeclineAuthenticationData.length &&
1319	    XdmcpCheckAuthentication (&DeclineAuthenticationName,
1320				      &DeclineAuthenticationData, DECLINE))
1321    	{
1322	    XdmcpFatal ("Session declined", &status);
1323    	}
1324    }
1325    XdmcpDisposeARRAY8 (&status);
1326    XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
1327    XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
1328}
1329
1330static void
1331send_manage_msg(void)
1332{
1333    XdmcpHeader	header;
1334    int socketfd = xdmcpSocket;
1335
1336    header.version = XDM_PROTOCOL_VERSION;
1337    header.opcode = (CARD16) MANAGE;
1338    header.length = 8 + DisplayClass.length;
1339
1340    if (!XdmcpWriteHeader (&buffer, &header))
1341	return;
1342    XdmcpWriteCARD32 (&buffer, SessionID);
1343    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1344    XdmcpWriteARRAY8 (&buffer, &DisplayClass);
1345    state = XDM_AWAIT_MANAGE_RESPONSE;
1346#if defined(IPv6) && defined(AF_INET6)
1347    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1348	socketfd = xdmcpSocket6;
1349#endif
1350    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1351}
1352
1353static void
1354recv_refuse_msg(unsigned length)
1355{
1356    CARD32  RefusedSessionID;
1357
1358    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1359	return;
1360    if (length != 4)
1361	return;
1362    if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
1363    {
1364	if (RefusedSessionID == SessionID)
1365	{
1366    	    state = XDM_START_CONNECTION;
1367    	    send_packet();
1368	}
1369    }
1370}
1371
1372static void
1373recv_failed_msg(unsigned length)
1374{
1375    CARD32  FailedSessionID;
1376    ARRAY8  status;
1377
1378    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1379	return;
1380    status.data = 0;
1381    if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
1382	XdmcpReadARRAY8 (&buffer, &status))
1383    {
1384    	if (length == 6 + status.length &&
1385	    SessionID == FailedSessionID)
1386	{
1387	    XdmcpFatal ("Session failed", &status);
1388	}
1389    }
1390    XdmcpDisposeARRAY8 (&status);
1391}
1392
1393static void
1394send_keepalive_msg(void)
1395{
1396    XdmcpHeader	header;
1397    int socketfd = xdmcpSocket;
1398
1399    header.version = XDM_PROTOCOL_VERSION;
1400    header.opcode = (CARD16) KEEPALIVE;
1401    header.length = 6;
1402
1403    XdmcpWriteHeader (&buffer, &header);
1404    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1405    XdmcpWriteCARD32 (&buffer, SessionID);
1406
1407    state = XDM_AWAIT_ALIVE_RESPONSE;
1408#if defined(IPv6) && defined(AF_INET6)
1409    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1410	socketfd = xdmcpSocket6;
1411#endif
1412    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1413}
1414
1415static void
1416recv_alive_msg (unsigned length)
1417{
1418    CARD8   SessionRunning;
1419    CARD32  AliveSessionID;
1420
1421    if (state != XDM_AWAIT_ALIVE_RESPONSE)
1422	return;
1423    if (length != 5)
1424	return;
1425    if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
1426	XdmcpReadCARD32 (&buffer, &AliveSessionID))
1427    {
1428    	if (SessionRunning && AliveSessionID == SessionID)
1429    	{
1430	    /* backoff dormancy period */
1431	    state = XDM_RUN_SESSION;
1432	    if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
1433		keepaliveDormancy * 1000)
1434	    {
1435		keepaliveDormancy <<= 1;
1436		if (keepaliveDormancy > XDM_MAX_DORMANCY)
1437		    keepaliveDormancy = XDM_MAX_DORMANCY;
1438	    }
1439	    timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
1440    	}
1441	else
1442    	{
1443	    XdmcpDeadSession ("Alive response indicates session dead");
1444    	}
1445    }
1446}
1447
1448static  void
1449XdmcpFatal (
1450    char	*type,
1451    ARRAY8Ptr	status)
1452{
1453    FatalError ("XDMCP fatal error: %s %*.*s\n", type,
1454	   status->length, status->length, status->data);
1455}
1456
1457static  void
1458XdmcpWarning(char *str)
1459{
1460    ErrorF("XDMCP warning: %s\n", str);
1461}
1462
1463static void
1464get_addr_by_name(
1465    char *	argtype,
1466    char *	namestr,
1467    int		port,
1468    int		socktype,
1469    SOCKADDR_TYPE *addr,
1470    SOCKLEN_TYPE *addrlen
1471#if defined(IPv6) && defined(AF_INET6)
1472      ,
1473    struct addrinfo **aip,
1474    struct addrinfo **aifirstp
1475#endif
1476    )
1477{
1478#if defined(IPv6) && defined(AF_INET6)
1479    struct addrinfo *ai;
1480    struct addrinfo hints;
1481    char portstr[6];
1482    char *pport = portstr;
1483    int gaierr;
1484
1485    bzero(&hints, sizeof(hints));
1486    hints.ai_socktype = socktype;
1487
1488    if (port == 0) {
1489	pport = NULL;
1490    } else if (port > 0 && port < 65535) {
1491	sprintf(portstr, "%d", port);
1492    } else {
1493	FatalError("Xserver: port out of range: %d\n", port);
1494    }
1495
1496    if (*aifirstp != NULL) {
1497	freeaddrinfo(*aifirstp);
1498	*aifirstp = NULL;
1499    }
1500
1501    if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) {
1502	for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) {
1503	    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
1504		break;
1505	}
1506	if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) {
1507	    FatalError ("Xserver: %s host %s not on supported network type\n",
1508	      argtype, namestr);
1509	} else {
1510	    *aip = ai;
1511	    *addrlen = ai->ai_addrlen;
1512	    memcpy(addr, ai->ai_addr, ai->ai_addrlen);
1513	}
1514    } else {
1515	FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr);
1516    }
1517#else
1518    struct hostent *hep;
1519#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1520    _Xgethostbynameparams hparams;
1521#endif
1522#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN))
1523    _XSERVTransWSAStartup();
1524#endif
1525    if (!(hep = _XGethostbyname(namestr, hparams)))
1526    {
1527	FatalError("Xserver: %s unknown host: %s\n", argtype, namestr);
1528    }
1529    if (hep->h_length == sizeof (struct in_addr))
1530    {
1531	memmove(&addr->sin_addr, hep->h_addr, hep->h_length);
1532	*addrlen = sizeof(struct sockaddr_in);
1533	addr->sin_family = AF_INET;
1534	addr->sin_port = htons (port);
1535    }
1536    else
1537    {
1538	FatalError("Xserver: %s host on strange network %s\n", argtype, namestr);
1539    }
1540#endif
1541}
1542
1543static void
1544get_manager_by_name(
1545    int	    argc,
1546    char    **argv,
1547    int	    i)
1548{
1549
1550    if ((i + 1) == argc)
1551    {
1552	FatalError("Xserver: missing %s host name in command line\n", argv[i]);
1553    }
1554
1555    get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM,
1556      &ManagerAddress, &ManagerAddressLen
1557#if defined(IPv6) && defined(AF_INET6)
1558      , &mgrAddr, &mgrAddrFirst
1559#endif
1560	);
1561}
1562
1563
1564static void
1565get_fromaddr_by_name(
1566    int	    argc,
1567    char    **argv,
1568    int	    i)
1569{
1570#if defined(IPv6) && defined(AF_INET6)
1571    struct addrinfo *ai = NULL;
1572    struct addrinfo *aifirst = NULL;
1573#endif
1574    if (i == argc)
1575    {
1576	FatalError("Xserver: missing -from host name in command line\n");
1577    }
1578    get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen
1579#if defined(IPv6) && defined(AF_INET6)
1580      , &ai, &aifirst
1581#endif
1582	);
1583#if defined(IPv6) && defined(AF_INET6)
1584    if (aifirst != NULL)
1585	freeaddrinfo(aifirst);
1586#endif
1587    xdm_from = argv[i];
1588}
1589
1590
1591#if defined(IPv6) && defined(AF_INET6)
1592static int
1593get_mcast_options(argc, argv, i)
1594    int	    argc, i;
1595    char    **argv;
1596{
1597    char *address = XDM_DEFAULT_MCAST_ADDR6;
1598    int hopcount = 1;
1599    struct addrinfo hints;
1600    char portstr[6];
1601    int gaierr;
1602    struct addrinfo *ai, *firstai;
1603
1604    if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1605	address = argv[i++];
1606	if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1607	    hopcount = strtol(argv[i++], NULL, 10);
1608	    if ((hopcount < 1) || (hopcount > 255)) {
1609		FatalError("Xserver: multicast hop count out of range: %d\n",
1610		  hopcount);
1611	    }
1612	}
1613    }
1614
1615    if (xdm_udp_port > 0 && xdm_udp_port < 65535) {
1616	sprintf(portstr, "%d", xdm_udp_port);
1617    } else {
1618	FatalError("Xserver: port out of range: %d\n", xdm_udp_port);
1619    }
1620    bzero(&hints, sizeof(hints));
1621    hints.ai_socktype = SOCK_DGRAM;
1622
1623    if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) {
1624	for (ai = firstai; ai != NULL; ai = ai->ai_next) {
1625	    if (((ai->ai_family == AF_INET) &&
1626	      	IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr)
1627							  ->sin_addr.s_addr))
1628		|| ((ai->ai_family == AF_INET6) &&
1629		  IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr)
1630							    ->sin6_addr)))
1631		break;
1632	}
1633	if (ai == NULL) {
1634	    FatalError ("Xserver: address not supported multicast type %s\n",
1635	      address);
1636	} else {
1637	    struct multicastinfo	*mcastinfo, *mcl;
1638
1639	    mcastinfo = malloc(sizeof(struct multicastinfo));
1640	    mcastinfo->next = NULL;
1641	    mcastinfo->ai = firstai;
1642	    mcastinfo->hops = hopcount;
1643
1644	    if (mcastlist == NULL) {
1645		mcastlist = mcastinfo;
1646	    } else {
1647		for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) {
1648		    /* Do nothing  - just find end of list */
1649		}
1650		mcl->next = mcastinfo;
1651	    }
1652	}
1653    } else {
1654	FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address);
1655    }
1656    return i;
1657}
1658#endif
1659
1660#else
1661static int xdmcp_non_empty; /* avoid complaint by ranlib */
1662#endif /* XDMCP */
1663