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