xdmcp.c revision b86d567b
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    if (ConnectionAddresses.length + 1 == 256)
495	return;
496    newAddress = xalloc (addrlen * sizeof (CARD8));
497    if (!newAddress)
498	return;
499    if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
500    {
501	xfree (newAddress);
502	return;
503    }
504    if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
505				    ConnectionAddresses.length +  1))
506    {
507	xfree (newAddress);
508	return;
509    }
510    ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
511    for (i = 0; i < addrlen; i++)
512	newAddress[i] = address[i];
513    ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
514    ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
515}
516
517/*
518 * Register an Authorization Name.  XDMCP advertises this list
519 * to the manager.
520 */
521
522static ARRAYofARRAY8	AuthorizationNames;
523
524void
525XdmcpRegisterAuthorizations (void)
526{
527    XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
528    RegisterAuthorizations ();
529}
530
531void
532XdmcpRegisterAuthorization (char *name, int namelen)
533{
534    ARRAY8  authName;
535    int	    i;
536
537    authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
538    if (!authName.data)
539	return;
540    if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
541    {
542	xfree (authName.data);
543	return;
544    }
545    for (i = 0; i < namelen; i++)
546	authName.data[i] = (CARD8) name[i];
547    authName.length = namelen;
548    AuthorizationNames.data[AuthorizationNames.length-1] = authName;
549}
550
551/*
552 * Register the DisplayClass string
553 */
554
555static ARRAY8	DisplayClass;
556
557static void
558XdmcpRegisterDisplayClass (char *name, int length)
559{
560    int	    i;
561
562    XdmcpDisposeARRAY8 (&DisplayClass);
563    if (!XdmcpAllocARRAY8 (&DisplayClass, length))
564	return;
565    for (i = 0; i < length; i++)
566	DisplayClass.data[i] = (CARD8) name[i];
567}
568
569/*
570 * initialize XDMCP; create the socket, compute the display
571 * number, set up the state machine
572 */
573
574void
575XdmcpInit(void)
576{
577    state = XDM_INIT_STATE;
578#ifdef HASXDMAUTH
579    if (xdmAuthCookie)
580	XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
581#endif
582    if (state != XDM_OFF)
583    {
584	XdmcpRegisterAuthorizations();
585	XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
586	AccessUsingXdmcp();
587	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
588				        (pointer) 0);
589    	timeOutRtx = 0;
590    	DisplayNumber = (CARD16) atoi(display);
591    	get_xdmcp_sock();
592    	send_packet();
593    }
594}
595
596void
597XdmcpReset (void)
598{
599    state = XDM_INIT_STATE;
600    if (state != XDM_OFF)
601    {
602	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
603				        (pointer) 0);
604    	timeOutRtx = 0;
605    	send_packet();
606    }
607}
608
609/*
610 * Called whenever a new connection is created; notices the
611 * first connection and saves it to terminate the session
612 * when it is closed
613 */
614
615void
616XdmcpOpenDisplay(int sock)
617{
618    if (state != XDM_AWAIT_MANAGE_RESPONSE)
619	return;
620    state = XDM_RUN_SESSION;
621    sessionSocket = sock;
622}
623
624void
625XdmcpCloseDisplay(int sock)
626{
627    if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
628	|| sessionSocket != sock)
629	    return;
630    state = XDM_INIT_STATE;
631    if (OneSession)
632	dispatchException |= DE_TERMINATE;
633    else
634	dispatchException |= DE_RESET;
635    isItTimeToYield = TRUE;
636}
637
638/*
639 * called before going to sleep, this routine
640 * may modify the timeout value about to be sent
641 * to select; in this way XDMCP can do appropriate things
642 * dynamically while starting up
643 */
644
645/*ARGSUSED*/
646static void
647XdmcpBlockHandler(
648    pointer	    data,   /* unused */
649    struct timeval  **wt,
650    pointer	    pReadmask)
651{
652    fd_set *LastSelectMask = (fd_set*)pReadmask;
653    CARD32 millisToGo;
654
655    if (state == XDM_OFF)
656	return;
657    FD_SET(xdmcpSocket, LastSelectMask);
658#if defined(IPv6) && defined(AF_INET6)
659    if (xdmcpSocket6 >= 0)
660	FD_SET(xdmcpSocket6, LastSelectMask);
661#endif
662    if (timeOutTime == 0)
663	return;
664    millisToGo = timeOutTime - GetTimeInMillis();
665    if ((int) millisToGo < 0)
666	millisToGo = 0;
667    AdjustWaitForDelay (wt, millisToGo);
668}
669
670/*
671 * called after select returns; this routine will
672 * recognise when XDMCP packets await and
673 * process them appropriately
674 */
675
676/*ARGSUSED*/
677static void
678XdmcpWakeupHandler(
679    pointer data,   /* unused */
680    int	    i,
681    pointer pReadmask)
682{
683    fd_set* LastSelectMask = (fd_set*)pReadmask;
684    fd_set   devicesReadable;
685
686    if (state == XDM_OFF)
687	return;
688    if (i > 0)
689    {
690	if (FD_ISSET(xdmcpSocket, LastSelectMask))
691	{
692	    receive_packet(xdmcpSocket);
693	    FD_CLR(xdmcpSocket, LastSelectMask);
694	}
695#if defined(IPv6) && defined(AF_INET6)
696	if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask))
697	{
698	    receive_packet(xdmcpSocket6);
699	    FD_CLR(xdmcpSocket6, LastSelectMask);
700	}
701#endif
702	XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
703	if (XFD_ANYSET(&devicesReadable))
704	{
705	    if (state == XDM_AWAIT_USER_INPUT)
706		restart();
707	    else if (state == XDM_RUN_SESSION)
708		keepaliveDormancy = defaultKeepaliveDormancy;
709	}
710	if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
711	    timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
712    }
713    else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0)
714    {
715    	if (state == XDM_RUN_SESSION)
716    	{
717	    state = XDM_KEEPALIVE;
718	    send_packet();
719    	}
720    	else
721	    timeout();
722    }
723}
724
725/*
726 * This routine should be called from the routine that drives the
727 * user's host menu when the user selects a host
728 */
729
730static void
731XdmcpSelectHost(
732    struct sockaddr	*host_sockaddr,
733    int			host_len,
734    ARRAY8Ptr		AuthenticationName)
735{
736    state = XDM_START_CONNECTION;
737    memmove(&req_sockaddr, host_sockaddr, host_len);
738    req_socklen = host_len;
739    XdmcpSetAuthentication (AuthenticationName);
740    send_packet();
741}
742
743/*
744 * !!! this routine should be replaced by a routine that adds
745 * the host to the user's host menu. the current version just
746 * selects the first host to respond with willing message.
747 */
748
749/*ARGSUSED*/
750static void
751XdmcpAddHost(
752    struct sockaddr    *from,
753    int			fromlen,
754    ARRAY8Ptr		AuthenticationName,
755    ARRAY8Ptr		hostname,
756    ARRAY8Ptr		status)
757{
758    XdmcpSelectHost(from, fromlen, AuthenticationName);
759}
760
761/*
762 * A message is queued on the socket; read it and
763 * do the appropriate thing
764 */
765
766static ARRAY8	UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
767
768static void
769receive_packet(int socketfd)
770{
771#if defined(IPv6) && defined(AF_INET6)
772    struct sockaddr_storage from;
773#else
774    struct sockaddr_in from;
775#endif
776    int fromlen = sizeof(from);
777    XdmcpHeader	header;
778
779    /* read message off socket */
780    if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &from, &fromlen))
781	return;
782
783    /* reset retransmission backoff */
784    timeOutRtx = 0;
785
786    if (!XdmcpReadHeader (&buffer, &header))
787	return;
788
789    if (header.version != XDM_PROTOCOL_VERSION)
790	return;
791
792    switch (header.opcode) {
793    case WILLING:
794	recv_willing_msg((struct sockaddr *) &from, fromlen, header.length);
795	break;
796    case UNWILLING:
797	XdmcpFatal("Manager unwilling", &UnwillingMessage);
798	break;
799    case ACCEPT:
800	recv_accept_msg(header.length);
801	break;
802    case DECLINE:
803	recv_decline_msg(header.length);
804	break;
805    case REFUSE:
806	recv_refuse_msg(header.length);
807	break;
808    case FAILED:
809	recv_failed_msg(header.length);
810	break;
811    case ALIVE:
812	recv_alive_msg(header.length);
813	break;
814    }
815}
816
817/*
818 * send the appropriate message given the current state
819 */
820
821static void
822send_packet(void)
823{
824    int rtx;
825    switch (state) {
826    case XDM_QUERY:
827    case XDM_BROADCAST:
828    case XDM_INDIRECT:
829#if defined(IPv6)  && defined(AF_INET6)
830    case XDM_MULTICAST:
831#endif
832	send_query_msg();
833	break;
834    case XDM_START_CONNECTION:
835	send_request_msg();
836	break;
837    case XDM_MANAGE:
838	send_manage_msg();
839	break;
840    case XDM_KEEPALIVE:
841	send_keepalive_msg();
842	break;
843    default:
844	break;
845    }
846    rtx = (XDM_MIN_RTX << timeOutRtx);
847    if (rtx > XDM_MAX_RTX)
848	rtx = XDM_MAX_RTX;
849    timeOutTime = GetTimeInMillis() + rtx * 1000;
850}
851
852/*
853 * The session is declared dead for some reason; too many
854 * timeouts, or Keepalive failure.
855 */
856
857static void
858XdmcpDeadSession (char *reason)
859{
860    ErrorF ("XDM: %s, declaring session dead\n", reason);
861    state = XDM_INIT_STATE;
862    isItTimeToYield = TRUE;
863    dispatchException |= DE_RESET;
864    timeOutTime = 0;
865    timeOutRtx = 0;
866    send_packet();
867}
868
869/*
870 * Timeout waiting for an XDMCP response.
871 */
872
873static void
874timeout(void)
875{
876    timeOutRtx++;
877    if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
878    {
879	XdmcpDeadSession ("too many keepalive retransmissions");
880	return;
881    }
882    else if (timeOutRtx >= XDM_RTX_LIMIT)
883    {
884	/* Quit if "-once" specified, otherwise reset and try again. */
885        if (OneSession) {
886	    dispatchException |= DE_TERMINATE;
887	    ErrorF("XDM: too many retransmissions\n");
888	} else {
889	    XdmcpDeadSession("too many retransmissions");
890	}
891	return;
892    }
893
894#if defined(IPv6) && defined(AF_INET6)
895    if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) {
896	/* Try next address */
897	for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) {
898	    if (mgrAddr == NULL) {
899		mgrAddr = mgrAddrFirst;
900	    }
901	    if (mgrAddr->ai_family == AF_INET
902	      || mgrAddr->ai_family == AF_INET6)
903		break;
904	}
905#ifndef SIN6_LEN
906	ManagerAddressLen = mgrAddr->ai_addrlen;
907#endif
908	memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen);
909    }
910#endif
911
912    switch (state) {
913    case XDM_COLLECT_QUERY:
914	state = XDM_QUERY;
915	break;
916    case XDM_COLLECT_BROADCAST_QUERY:
917	state = XDM_BROADCAST;
918	break;
919#if defined(IPv6) && defined(AF_INET6)
920    case XDM_COLLECT_MULTICAST_QUERY:
921	state = XDM_MULTICAST;
922	break;
923#endif
924    case XDM_COLLECT_INDIRECT_QUERY:
925	state = XDM_INDIRECT;
926	break;
927    case XDM_AWAIT_REQUEST_RESPONSE:
928	state = XDM_START_CONNECTION;
929	break;
930    case XDM_AWAIT_MANAGE_RESPONSE:
931	state = XDM_MANAGE;
932	break;
933    case XDM_AWAIT_ALIVE_RESPONSE:
934	state = XDM_KEEPALIVE;
935	break;
936    default:
937	break;
938    }
939    send_packet();
940}
941
942static void
943restart(void)
944{
945    state = XDM_INIT_STATE;
946    timeOutRtx = 0;
947    send_packet();
948}
949
950static int
951XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type)
952{
953    return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
954	    (AuthenticationName->length == 0 ||
955	     (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
956}
957
958static int
959XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data)
960{
961    AddAuthorFunc AddAuth;
962
963    if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
964	AddAuth = AuthenticationFuncs->AddAuth;
965    else
966	AddAuth = AddAuthorization;
967    return (*AddAuth) ((unsigned short)name->length,
968		       (char *)name->data,
969		       (unsigned short)data->length,
970		       (char *)data->data);
971}
972
973/*
974 * from here to the end of this file are routines private
975 * to the state machine.
976 */
977
978static void
979get_xdmcp_sock(void)
980{
981#ifdef STREAMSCONN
982    struct netconfig *nconf;
983
984    if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
985	XdmcpWarning("t_open() of /dev/udp failed");
986	return;
987    }
988
989    if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) {
990	XdmcpWarning("UDP socket creation failed");
991	t_error("t_bind(xdmcpSocket) failed" );
992	t_close(xdmcpSocket);
993	return;
994    }
995
996    /*
997     * This part of the code looks contrived. It will actually fit in nicely
998     * when the CLTS part of Xtrans is implemented.
999     */
1000
1001    if( (nconf=getnetconfigent("udp")) == NULL ) {
1002	XdmcpWarning("UDP socket creation failed: getnetconfigent()");
1003	t_unbind(xdmcpSocket);
1004	t_close(xdmcpSocket);
1005	return;
1006    }
1007
1008    if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) {
1009	XdmcpWarning("UDP set broadcast option failed: netdir_options()");
1010	freenetconfigent(nconf);
1011	t_unbind(xdmcpSocket);
1012	t_close(xdmcpSocket);
1013	return;
1014    }
1015
1016    freenetconfigent(nconf);
1017#else
1018    int soopts = 1;
1019
1020#if defined(IPv6) && defined(AF_INET6)
1021    if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1022	XdmcpWarning("INET6 UDP socket creation failed");
1023#endif
1024    if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1025	XdmcpWarning("UDP socket creation failed");
1026#ifdef SO_BROADCAST
1027    else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
1028	sizeof(soopts)) < 0)
1029	    XdmcpWarning("UDP set broadcast socket-option failed");
1030#endif /* SO_BROADCAST */
1031    if (xdmcpSocket >= 0 && xdm_from != NULL) {
1032	if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress,
1033		 FromAddressLen) < 0) {
1034	    FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from);
1035	}
1036    }
1037#endif /* STREAMSCONN */
1038}
1039
1040static void
1041send_query_msg(void)
1042{
1043    XdmcpHeader	header;
1044    Bool	broadcast = FALSE;
1045#if defined(IPv6) && defined(AF_INET6)
1046    Bool	multicast = FALSE;
1047#endif
1048    int		i;
1049    int 	socketfd = xdmcpSocket;
1050
1051    header.version = XDM_PROTOCOL_VERSION;
1052    switch(state){
1053    case XDM_QUERY:
1054	header.opcode = (CARD16) QUERY;
1055	state = XDM_COLLECT_QUERY;
1056	break;
1057    case XDM_BROADCAST:
1058	header.opcode = (CARD16) BROADCAST_QUERY;
1059	state = XDM_COLLECT_BROADCAST_QUERY;
1060	broadcast = TRUE;
1061	break;
1062#if defined(IPv6) && defined(AF_INET6)
1063    case XDM_MULTICAST:
1064	header.opcode = (CARD16) BROADCAST_QUERY;
1065	state = XDM_COLLECT_MULTICAST_QUERY;
1066	multicast = TRUE;
1067	break;
1068#endif
1069    case XDM_INDIRECT:
1070	header.opcode = (CARD16) INDIRECT_QUERY;
1071	state = XDM_COLLECT_INDIRECT_QUERY;
1072	break;
1073    default:
1074	break;
1075    }
1076    header.length = 1;
1077    for (i = 0; i < AuthenticationNames.length; i++)
1078	header.length += 2 + AuthenticationNames.data[i].length;
1079
1080    XdmcpWriteHeader (&buffer, &header);
1081    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
1082    if (broadcast)
1083    {
1084	int i;
1085
1086	for (i = 0; i < NumBroadcastAddresses; i++)
1087	    XdmcpFlush (xdmcpSocket, &buffer, (XdmcpNetaddr) &BroadcastAddresses[i],
1088			sizeof (struct sockaddr_in));
1089    }
1090#if defined(IPv6) && defined(AF_INET6)
1091    else if (multicast)
1092    {
1093	struct multicastinfo *mcl;
1094	struct addrinfo *ai;
1095
1096	for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) {
1097	    for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) {
1098		if (ai->ai_family == AF_INET) {
1099		    unsigned char hopflag = (unsigned char) mcl->hops;
1100		    socketfd = xdmcpSocket;
1101		    setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
1102		      &hopflag, sizeof(hopflag));
1103		} else if (ai->ai_family == AF_INET6) {
1104		    int hopflag6 = mcl->hops;
1105		    socketfd = xdmcpSocket6;
1106		    setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1107		      &hopflag6, sizeof(hopflag6));
1108		} else {
1109		    continue;
1110		}
1111		XdmcpFlush (socketfd, &buffer,
1112		  	    (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
1113		break;
1114	    }
1115	}
1116    }
1117#endif
1118    else
1119    {
1120#if defined(IPv6) && defined(AF_INET6)
1121	if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
1122	    socketfd = xdmcpSocket6;
1123#endif
1124	XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress,
1125		    ManagerAddressLen);
1126    }
1127}
1128
1129static void
1130recv_willing_msg(
1131    struct sockaddr	*from,
1132    int			fromlen,
1133    unsigned		length)
1134{
1135    ARRAY8	authenticationName;
1136    ARRAY8	hostname;
1137    ARRAY8	status;
1138
1139    authenticationName.data = 0;
1140    hostname.data = 0;
1141    status.data = 0;
1142    if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
1143	XdmcpReadARRAY8 (&buffer, &hostname) &&
1144	XdmcpReadARRAY8 (&buffer, &status))
1145    {
1146    	if (length == 6 + authenticationName.length +
1147		      hostname.length + status.length)
1148    	{
1149	    switch (state)
1150	    {
1151	    case XDM_COLLECT_QUERY:
1152	    	XdmcpSelectHost(from, fromlen, &authenticationName);
1153	    	break;
1154	    case XDM_COLLECT_BROADCAST_QUERY:
1155#if defined(IPv6) && defined(AF_INET6)
1156	    case XDM_COLLECT_MULTICAST_QUERY:
1157#endif
1158	    case XDM_COLLECT_INDIRECT_QUERY:
1159	    	XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
1160	    	break;
1161	    default:
1162		break;
1163    	    }
1164    	}
1165    }
1166    XdmcpDisposeARRAY8 (&authenticationName);
1167    XdmcpDisposeARRAY8 (&hostname);
1168    XdmcpDisposeARRAY8 (&status);
1169}
1170
1171static void
1172send_request_msg(void)
1173{
1174    XdmcpHeader	    header;
1175    int		    length;
1176    int		    i;
1177    CARD16	    XdmcpConnectionType;
1178    ARRAY8	    authenticationData;
1179    int		    socketfd = xdmcpSocket;
1180
1181    switch (SOCKADDR_FAMILY(ManagerAddress))
1182    {
1183    case AF_INET:	XdmcpConnectionType=FamilyInternet; break;
1184#if defined(IPv6) && defined(AF_INET6)
1185    case AF_INET6:	XdmcpConnectionType=FamilyInternet6; break;
1186#endif
1187    default:		XdmcpConnectionType=0xffff; break;
1188    }
1189
1190    header.version = XDM_PROTOCOL_VERSION;
1191    header.opcode = (CARD16) REQUEST;
1192
1193    length = 2;					    /* display number */
1194    length += 1 + 2 * ConnectionTypes.length;	    /* connection types */
1195    length += 1;				    /* connection addresses */
1196    for (i = 0; i < ConnectionAddresses.length; i++)
1197	length += 2 + ConnectionAddresses.data[i].length;
1198    authenticationData.length = 0;
1199    authenticationData.data = 0;
1200    if (AuthenticationFuncs)
1201    {
1202	(*AuthenticationFuncs->Generator) (AuthenticationData,
1203					   &authenticationData,
1204 					   REQUEST);
1205    }
1206    length += 2 + AuthenticationName->length;	    /* authentication name */
1207    length += 2 + authenticationData.length;	    /* authentication data */
1208    length += 1;				    /* authorization names */
1209    for (i = 0; i < AuthorizationNames.length; i++)
1210	length += 2 + AuthorizationNames.data[i].length;
1211    length += 2 + ManufacturerDisplayID.length;	    /* display ID */
1212    header.length = length;
1213
1214    if (!XdmcpWriteHeader (&buffer, &header))
1215    {
1216	XdmcpDisposeARRAY8 (&authenticationData);
1217	return;
1218    }
1219    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1220    XdmcpWriteCARD8 (&buffer, ConnectionTypes.length);
1221
1222    /* The connection array is send reordered, so that connections of	*/
1223    /* the same address type as the XDMCP manager connection are send	*/
1224    /* first. This works around a bug in xdm. mario@klebsch.de 		*/
1225    for (i = 0; i < (int)ConnectionTypes.length; i++)
1226	if (ConnectionTypes.data[i]==XdmcpConnectionType)
1227	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1228    for (i = 0; i < (int)ConnectionTypes.length; i++)
1229	if (ConnectionTypes.data[i]!=XdmcpConnectionType)
1230	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1231
1232    XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length);
1233    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1234	if ( (i<ConnectionTypes.length) &&
1235	     (ConnectionTypes.data[i]==XdmcpConnectionType) )
1236	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1237    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1238	if ( (i>=ConnectionTypes.length) ||
1239	     (ConnectionTypes.data[i]!=XdmcpConnectionType) )
1240	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1241
1242    XdmcpWriteARRAY8 (&buffer, AuthenticationName);
1243    XdmcpWriteARRAY8 (&buffer, &authenticationData);
1244    XdmcpDisposeARRAY8 (&authenticationData);
1245    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
1246    XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
1247#if defined(IPv6) && defined(AF_INET6)
1248    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1249	socketfd = xdmcpSocket6;
1250#endif
1251    if (XdmcpFlush (socketfd, &buffer,
1252			(XdmcpNetaddr) &req_sockaddr, req_socklen))
1253	state = XDM_AWAIT_REQUEST_RESPONSE;
1254}
1255
1256static void
1257recv_accept_msg(unsigned length)
1258{
1259    CARD32  AcceptSessionID;
1260    ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
1261    ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
1262
1263    if (state != XDM_AWAIT_REQUEST_RESPONSE)
1264	return;
1265    AcceptAuthenticationName.data = 0;
1266    AcceptAuthenticationData.data = 0;
1267    AcceptAuthorizationName.data = 0;
1268    AcceptAuthorizationData.data = 0;
1269    if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
1270	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
1271	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
1272	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
1273	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
1274    {
1275    	if (length == 12 + AcceptAuthenticationName.length +
1276		      	   AcceptAuthenticationData.length +
1277		      	   AcceptAuthorizationName.length +
1278 		      	   AcceptAuthorizationData.length)
1279    	{
1280	    if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
1281				      &AcceptAuthenticationData, ACCEPT))
1282	    {
1283		XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
1284	    }
1285	    /* permit access control manipulations from this host */
1286	    AugmentSelf (&req_sockaddr, req_socklen);
1287	    /* if the authorization specified in the packet fails
1288	     * to be acceptable, enable the local addresses
1289	     */
1290	    if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
1291					&AcceptAuthorizationData))
1292	    {
1293		AddLocalHosts ();
1294	    }
1295	    SessionID = AcceptSessionID;
1296    	    state = XDM_MANAGE;
1297    	    send_packet();
1298    	}
1299    }
1300    XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
1301    XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
1302    XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
1303    XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
1304}
1305
1306static void
1307recv_decline_msg(unsigned length)
1308{
1309    ARRAY8  status, DeclineAuthenticationName, DeclineAuthenticationData;
1310
1311    status.data = 0;
1312    DeclineAuthenticationName.data = 0;
1313    DeclineAuthenticationData.data = 0;
1314    if (XdmcpReadARRAY8 (&buffer, &status) &&
1315	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
1316	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
1317    {
1318    	if (length == 6 + status.length +
1319		      	  DeclineAuthenticationName.length +
1320 		      	  DeclineAuthenticationData.length &&
1321	    XdmcpCheckAuthentication (&DeclineAuthenticationName,
1322				      &DeclineAuthenticationData, DECLINE))
1323    	{
1324	    XdmcpFatal ("Session declined", &status);
1325    	}
1326    }
1327    XdmcpDisposeARRAY8 (&status);
1328    XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
1329    XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
1330}
1331
1332static void
1333send_manage_msg(void)
1334{
1335    XdmcpHeader	header;
1336    int socketfd = xdmcpSocket;
1337
1338    header.version = XDM_PROTOCOL_VERSION;
1339    header.opcode = (CARD16) MANAGE;
1340    header.length = 8 + DisplayClass.length;
1341
1342    if (!XdmcpWriteHeader (&buffer, &header))
1343	return;
1344    XdmcpWriteCARD32 (&buffer, SessionID);
1345    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1346    XdmcpWriteARRAY8 (&buffer, &DisplayClass);
1347    state = XDM_AWAIT_MANAGE_RESPONSE;
1348#if defined(IPv6) && defined(AF_INET6)
1349    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1350	socketfd = xdmcpSocket6;
1351#endif
1352    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1353}
1354
1355static void
1356recv_refuse_msg(unsigned length)
1357{
1358    CARD32  RefusedSessionID;
1359
1360    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1361	return;
1362    if (length != 4)
1363	return;
1364    if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
1365    {
1366	if (RefusedSessionID == SessionID)
1367	{
1368    	    state = XDM_START_CONNECTION;
1369    	    send_packet();
1370	}
1371    }
1372}
1373
1374static void
1375recv_failed_msg(unsigned length)
1376{
1377    CARD32  FailedSessionID;
1378    ARRAY8  status;
1379
1380    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1381	return;
1382    status.data = 0;
1383    if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
1384	XdmcpReadARRAY8 (&buffer, &status))
1385    {
1386    	if (length == 6 + status.length &&
1387	    SessionID == FailedSessionID)
1388	{
1389	    XdmcpFatal ("Session failed", &status);
1390	}
1391    }
1392    XdmcpDisposeARRAY8 (&status);
1393}
1394
1395static void
1396send_keepalive_msg(void)
1397{
1398    XdmcpHeader	header;
1399    int socketfd = xdmcpSocket;
1400
1401    header.version = XDM_PROTOCOL_VERSION;
1402    header.opcode = (CARD16) KEEPALIVE;
1403    header.length = 6;
1404
1405    XdmcpWriteHeader (&buffer, &header);
1406    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1407    XdmcpWriteCARD32 (&buffer, SessionID);
1408
1409    state = XDM_AWAIT_ALIVE_RESPONSE;
1410#if defined(IPv6) && defined(AF_INET6)
1411    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1412	socketfd = xdmcpSocket6;
1413#endif
1414    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1415}
1416
1417static void
1418recv_alive_msg (unsigned length)
1419{
1420    CARD8   SessionRunning;
1421    CARD32  AliveSessionID;
1422
1423    if (state != XDM_AWAIT_ALIVE_RESPONSE)
1424	return;
1425    if (length != 5)
1426	return;
1427    if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
1428	XdmcpReadCARD32 (&buffer, &AliveSessionID))
1429    {
1430    	if (SessionRunning && AliveSessionID == SessionID)
1431    	{
1432	    /* backoff dormancy period */
1433	    state = XDM_RUN_SESSION;
1434	    if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
1435		keepaliveDormancy * 1000)
1436	    {
1437		keepaliveDormancy <<= 1;
1438		if (keepaliveDormancy > XDM_MAX_DORMANCY)
1439		    keepaliveDormancy = XDM_MAX_DORMANCY;
1440	    }
1441	    timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
1442    	}
1443	else
1444    	{
1445	    XdmcpDeadSession ("Alive response indicates session dead");
1446    	}
1447    }
1448}
1449
1450static  void
1451XdmcpFatal (
1452    char	*type,
1453    ARRAY8Ptr	status)
1454{
1455    FatalError ("XDMCP fatal error: %s %*.*s\n", type,
1456	   status->length, status->length, status->data);
1457}
1458
1459static  void
1460XdmcpWarning(char *str)
1461{
1462    ErrorF("XDMCP warning: %s\n", str);
1463}
1464
1465static void
1466get_addr_by_name(
1467    char *	argtype,
1468    char *	namestr,
1469    int		port,
1470    int		socktype,
1471    SOCKADDR_TYPE *addr,
1472    SOCKLEN_TYPE *addrlen
1473#if defined(IPv6) && defined(AF_INET6)
1474      ,
1475    struct addrinfo **aip,
1476    struct addrinfo **aifirstp
1477#endif
1478    )
1479{
1480#if defined(IPv6) && defined(AF_INET6)
1481    struct addrinfo *ai;
1482    struct addrinfo hints;
1483    char portstr[6];
1484    char *pport = portstr;
1485    int gaierr;
1486
1487    bzero(&hints, sizeof(hints));
1488    hints.ai_socktype = socktype;
1489
1490    if (port == 0) {
1491	pport = NULL;
1492    } else if (port > 0 && port < 65535) {
1493	sprintf(portstr, "%d", port);
1494    } else {
1495	FatalError("Xserver: port out of range: %d\n", port);
1496    }
1497
1498    if (*aifirstp != NULL) {
1499	freeaddrinfo(*aifirstp);
1500	*aifirstp = NULL;
1501    }
1502
1503    if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) {
1504	for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) {
1505	    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
1506		break;
1507	}
1508	if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) {
1509	    FatalError ("Xserver: %s host %s not on supported network type\n",
1510	      argtype, namestr);
1511	} else {
1512	    *aip = ai;
1513	    *addrlen = ai->ai_addrlen;
1514	    memcpy(addr, ai->ai_addr, ai->ai_addrlen);
1515	}
1516    } else {
1517	FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr);
1518    }
1519#else
1520    struct hostent *hep;
1521#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1522    _Xgethostbynameparams hparams;
1523#endif
1524#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN))
1525    _XSERVTransWSAStartup();
1526#endif
1527    if (!(hep = _XGethostbyname(namestr, hparams)))
1528    {
1529	FatalError("Xserver: %s unknown host: %s\n", argtype, namestr);
1530    }
1531    if (hep->h_length == sizeof (struct in_addr))
1532    {
1533	memmove(&addr->sin_addr, hep->h_addr, hep->h_length);
1534	*addrlen = sizeof(struct sockaddr_in);
1535	addr->sin_family = AF_INET;
1536	addr->sin_port = htons (port);
1537    }
1538    else
1539    {
1540	FatalError("Xserver: %s host on strange network %s\n", argtype, namestr);
1541    }
1542#endif
1543}
1544
1545static void
1546get_manager_by_name(
1547    int	    argc,
1548    char    **argv,
1549    int	    i)
1550{
1551
1552    if ((i + 1) == argc)
1553    {
1554	FatalError("Xserver: missing %s host name in command line\n", argv[i]);
1555    }
1556
1557    get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM,
1558      &ManagerAddress, &ManagerAddressLen
1559#if defined(IPv6) && defined(AF_INET6)
1560      , &mgrAddr, &mgrAddrFirst
1561#endif
1562	);
1563}
1564
1565
1566static void
1567get_fromaddr_by_name(
1568    int	    argc,
1569    char    **argv,
1570    int	    i)
1571{
1572#if defined(IPv6) && defined(AF_INET6)
1573    struct addrinfo *ai = NULL;
1574    struct addrinfo *aifirst = NULL;
1575#endif
1576    if (i == argc)
1577    {
1578	FatalError("Xserver: missing -from host name in command line\n");
1579    }
1580    get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen
1581#if defined(IPv6) && defined(AF_INET6)
1582      , &ai, &aifirst
1583#endif
1584	);
1585#if defined(IPv6) && defined(AF_INET6)
1586    if (aifirst != NULL)
1587	freeaddrinfo(aifirst);
1588#endif
1589    xdm_from = argv[i];
1590}
1591
1592
1593#if defined(IPv6) && defined(AF_INET6)
1594static int
1595get_mcast_options(argc, argv, i)
1596    int	    argc, i;
1597    char    **argv;
1598{
1599    char *address = XDM_DEFAULT_MCAST_ADDR6;
1600    int hopcount = 1;
1601    struct addrinfo hints;
1602    char portstr[6];
1603    int gaierr;
1604    struct addrinfo *ai, *firstai;
1605
1606    if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1607	address = argv[i++];
1608	if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1609	    hopcount = strtol(argv[i++], NULL, 10);
1610	    if ((hopcount < 1) || (hopcount > 255)) {
1611		FatalError("Xserver: multicast hop count out of range: %d\n",
1612		  hopcount);
1613	    }
1614	}
1615    }
1616
1617    if (xdm_udp_port > 0 && xdm_udp_port < 65535) {
1618	sprintf(portstr, "%d", xdm_udp_port);
1619    } else {
1620	FatalError("Xserver: port out of range: %d\n", xdm_udp_port);
1621    }
1622    bzero(&hints, sizeof(hints));
1623    hints.ai_socktype = SOCK_DGRAM;
1624
1625    if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) {
1626	for (ai = firstai; ai != NULL; ai = ai->ai_next) {
1627	    if (((ai->ai_family == AF_INET) &&
1628	      	IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr)
1629							  ->sin_addr.s_addr))
1630		|| ((ai->ai_family == AF_INET6) &&
1631		  IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr)
1632							    ->sin6_addr)))
1633		break;
1634	}
1635	if (ai == NULL) {
1636	    FatalError ("Xserver: address not supported multicast type %s\n",
1637	      address);
1638	} else {
1639	    struct multicastinfo	*mcastinfo, *mcl;
1640
1641	    mcastinfo = malloc(sizeof(struct multicastinfo));
1642	    mcastinfo->next = NULL;
1643	    mcastinfo->ai = firstai;
1644	    mcastinfo->hops = hopcount;
1645
1646	    if (mcastlist == NULL) {
1647		mcastlist = mcastinfo;
1648	    } else {
1649		for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) {
1650		    /* Do nothing  - just find end of list */
1651		}
1652		mcl->next = mcastinfo;
1653	    }
1654	}
1655    } else {
1656	FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address);
1657    }
1658    return i;
1659}
1660#endif
1661
1662#else
1663static int xdmcp_non_empty; /* avoid complaint by ranlib */
1664#endif /* XDMCP */
1665