Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kdm / backend / choose.c
blob22cc5880920fdf1c512c37ba26b78ee9ef02a62f
1 /*
3 Copyright 1990, 1998 The Open Group
4 Copyright 2002-2004 Oswald Buddenhagen <ossi@kde.org>
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of a copyright holder shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from the copyright holder.
31 * xdm - display manager daemon
32 * Author: Keith Packard, MIT X Consortium
34 * chooser backend
37 #include "dm.h"
38 #include "dm_error.h"
39 #include "dm_socket.h"
41 #include <ctype.h>
43 #ifdef __svr4__
44 # include <sys/sockio.h>
45 #endif
46 #include <arpa/inet.h>
48 #include <sys/ioctl.h>
49 #ifdef STREAMSCONN
50 # ifdef WINTCP /* NCR with Wollongong TCP */
51 # include <netinet/ip.h>
52 # endif
53 # include <stropts.h>
54 # include <tiuser.h>
55 # include <netconfig.h>
56 # include <netdir.h>
57 #endif
59 #if !defined(__GNU__) && !defined(__hpux) /* XXX __hpux might be wrong */
60 # include <net/if.h>
61 #endif
63 #include <netdb.h>
65 typedef struct _Choices {
66 struct _Choices *next;
67 ARRAY8 client;
68 ARRAY8 port;
69 CARD16 connectionType;
70 ARRAY8 choice;
71 time_t timeout;
72 } ChoiceRec, *ChoicePtr;
74 static ChoicePtr choices;
76 time_t
77 disposeIndirectHosts()
79 ChoicePtr c;
81 while (choices) {
82 if (choices->timeout > now)
83 return choices->timeout;
84 debug( "timing out indirect host\n" );
85 c = choices;
86 choices = c->next;
87 XdmcpDisposeARRAY8( &c->client );
88 XdmcpDisposeARRAY8( &c->port );
89 XdmcpDisposeARRAY8( &c->choice );
90 free( (char *)c );
92 return TO_INF;
95 ARRAY8Ptr
96 indirectChoice( ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
97 CARD16 connectionType )
99 ChoicePtr c;
101 debug( "have indirect choice?\n" );
102 for (c = choices; c; c = c->next)
103 if (XdmcpARRAY8Equal( clientAddress, &c->client ) &&
104 XdmcpARRAY8Equal( clientPort, &c->port ) &&
105 connectionType == c->connectionType)
107 debug( c->choice.data ? " yes\n" : " not yet\n" );
108 return c->choice.data ? &c->choice : 0;
110 debug( " host not registered\n" );
111 return 0;
115 checkIndirectChoice( ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
116 CARD16 connectionType )
118 ChoicePtr c, *cp;
119 int uc;
121 debug( "checkIndirectChoice\n" );
122 for (cp = &choices; (c = *cp); cp = &c->next) {
123 if (XdmcpARRAY8Equal( clientAddress, &c->client ) &&
124 XdmcpARRAY8Equal( clientPort, &c->port ) &&
125 connectionType == c->connectionType)
127 *cp = c->next;
128 if (c->choice.data) {
129 XdmcpDisposeARRAY8( &c->choice );
130 debug( " choice already made\n" );
131 uc = False;
132 } else
133 uc = True;
134 XdmcpDisposeARRAY8( &c->port );
135 XdmcpDisposeARRAY8( &c->client );
136 free( c );
137 return uc;
140 debug( " host not registered\n" );
141 return False;
144 void
145 registerIndirectChoice( ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
146 CARD16 connectionType, ARRAY8Ptr choice )
148 ChoicePtr c, *cp;
150 debug( "registering indirect %s\n", choice ? "choice" : "client" );
151 for (cp = &choices; (c = *cp); cp = &c->next) {
152 if (XdmcpARRAY8Equal( clientAddress, &c->client ) &&
153 XdmcpARRAY8Equal( clientPort, &c->port ) &&
154 connectionType == c->connectionType)
156 *cp = c->next;
157 while (*cp)
158 cp = &(*cp)->next;
159 if (choice)
160 XdmcpDisposeARRAY8( &c->choice );
161 debug( " replacing existing\n" );
162 goto found;
166 if (!(c = (ChoicePtr)Malloc( sizeof(ChoiceRec) )))
167 return;
168 if (!XdmcpCopyARRAY8( clientAddress, &c->client )) {
169 free( c );
170 return;
172 if (!XdmcpCopyARRAY8( clientPort, &c->port )) {
173 XdmcpDisposeARRAY8( &c->client );
174 free( c );
175 return;
177 c->connectionType = connectionType;
178 c->choice.data = 0;
179 found:
180 if (choice && !XdmcpCopyARRAY8( choice, &c->choice )) {
181 XdmcpDisposeARRAY8( &c->port );
182 XdmcpDisposeARRAY8( &c->client );
183 free( (char *)c );
184 return;
186 c->timeout = now + choiceTimeout;
187 c->next = 0;
188 *cp = c;
192 /* ####################### */
195 typedef struct _HostAddr {
196 struct _HostAddr *next;
197 struct sockaddr *addr;
198 int addrlen;
199 xdmOpCode type;
200 } HostAddr;
202 static HostAddr *hostAddrdb;
204 typedef struct _HostName {
205 struct _HostName *next;
206 unsigned willing:1, alive:1;
207 ARRAY8 hostname, status;
208 CARD16 connectionType;
209 ARRAY8 hostaddr;
210 } HostName;
212 static HostName *hostNamedb;
214 static XdmcpBuffer directBuffer, broadcastBuffer;
215 static XdmcpBuffer buffer;
217 static int socketFD;
218 #if defined(IPv6) && defined(AF_INET6)
219 static int socket6FD;
220 #endif
223 static void
224 doPingHosts()
226 HostAddr *hosts;
228 for (hosts = hostAddrdb; hosts; hosts = hosts->next)
229 #if defined(IPv6) && defined(AF_INET6)
230 XdmcpFlush( hosts->addr->sa_family == AF_INET6 ? socket6FD : socketFD,
231 #else
232 XdmcpFlush( socketFD,
233 #endif
234 hosts->type == QUERY ? &directBuffer : &broadcastBuffer,
235 (XdmcpNetaddr)hosts->addr, hosts->addrlen );
238 static int
239 addHostname( ARRAY8Ptr hostname, ARRAY8Ptr status,
240 struct sockaddr *addr, int will )
242 HostName **names, *name;
243 ARRAY8 hostAddr;
244 CARD16 connectionType;
246 switch (addr->sa_family) {
247 case AF_INET:
248 hostAddr.data =
249 (CARD8 *)& ((struct sockaddr_in *)addr)->sin_addr;
250 hostAddr.length = 4;
251 connectionType = FamilyInternet;
252 break;
253 #if defined(IPv6) && defined(AF_INET6)
254 case AF_INET6:
255 hostAddr.data =
256 (CARD8 *)&((struct sockaddr_in6 *)addr)->sin6_addr;
257 hostAddr.length = 16;
258 connectionType = FamilyInternet6;
259 break;
260 #endif
261 default:
262 hostAddr.data = (CARD8 *)"";
263 hostAddr.length = 0;
264 connectionType = FamilyLocal;
265 break;
267 for (names = &hostNamedb; *names; names = &(*names)->next) {
268 name = *names;
269 if (connectionType == name->connectionType &&
270 XdmcpARRAY8Equal( &hostAddr, &name->hostaddr ))
272 if (XdmcpARRAY8Equal( status, &name->status ))
273 return False;
274 XdmcpDisposeARRAY8( &name->status );
275 XdmcpDisposeARRAY8( hostname );
277 gSendInt( G_Ch_ChangeHost );
278 goto gotold;
281 if (!(name = (HostName *)Malloc( sizeof(*name) )))
282 return False;
283 if (hostname->length) {
284 switch (addr->sa_family) {
285 case AF_INET:
286 #if defined(IPv6) && defined(AF_INET6)
287 case AF_INET6:
288 #endif
290 struct hostent *hostent;
291 char *host;
293 hostent = gethostbyaddr( (char *)hostAddr.data,
294 hostAddr.length, addr->sa_family );
295 if (hostent) {
296 XdmcpDisposeARRAY8( hostname );
297 host = hostent->h_name;
298 XdmcpAllocARRAY8( hostname, strlen( host ) );
299 memmove( hostname->data, host, hostname->length );
304 if (!XdmcpAllocARRAY8( &name->hostaddr, hostAddr.length )) {
305 free( (char *)name );
306 return False;
308 memmove( name->hostaddr.data, hostAddr.data, hostAddr.length );
309 name->connectionType = connectionType;
310 name->hostname = *hostname;
312 *names = name;
313 name->next = 0;
315 gSendInt( G_Ch_AddHost );
316 gotold:
317 name->alive = True;
318 name->willing = will;
319 name->status = *status;
321 gSendInt( (int)(long)name ); /* just an id */
322 gSendNStr( (char *)name->hostname.data, name->hostname.length );
323 gSendNStr( (char *)name->status.data, name->status.length );
324 gSendInt( will );
326 return True;
329 static void
330 disposeHostname( HostName *host )
332 XdmcpDisposeARRAY8( &host->hostname );
333 XdmcpDisposeARRAY8( &host->hostaddr );
334 XdmcpDisposeARRAY8( &host->status );
335 free( (char *)host );
338 static void
339 emptyHostnames( void )
341 HostName *host, *nhost;
343 for (host = hostNamedb; host; host = nhost) {
344 nhost = host->next;
345 disposeHostname( host );
347 hostNamedb = 0;
350 static void
351 receivePacket( int sfd )
353 XdmcpHeader header;
354 ARRAY8 authenticationName;
355 ARRAY8 hostname;
356 ARRAY8 status;
357 int saveHostname = False;
358 #if defined(IPv6) && defined(AF_INET6)
359 struct sockaddr_storage addr;
360 #else
361 struct sockaddr addr;
362 #endif
363 int addrlen;
365 addrlen = sizeof(addr);
366 if (!XdmcpFill( sfd, &buffer, (XdmcpNetaddr)&addr, &addrlen ))
367 return;
368 if (!XdmcpReadHeader( &buffer, &header ))
369 return;
370 if (header.version != XDM_PROTOCOL_VERSION)
371 return;
372 hostname.data = 0;
373 status.data = 0;
374 authenticationName.data = 0;
375 switch (header.opcode) {
376 case WILLING:
377 if (XdmcpReadARRAY8( &buffer, &authenticationName ) &&
378 XdmcpReadARRAY8( &buffer, &hostname ) &&
379 XdmcpReadARRAY8( &buffer, &status )) {
380 if (header.length == 6 + authenticationName.length +
381 hostname.length + status.length) {
382 if (addHostname( &hostname, &status,
383 (struct sockaddr *)&addr, True ))
384 saveHostname = True;
387 XdmcpDisposeARRAY8( &authenticationName );
388 break;
389 case UNWILLING:
390 if (XdmcpReadARRAY8( &buffer, &hostname ) &&
391 XdmcpReadARRAY8( &buffer, &status )) {
392 if (header.length == 4 + hostname.length + status.length) {
393 if (addHostname( &hostname, &status,
394 (struct sockaddr *)&addr, False ))
395 saveHostname = True;
398 break;
399 default:
400 break;
402 if (!saveHostname) {
403 XdmcpDisposeARRAY8( &hostname );
404 XdmcpDisposeARRAY8( &status );
408 static void
409 addHostaddr( HostAddr **hosts, struct sockaddr *addr, int len, xdmOpCode type )
411 HostAddr *host;
413 debug( "adding host %[*hhu, type %d\n", len, addr, type );
414 for (host = *hosts; host; host = host->next)
415 if (host->type == type && host->addr->sa_family == addr->sa_family)
416 switch (addr->sa_family) {
417 case AF_INET:
419 struct sockaddr_in *na = (struct sockaddr_in *)addr;
420 struct sockaddr_in *oa = (struct sockaddr_in *)host->addr;
421 if (na->sin_port == oa->sin_port &&
422 na->sin_addr.s_addr == oa->sin_addr.s_addr)
423 return;
424 break;
426 #if defined(IPv6) && defined(AF_INET6)
427 case AF_INET6:
429 struct sockaddr_in6 *na = (struct sockaddr_in6 *)addr;
430 struct sockaddr_in6 *oa = (struct sockaddr_in6 *)host->addr;
431 if (na->sin6_port == oa->sin6_port &&
432 !memcmp( &na->sin6_addr, &oa->sin6_addr, 16 ))
433 return;
434 break;
436 #endif
437 default: /* ... */
438 break;
440 debug( " not dupe\n" );
441 if (!(host = (HostAddr *)Malloc( sizeof(*host) )))
442 return;
443 if (!(host->addr = (struct sockaddr *)Malloc( len ))) {
444 free( (char *)host );
445 return;
447 memcpy( (char *)host->addr, (char *)addr, len );
448 host->addrlen = len;
449 host->type = type;
450 host->next = *hosts;
451 *hosts = host;
454 static void
455 registerHostaddr( struct sockaddr *addr, int len, xdmOpCode type )
457 addHostaddr( &hostAddrdb, addr, len, type );
460 static void
461 emptyPingHosts( void )
463 HostAddr *host, *nhost;
465 for (host = hostAddrdb; host; host = nhost) {
466 nhost = host->next;
467 free( host->addr );
468 free( host );
470 hostAddrdb = 0;
473 /* Handle variable length ifreq in BNR2 and later */
474 #ifdef VARIABLE_IFREQ
475 # define ifr_size(p) \
476 (sizeof(struct ifreq) + \
477 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
478 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
479 #else
480 # define ifr_size(p) (sizeof(struct ifreq))
481 #endif
483 #define IFC_REQ(ifc) ifc.ifc_req
485 #ifndef SYSV_SIOCGIFCONF
486 # define ifioctl ioctl
487 #endif
489 static void
490 registerBroadcastForPing( void )
492 struct sockaddr_in in_addr;
494 #ifdef __GNU__
495 in_addr.sin_addr.s_addr = htonl( 0xFFFFFFFF );
496 in_addr.sin_port = htons( XDM_UDP_PORT );
497 registerHostaddr( (struct sockaddr *)&in_addr, sizeof(in_addr),
498 BROADCAST_QUERY );
499 #else /* __GNU__ */
500 struct ifconf ifc;
501 register struct ifreq *ifr;
502 struct sockaddr broad_addr;
503 char buf[2048], *cp, *cplim;
504 # ifdef WINTCP /* NCR with Wollongong TCP */
505 int ipfd;
506 struct ifconf *ifcp;
507 struct strioctl ioc;
508 int n;
510 ifcp = (struct ifconf *)buf;
511 ifcp->ifc_buf = buf + 4;
512 ifcp->ifc_len = sizeof(buf) - 4;
514 if ((ipfd = open( "/dev/ip", O_RDONLY )) < 0) {
515 t_error( "RegisterBroadcastForPing() t_open(/dev/ip) failed" );
516 return;
519 ioc.ic_cmd = IPIOC_GETIFCONF;
520 ioc.ic_timout = 60;
521 ioc.ic_len = sizeof(buf);
522 ioc.ic_dp = (char *)ifcp;
524 if (ioctl( ipfd, (int)I_STR, (char *)&ioc ) < 0) {
525 perror( "RegisterBroadcastForPing() ioctl(I_STR(IPIOC_GETIFCONF)) failed" );
526 close( ipfd );
527 return;
530 for (ifr = ifcp->ifc_req, n = ifcp->ifc_len / sizeof(struct ifreq);
531 --n >= 0; ifr++)
532 # else /* WINTCP */
533 ifc.ifc_len = sizeof(buf);
534 ifc.ifc_buf = buf;
535 if (ifioctl(socketFD, (int)SIOCGIFCONF, (char *)&ifc) < 0)
536 return;
538 cplim = (char *)IFC_REQ( ifc ) + ifc.ifc_len;
540 for (cp = (char *)IFC_REQ( ifc ); cp < cplim; cp += ifr_size(ifr))
541 # endif /* WINTCP */
543 # ifndef WINTCP
544 ifr = (struct ifreq *)cp;
545 # endif
546 if (ifr->ifr_addr.sa_family != AF_INET)
547 continue;
549 broad_addr = ifr->ifr_addr;
550 ((struct sockaddr_in *)&broad_addr)->sin_addr.s_addr =
551 htonl( INADDR_BROADCAST );
552 # ifdef SIOCGIFBRDADDR
554 struct ifreq broad_req;
556 broad_req = *ifr;
557 # ifdef WINTCP /* NCR with Wollongong TCP */
558 ioc.ic_cmd = IPIOC_GETIFFLAGS;
559 ioc.ic_timout = 0;
560 ioc.ic_len = sizeof(broad_req);
561 ioc.ic_dp = (char *)&broad_req;
563 if (ioctl( ipfd, I_STR, (char *)&ioc )
564 # else /* WINTCP */
565 if (ifioctl( socketFD, SIOCGIFFLAGS, (char *)&broad_req )
566 # endif /* WINTCP */
567 != -1 &&
568 (broad_req.ifr_flags & IFF_BROADCAST) &&
569 (broad_req.ifr_flags & IFF_UP))
571 broad_req = *ifr;
572 # ifdef WINTCP /* NCR with Wollongong TCP */
573 ioc.ic_cmd = IPIOC_GETIFBRDADDR;
574 ioc.ic_timout = 0;
575 ioc.ic_len = sizeof(broad_req);
576 ioc.ic_dp = (char *)&broad_req;
578 if (ioctl( ipfd, I_STR, (char *)&ioc )
579 # else /* WINTCP */
580 if (ifioctl( socketFD, SIOCGIFBRDADDR, (char *)&broad_req )
581 # endif /* WINTCP */
582 != -1)
583 broad_addr = broad_req.ifr_addr;
584 else
585 continue;
586 } else
587 continue;
589 # endif
590 in_addr = *((struct sockaddr_in *)&broad_addr);
591 in_addr.sin_port = htons( XDM_UDP_PORT );
592 # ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
593 in_addr.sin_len = sizeof(in_addr);
594 # endif
595 registerHostaddr( (struct sockaddr *)&in_addr, sizeof(in_addr),
596 BROADCAST_QUERY );
598 #endif
601 static int
602 makeSockAddrs( const char *name, HostAddr **hosts )
604 #if defined(IPv6) && defined(AF_INET6)
605 struct addrinfo *ai, *nai, hints;
606 bzero( &hints, sizeof(hints) );
607 hints.ai_socktype = SOCK_DGRAM;
608 if (getaddrinfo( name, stringify( XDM_UDP_PORT ), &hints, &ai ))
609 return False;
610 for (nai = ai; nai; nai = nai->ai_next)
611 if ((nai->ai_family == AF_INET) || (nai->ai_family == AF_INET6))
612 addHostaddr( hosts, nai->ai_addr, nai->ai_addrlen,
613 (nai->ai_family == AF_INET ?
614 IN_MULTICAST( ((struct sockaddr_in *)nai->ai_addr)->sin_addr.s_addr ) :
615 IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr )) ?
616 BROADCAST_QUERY : QUERY );
617 #else
618 struct sockaddr_in in_addr;
619 /* Per RFC 1123, check first for IP address in dotted-decimal form */
620 if ((in_addr.sin_addr.s_addr = inet_addr( name )) == (unsigned)-1) {
621 struct hostent *hostent;
622 if (!(hostent = gethostbyname( name )) ||
623 hostent->h_addrtype != AF_INET)
624 return False;
625 memcpy( &in_addr.sin_addr, hostent->h_addr, 4 );
627 in_addr.sin_family = AF_INET;
628 in_addr.sin_port = htons( XDM_UDP_PORT );
629 # ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
630 in_addr.sin_len = sizeof(in_addr);
631 # endif
632 addHostaddr( hosts, (struct sockaddr *)&in_addr, sizeof(in_addr),
633 # ifdef IN_MULTICAST
634 IN_MULTICAST( in_addr.sin_addr.s_addr ) ?
635 BROADCAST_QUERY :
636 # endif
637 QUERY );
638 #endif
639 return True;
643 * Register the address for this host.
644 * Called for interactively specified hosts.
645 * The special names "BROADCAST" and "*" look up all the broadcast
646 * addresses on the local host.
649 static int
650 registerForPing( const char *name )
652 debug( "manual host registration: %s\n", name );
653 if (!strcmp( name, "BROADCAST" ) || !strcmp( name, "*" ))
654 registerBroadcastForPing();
655 else if (!makeSockAddrs( name, &hostAddrdb ))
656 return False;
657 return True;
660 /*ARGSUSED*/
661 static void
662 addChooserHost( CARD16 connectionType,
663 ARRAY8Ptr addr,
664 char *closure ATTR_UNUSED )
666 if (connectionType == FamilyBroadcast) {
667 registerBroadcastForPing();
668 return;
670 debug( "internal host registration: %[*hhu, family %hx\n",
671 addr->length, addr->data, connectionType );
672 if (connectionType == FamilyInternet) {
673 struct sockaddr_in in_addr;
674 in_addr.sin_family = AF_INET;
675 memmove( &in_addr.sin_addr, addr->data, 4 );
676 in_addr.sin_port = htons( XDM_UDP_PORT );
677 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
678 in_addr.sin_len = sizeof(in_addr);
679 #endif
680 registerHostaddr( (struct sockaddr *)&in_addr, sizeof(in_addr),
681 #ifdef IN_MULTICAST
682 IN_MULTICAST( in_addr.sin_addr.s_addr ) ?
683 BROADCAST_QUERY :
684 #endif
685 QUERY );
687 #if defined(IPv6) && defined(AF_INET6)
688 else if (connectionType == FamilyInternet6) {
689 struct sockaddr_in6 in6_addr;
690 in6_addr.sin6_family = AF_INET6;
691 memmove( &in6_addr.sin6_addr, addr->data, 16 );
692 in6_addr.sin6_port = htons( XDM_UDP_PORT );
693 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
694 in6_addr.sin6_len = sizeof(in6_addr);
695 #endif
696 registerHostaddr( (struct sockaddr *)&in6_addr, sizeof(in6_addr),
697 IN6_IS_ADDR_MULTICAST( &in6_addr.sin6_addr ) ?
698 BROADCAST_QUERY : QUERY );
700 #endif
703 static ARRAYofARRAY8 AuthenticationNames;
705 #if 0
706 static void
707 registerAuthenticationName( char *name, int namelen )
709 ARRAY8Ptr authName;
710 if (!XdmcpReallocARRAYofARRAY8( &AuthenticationNames,
711 AuthenticationNames.length + 1 ))
712 return;
713 authName = &AuthenticationNames.data[AuthenticationNames.length - 1];
714 if (!XdmcpAllocARRAY8( authName, namelen ))
715 return;
716 memmove( authName->data, name, namelen );
718 #endif
720 static int
721 initXDMCP()
723 XdmcpHeader header;
724 #if 0
725 int i;
726 #endif
727 #ifndef STREAMSCONN
728 #ifdef SO_BROADCAST
729 int soopts;
730 #endif
731 #endif
733 header.version = XDM_PROTOCOL_VERSION;
734 header.length = 1;
735 #if 0
736 for (i = 0; i < (int)AuthenticationNames.length; i++)
737 header.length += 2 + AuthenticationNames.data[i].length;
738 #endif
740 header.opcode = (CARD16)BROADCAST_QUERY;
741 XdmcpWriteHeader( &broadcastBuffer, &header );
742 XdmcpWriteARRAYofARRAY8( &broadcastBuffer, &AuthenticationNames );
744 header.opcode = (CARD16)QUERY;
745 XdmcpWriteHeader( &directBuffer, &header );
746 XdmcpWriteARRAYofARRAY8( &directBuffer, &AuthenticationNames );
748 #if defined(STREAMSCONN)
749 if ((socketFD = t_open( "/dev/udp", O_RDWR, 0 )) < 0)
750 return 0;
752 if (t_bind( socketFD, NULL, NULL ) < 0) {
753 t_close( socketFD );
754 return False;
758 * This part of the code looks contrived. It will actually fit in nicely
759 * when the CLTS part of Xtrans is implemented.
762 struct netconfig *nconf;
764 if ((nconf = getnetconfigent( "udp" )) == NULL) {
765 t_unbind( socketFD );
766 t_close( socketFD );
767 return False;
770 if (netdir_options( nconf, ND_SET_BROADCAST, socketFD, NULL )) {
771 freenetconfigent( nconf );
772 t_unbind( socketFD );
773 t_close( socketFD );
774 return False;
777 freenetconfigent( nconf );
779 #else
780 if ((socketFD = socket( AF_INET, SOCK_DGRAM, 0 )) < 0)
781 return False;
782 #if defined(IPv6) && defined(AF_INET6)
783 socket6FD = socket( AF_INET6, SOCK_DGRAM, 0 );
784 #endif
785 # ifdef SO_BROADCAST
786 soopts = 1;
787 if (setsockopt( socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
788 sizeof(soopts) ) < 0)
789 perror( "setsockopt" );
790 # endif
791 #endif
793 return True;
796 static void ATTR_NORETURN
797 chooseHost( int hid )
799 HostName *h;
800 #if defined(IPv6) && defined(AF_INET6)
801 char addr[64];
802 #endif
804 for (h = hostNamedb; h; h = h->next)
805 if ((int)(long)h == hid) {
806 /* XXX error handling */
807 gSet( &mstrtalk );
808 if ((td->displayType & d_location) == dLocal) {
809 gSendInt( D_RemoteHost );
810 #if defined(IPv6) && defined(AF_INET6)
811 switch (h->connectionType) {
812 case FamilyInternet6:
813 inet_ntop( AF_INET6, h->hostaddr.data, addr, sizeof(addr) );
814 break;
815 default: /* FamilyInternet */
816 inet_ntop( AF_INET, h->hostaddr.data, addr, sizeof(addr) );
817 break;
819 gSendStr( addr );
820 #else
821 gSendStr( inet_ntoa( *(struct in_addr *)h->hostaddr.data ) );
822 #endif
823 sessionExit( EX_REMOTE );
824 } else {
825 gSendInt( D_ChooseHost );
826 gSendArr( td->clientAddr.length, (char *)td->clientAddr.data );
827 gSendArr( td->clientPort.length, (char *)td->clientPort.data );
828 gSendInt( td->connectionType );
829 gSendArr( h->hostaddr.length, (char *)h->hostaddr.data );
830 goto bout;
832 break;
834 /* logError( "Internal error: chose unexisting host\n" ); */
835 bout:
836 sessionExit( EX_NORMAL );
839 static void
840 directChooseHost( const char *name )
842 HostAddr *hosts = 0;
844 if (!makeSockAddrs( name, &hosts ))
845 return;
846 gSendInt( G_Ch_Exit );
847 /* XXX error handling */
848 gSet( &mstrtalk );
849 if ((td->displayType & d_location) == dLocal) {
850 gSendInt( D_RemoteHost );
851 gSendStr( name );
852 sessionExit( EX_REMOTE );
853 } else {
854 gSendInt( D_ChooseHost );
855 gSendArr( td->clientAddr.length, (char *)td->clientAddr.data );
856 gSendArr( td->clientPort.length, (char *)td->clientPort.data );
857 gSendInt( td->connectionType );
858 gSendArr( hosts->addrlen, (char *)hosts->addr );
859 sessionExit( EX_NORMAL );
863 #define PING_TRIES 3
866 doChoose()
868 HostName **hp, *h;
869 char *host, **hostp;
870 struct timeval *to, tnow, nextPing;
871 int pingTry, n, cmd;
872 fd_set rfds;
873 static int xdmcpInited;
875 openGreeter();
876 gSendInt( G_Choose );
877 switch (cmd = ctrlGreeterWait( True )) {
878 case G_Ready:
879 break;
880 default: /* error */
881 return cmd;
884 if (!xdmcpInited) {
885 if (!initXDMCP())
886 sessionExit( EX_UNMANAGE_DPY );
887 xdmcpInited = True;
889 if ((td->displayType & d_location) == dLocal) {
890 /* XXX the config reader should do the lookup already */
891 for (hostp = td->chooserHosts; *hostp; hostp++)
892 if (!registerForPing( *hostp ))
893 logError( "Unknown host %\"s specified for local chooser preload of display %s\n", *hostp, td->name );
894 } else
895 forEachChooserHost( &td->clientAddr, td->connectionType,
896 addChooserHost, 0 );
898 gSendInt( 0 ); /* entering async mode signal */
900 reping:
901 for (h = hostNamedb; h; h = h->next)
902 h->alive = False;
903 pingTry = 0;
904 goto pingen;
906 for (;;) {
907 to = 0;
908 if (pingTry <= PING_TRIES) {
909 gettimeofday( &tnow, 0 );
910 if (nextPing.tv_sec < tnow.tv_sec ||
911 (nextPing.tv_sec == tnow.tv_sec &&
912 nextPing.tv_usec < tnow.tv_usec)) {
913 if (pingTry < PING_TRIES) {
914 pingen:
915 pingTry++;
916 doPingHosts();
917 gettimeofday( &tnow, 0 );
918 nextPing = tnow;
919 nextPing.tv_sec++;
920 } else {
921 for (hp = &hostNamedb; *hp; )
922 if (!(*hp)->alive) {
923 h = (*hp)->next;
924 disposeHostname( *hp );
925 gSendInt( G_Ch_RemoveHost );
926 gSendInt( (int)(long)*hp ); /* just an id */
927 *hp = h;
928 } else
929 hp = &(*hp)->next;
930 goto noto;
933 to = &tnow;
934 tnow.tv_sec = nextPing.tv_sec - tnow.tv_sec;
935 tnow.tv_usec = nextPing.tv_usec - tnow.tv_usec;
936 if (tnow.tv_usec < 0) {
937 tnow.tv_usec += 1000000;
938 tnow.tv_sec--;
941 noto:
942 FD_ZERO( &rfds );
943 FD_SET( grtproc.pipe.fd.r, &rfds );
944 FD_SET( socketFD, &rfds );
945 #if defined(IPv6) && defined(AF_INET6)
946 if (socket6FD >= 0)
947 FD_SET( socket6FD, &rfds );
948 #endif
949 n = grtproc.pipe.fd.r;
950 if (socketFD > n)
951 n = socketFD;
952 #if defined(IPv6) && defined(AF_INET6)
953 if (socket6FD > n)
954 n = socket6FD;
955 #endif
956 if (select( n + 1, &rfds, 0, 0, to ) > 0) {
957 if (FD_ISSET( grtproc.pipe.fd.r, &rfds ))
958 switch (cmd = ctrlGreeterWait( False )) {
959 case -1:
960 break;
961 case G_Ch_Refresh:
962 goto reping;
963 case G_Ch_RegisterHost:
964 host = gRecvStr();
965 if (!registerForPing( host )) {
966 gSendInt( G_Ch_BadHost );
967 gSendStr( host );
969 free( host );
970 goto reping;
971 case G_Ch_DirectChoice:
972 host = gRecvStr();
973 directChooseHost( host );
974 gSendInt( G_Ch_BadHost );
975 gSendStr( host );
976 free( host );
977 break;
978 case G_Ready:
979 chooseHost( gRecvInt() );
980 /* NOTREACHED */
981 default:
982 emptyHostnames();
983 emptyPingHosts();
984 return cmd;
986 if (FD_ISSET( socketFD, &rfds ))
987 receivePacket( socketFD );
988 #if defined(IPv6) && defined(AF_INET6)
989 if (socket6FD >= 0 && FD_ISSET( socket6FD, &rfds ))
990 receivePacket( socket6FD );
991 #endif