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
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
39
#include "dm_socket.h"
42
#include <sys/ioctl.h>
43
#ifdef HAVE_SYS_SOCKIO_H
44
# include <sys/sockio.h>
49
#include <arpa/inet.h>
53
# ifdef WINTCP /* NCR with Wollongong TCP */
54
# include <netinet/ip.h>
58
# include <netconfig.h>
62
typedef struct _Choices {
63
struct _Choices *next;
66
CARD16 connectionType;
69
} ChoiceRec, *ChoicePtr;
71
static ChoicePtr choices;
74
disposeIndirectHosts()
79
if (choices->timeout > now)
80
return choices->timeout;
81
debug("timing out indirect host\n");
84
XdmcpDisposeARRAY8(&c->client);
85
XdmcpDisposeARRAY8(&c->port);
86
XdmcpDisposeARRAY8(&c->choice);
93
indirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
94
CARD16 connectionType)
98
debug("have indirect choice?\n");
99
for (c = choices; c; c = c->next)
100
if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
101
XdmcpARRAY8Equal(clientPort, &c->port) &&
102
connectionType == c->connectionType)
104
debug(c->choice.data ? " yes\n" : " not yet\n");
105
return c->choice.data ? &c->choice : 0;
107
debug(" host not registered\n");
112
checkIndirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
113
CARD16 connectionType)
118
debug("checkIndirectChoice\n");
119
for (cp = &choices; (c = *cp); cp = &c->next) {
120
if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
121
XdmcpARRAY8Equal(clientPort, &c->port) &&
122
connectionType == c->connectionType)
125
if (c->choice.data) {
126
XdmcpDisposeARRAY8(&c->choice);
127
debug(" choice already made\n");
132
XdmcpDisposeARRAY8(&c->port);
133
XdmcpDisposeARRAY8(&c->client);
138
debug(" host not registered\n");
143
registerIndirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
144
CARD16 connectionType, ARRAY8Ptr choice)
148
debug("registering indirect %s\n", choice ? "choice" : "client");
149
for (cp = &choices; (c = *cp); cp = &c->next) {
150
if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
151
XdmcpARRAY8Equal(clientPort, &c->port) &&
152
connectionType == c->connectionType)
158
XdmcpDisposeARRAY8(&c->choice);
159
debug(" replacing existing\n");
164
if (!(c = Malloc(sizeof(ChoiceRec))))
166
if (!XdmcpCopyARRAY8(clientAddress, &c->client)) {
170
if (!XdmcpCopyARRAY8(clientPort, &c->port)) {
171
XdmcpDisposeARRAY8(&c->client);
175
c->connectionType = connectionType;
178
if (choice && !XdmcpCopyARRAY8(choice, &c->choice)) {
179
XdmcpDisposeARRAY8(&c->port);
180
XdmcpDisposeARRAY8(&c->client);
184
c->timeout = now + choiceTimeout;
190
/* ####################### */
193
typedef struct _HostAddr {
194
struct _HostAddr *next;
195
struct sockaddr *addr;
200
static HostAddr *hostAddrdb;
202
typedef struct _HostName {
203
struct _HostName *next;
204
unsigned willing:1, alive:1;
205
ARRAY8 hostname, status;
206
CARD16 connectionType;
210
static HostName *hostNamedb;
212
static XdmcpBuffer directBuffer, broadcastBuffer;
213
static XdmcpBuffer buffer;
216
#if defined(IPv6) && defined(AF_INET6)
217
static int socket6FD;
226
for (hosts = hostAddrdb; hosts; hosts = hosts->next)
227
#if defined(IPv6) && defined(AF_INET6)
228
XdmcpFlush(hosts->addr->sa_family == AF_INET6 ? socket6FD : socketFD,
232
hosts->type == QUERY ? &directBuffer : &broadcastBuffer,
233
(XdmcpNetaddr)hosts->addr, hosts->addrlen);
237
addHostname(ARRAY8Ptr hostname, ARRAY8Ptr status,
238
struct sockaddr *addr, int will)
240
HostName **names, *name;
242
CARD16 connectionType;
244
switch (addr->sa_family) {
246
hostAddr.data = (CARD8 *)&((struct sockaddr_in *)addr)->sin_addr;
248
connectionType = FamilyInternet;
250
#if defined(IPv6) && defined(AF_INET6)
252
hostAddr.data = (CARD8 *)&((struct sockaddr_in6 *)addr)->sin6_addr;
253
hostAddr.length = 16;
254
connectionType = FamilyInternet6;
258
hostAddr.data = (CARD8 *)"";
260
connectionType = FamilyLocal;
263
for (names = &hostNamedb; *names; names = &(*names)->next) {
265
if (connectionType == name->connectionType &&
266
XdmcpARRAY8Equal(&hostAddr, &name->hostaddr))
268
if (XdmcpARRAY8Equal(status, &name->status))
270
XdmcpDisposeARRAY8(&name->status);
271
XdmcpDisposeARRAY8(hostname);
273
gSendInt(G_Ch_ChangeHost);
277
if (!(name = Malloc(sizeof(*name))))
279
if (hostname->length) {
280
switch (addr->sa_family) {
282
#if defined(IPv6) && defined(AF_INET6)
286
struct hostent *hostent;
289
hostent = gethostbyaddr((char *)hostAddr.data,
290
hostAddr.length, addr->sa_family);
292
XdmcpDisposeARRAY8(hostname);
293
host = hostent->h_name;
294
XdmcpAllocARRAY8(hostname, strlen(host));
295
memmove(hostname->data, host, hostname->length);
300
if (!XdmcpAllocARRAY8(&name->hostaddr, hostAddr.length)) {
304
memmove(name->hostaddr.data, hostAddr.data, hostAddr.length);
305
name->connectionType = connectionType;
306
name->hostname = *hostname;
311
gSendInt(G_Ch_AddHost);
314
name->willing = will;
315
name->status = *status;
317
gSendInt((int)(long)name); /* just an id */
318
gSendNStr((char *)name->hostname.data, name->hostname.length);
319
gSendNStr((char *)name->status.data, name->status.length);
326
disposeHostname(HostName *host)
328
XdmcpDisposeARRAY8(&host->hostname);
329
XdmcpDisposeARRAY8(&host->hostaddr);
330
XdmcpDisposeARRAY8(&host->status);
337
HostName *host, *nhost;
339
for (host = hostNamedb; host; host = nhost) {
341
disposeHostname(host);
347
receivePacket(int sfd)
350
ARRAY8 authenticationName;
353
int saveHostname = False;
354
#if defined(IPv6) && defined(AF_INET6)
355
struct sockaddr_storage addr;
357
struct sockaddr addr;
361
addrlen = sizeof(addr);
362
if (!XdmcpFill(sfd, &buffer, (XdmcpNetaddr)&addr, &addrlen))
364
if (!XdmcpReadHeader(&buffer, &header))
366
if (header.version != XDM_PROTOCOL_VERSION)
370
authenticationName.data = 0;
371
switch (header.opcode) {
373
if (XdmcpReadARRAY8(&buffer, &authenticationName) &&
374
XdmcpReadARRAY8(&buffer, &hostname) &&
375
XdmcpReadARRAY8(&buffer, &status))
377
if (header.length == 6 + authenticationName.length +
378
hostname.length + status.length)
379
if (addHostname(&hostname, &status,
380
(struct sockaddr *)&addr, True))
383
XdmcpDisposeARRAY8(&authenticationName);
386
if (XdmcpReadARRAY8(&buffer, &hostname) &&
387
XdmcpReadARRAY8(&buffer, &status))
389
if (header.length == 4 + hostname.length + status.length)
390
if (addHostname(&hostname, &status,
391
(struct sockaddr *)&addr, False))
399
XdmcpDisposeARRAY8(&hostname);
400
XdmcpDisposeARRAY8(&status);
405
addHostaddr(HostAddr **hosts, struct sockaddr *addr, int len, xdmOpCode type)
409
debug("adding host %[*hhu, type %d\n", len, addr, type);
410
for (host = *hosts; host; host = host->next)
411
if (host->type == type && host->addr->sa_family == addr->sa_family)
412
switch (addr->sa_family) {
414
struct sockaddr_in *na = (struct sockaddr_in *)addr;
415
struct sockaddr_in *oa = (struct sockaddr_in *)host->addr;
416
if (na->sin_port == oa->sin_port &&
417
na->sin_addr.s_addr == oa->sin_addr.s_addr)
420
#if defined(IPv6) && defined(AF_INET6)
422
struct sockaddr_in6 *na = (struct sockaddr_in6 *)addr;
423
struct sockaddr_in6 *oa = (struct sockaddr_in6 *)host->addr;
424
if (na->sin6_port == oa->sin6_port &&
425
!memcmp(&na->sin6_addr, &oa->sin6_addr, 16))
432
debug(" not dupe\n");
433
if (!(host = Malloc(sizeof(*host))))
435
if (!(host->addr = Malloc(len))) {
439
memcpy(host->addr, addr, len);
447
registerHostaddr(struct sockaddr *addr, int len, xdmOpCode type)
449
addHostaddr(&hostAddrdb, addr, len, type);
455
HostAddr *host, *nhost;
457
for (host = hostAddrdb; host; host = nhost) {
465
/* Handle variable length ifreq in BNR2 and later */
466
#ifdef VARIABLE_IFREQ
467
# define ifr_size(p) \
468
(sizeof(struct ifreq) + \
469
(p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
470
p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
472
# define ifr_size(p) (sizeof(struct ifreq))
475
#define IFC_REQ(ifc) ifc.ifc_req
477
#ifndef SYSV_SIOCGIFCONF
478
# define ifioctl ioctl
482
registerBroadcastForPing(void)
484
struct sockaddr_in in_addr;
487
in_addr.sin_addr.s_addr = htonl(0xFFFFFFFF);
488
in_addr.sin_port = htons(XDM_UDP_PORT);
489
registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
493
register struct ifreq *ifr;
494
struct sockaddr broad_addr;
495
char buf[2048], *cp, *cplim;
496
# ifdef WINTCP /* NCR with Wollongong TCP */
502
ifcp = (struct ifconf *)buf;
503
ifcp->ifc_buf = buf + 4;
504
ifcp->ifc_len = sizeof(buf) - 4;
506
if ((ipfd = open("/dev/ip", O_RDONLY)) < 0) {
507
t_error("RegisterBroadcastForPing() t_open(/dev/ip) failed");
511
ioc.ic_cmd = IPIOC_GETIFCONF;
513
ioc.ic_len = sizeof(buf);
514
ioc.ic_dp = (char *)ifcp;
516
if (ioctl(ipfd, (int)I_STR, (char *)&ioc) < 0) {
517
perror("RegisterBroadcastForPing() ioctl(I_STR(IPIOC_GETIFCONF)) failed");
522
for (ifr = ifcp->ifc_req, n = ifcp->ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
524
ifc.ifc_len = sizeof(buf);
526
if (ifioctl(socketFD, (int)SIOCGIFCONF, (char *)&ifc) < 0)
529
cplim = (char *)IFC_REQ(ifc) + ifc.ifc_len;
531
for (cp = (char *)IFC_REQ(ifc); cp < cplim; cp += ifr_size(ifr))
535
ifr = (struct ifreq *)cp;
537
if (ifr->ifr_addr.sa_family != AF_INET)
540
broad_addr = ifr->ifr_addr;
541
((struct sockaddr_in *)&broad_addr)->sin_addr.s_addr =
542
htonl(INADDR_BROADCAST);
543
# ifdef SIOCGIFBRDADDR
545
struct ifreq broad_req;
548
# ifdef WINTCP /* NCR with Wollongong TCP */
549
ioc.ic_cmd = IPIOC_GETIFFLAGS;
551
ioc.ic_len = sizeof(broad_req);
552
ioc.ic_dp = (char *)&broad_req;
554
if (ioctl(ipfd, I_STR, (char *)&ioc) != -1 &&
556
if (ifioctl(socketFD, SIOCGIFFLAGS, (char *)&broad_req) != -1 &&
558
(broad_req.ifr_flags & IFF_BROADCAST) &&
559
(broad_req.ifr_flags & IFF_UP))
562
# ifdef WINTCP /* NCR with Wollongong TCP */
563
ioc.ic_cmd = IPIOC_GETIFBRDADDR;
565
ioc.ic_len = sizeof(broad_req);
566
ioc.ic_dp = (char *)&broad_req;
568
if (ioctl(ipfd, I_STR, (char *)&ioc) != -1)
570
if (ifioctl(socketFD, SIOCGIFBRDADDR, (char *)&broad_req) != -1)
572
broad_addr = broad_req.ifr_addr;
579
in_addr = *((struct sockaddr_in *)&broad_addr);
580
in_addr.sin_port = htons(XDM_UDP_PORT);
581
# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
582
in_addr.sin_len = sizeof(in_addr);
584
registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
591
makeSockAddrs(const char *name, HostAddr **hosts)
593
#if defined(IPv6) && defined(AF_INET6)
594
struct addrinfo *ai, *nai, hints;
595
bzero(&hints, sizeof(hints));
596
hints.ai_socktype = SOCK_DGRAM;
597
if (getaddrinfo(name, stringify(XDM_UDP_PORT), &hints, &ai))
599
for (nai = ai; nai; nai = nai->ai_next)
600
if ((nai->ai_family == AF_INET) || (nai->ai_family == AF_INET6))
601
addHostaddr(hosts, nai->ai_addr, nai->ai_addrlen,
602
(nai->ai_family == AF_INET ?
603
IN_MULTICAST(((struct sockaddr_in *)nai->ai_addr)->sin_addr.s_addr) :
604
IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr)) ?
605
BROADCAST_QUERY : QUERY);
607
struct sockaddr_in in_addr;
608
/* Per RFC 1123, check first for IP address in dotted-decimal form */
609
if ((in_addr.sin_addr.s_addr = inet_addr(name)) == (unsigned)-1) {
610
struct hostent *hostent;
611
if (!(hostent = gethostbyname(name)) ||
612
hostent->h_addrtype != AF_INET)
614
memcpy(&in_addr.sin_addr, hostent->h_addr, 4);
616
in_addr.sin_family = AF_INET;
617
in_addr.sin_port = htons(XDM_UDP_PORT);
618
# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
619
in_addr.sin_len = sizeof(in_addr);
621
addHostaddr(hosts, (struct sockaddr *)&in_addr, sizeof(in_addr),
623
IN_MULTICAST(in_addr.sin_addr.s_addr) ?
632
* Register the address for this host.
633
* Called for interactively specified hosts.
634
* The special names "BROADCAST" and "*" look up all the broadcast
635
* addresses on the local host.
639
registerForPing(const char *name)
641
debug("manual host registration: %s\n", name);
642
if (!strcmp(name, "BROADCAST") || !strcmp(name, "*"))
643
registerBroadcastForPing();
644
else if (!makeSockAddrs(name, &hostAddrdb))
651
addChooserHost(CARD16 connectionType,
653
char *closure ATTR_UNUSED)
655
if (connectionType == FamilyBroadcast) {
656
registerBroadcastForPing();
659
debug("internal host registration: %[*hhu, family %hx\n",
660
addr->length, addr->data, connectionType);
661
if (connectionType == FamilyInternet) {
662
struct sockaddr_in in_addr;
663
in_addr.sin_family = AF_INET;
664
memmove(&in_addr.sin_addr, addr->data, 4);
665
in_addr.sin_port = htons(XDM_UDP_PORT);
666
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
667
in_addr.sin_len = sizeof(in_addr);
669
registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
671
IN_MULTICAST(in_addr.sin_addr.s_addr) ?
675
#if defined(IPv6) && defined(AF_INET6)
676
} else if (connectionType == FamilyInternet6) {
677
struct sockaddr_in6 in6_addr;
678
in6_addr.sin6_family = AF_INET6;
679
memmove(&in6_addr.sin6_addr, addr->data, 16);
680
in6_addr.sin6_port = htons(XDM_UDP_PORT);
681
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
682
in6_addr.sin6_len = sizeof(in6_addr);
684
registerHostaddr((struct sockaddr *)&in6_addr, sizeof(in6_addr),
685
IN6_IS_ADDR_MULTICAST(&in6_addr.sin6_addr) ?
686
BROADCAST_QUERY : QUERY);
691
static ARRAYofARRAY8 AuthenticationNames;
695
registerAuthenticationName(char *name, int namelen)
698
if (!XdmcpReallocARRAYofARRAY8(&AuthenticationNames,
699
AuthenticationNames.length + 1))
701
authName = &AuthenticationNames.data[AuthenticationNames.length - 1];
702
if (!XdmcpAllocARRAY8(authName, namelen))
704
memmove(authName->data, name, namelen);
721
header.version = XDM_PROTOCOL_VERSION;
724
for (i = 0; i < (int)AuthenticationNames.length; i++)
725
header.length += 2 + AuthenticationNames.data[i].length;
728
header.opcode = (CARD16)BROADCAST_QUERY;
729
XdmcpWriteHeader(&broadcastBuffer, &header);
730
XdmcpWriteARRAYofARRAY8(&broadcastBuffer, &AuthenticationNames);
732
header.opcode = (CARD16)QUERY;
733
XdmcpWriteHeader(&directBuffer, &header);
734
XdmcpWriteARRAYofARRAY8(&directBuffer, &AuthenticationNames);
736
#if defined(STREAMSCONN)
737
if ((socketFD = t_open("/dev/udp", O_RDWR, 0)) < 0)
740
if (t_bind(socketFD, 0, 0) < 0) {
746
* This part of the code looks contrived. It will actually fit in nicely
747
* when the CLTS part of Xtrans is implemented.
750
struct netconfig *nconf;
752
if (!(nconf = getnetconfigent("udp"))) {
758
if (netdir_options(nconf, ND_SET_BROADCAST, socketFD, 0)) {
759
freenetconfigent(nconf);
765
freenetconfigent(nconf);
768
if ((socketFD = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
770
#if defined(IPv6) && defined(AF_INET6)
771
socket6FD = socket(AF_INET6, SOCK_DGRAM, 0);
775
if (setsockopt(socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
777
perror("setsockopt");
784
static void ATTR_NORETURN
788
#if defined(IPv6) && defined(AF_INET6)
792
for (h = hostNamedb; h; h = h->next)
793
if ((int)(long)h == hid) {
795
if ((td->displayType & d_location) == dLocal) {
796
gSendInt(D_RemoteHost);
797
#if defined(IPv6) && defined(AF_INET6)
798
switch (h->connectionType) {
799
case FamilyInternet6:
800
inet_ntop(AF_INET6, h->hostaddr.data, addr, sizeof(addr));
802
default: /* FamilyInternet */
803
inet_ntop(AF_INET, h->hostaddr.data, addr, sizeof(addr));
808
gSendStr(inet_ntoa(*(struct in_addr *)h->hostaddr.data));
810
sessionExit(EX_REMOTE);
812
gSendInt(D_ChooseHost);
813
gSendArr(td->clientAddr.length, (char *)td->clientAddr.data);
814
gSendArr(td->clientPort.length, (char *)td->clientPort.data);
815
gSendInt(td->connectionType);
816
gSendArr(h->hostaddr.length, (char *)h->hostaddr.data);
821
/* logError("Internal error: chose unexisting host\n"); */
823
sessionExit(EX_NORMAL);
827
directChooseHost(const char *name)
831
if (!makeSockAddrs(name, &hosts))
835
if ((td->displayType & d_location) == dLocal) {
836
gSendInt(D_RemoteHost);
838
sessionExit(EX_REMOTE);
840
gSendInt(D_ChooseHost);
841
gSendArr(td->clientAddr.length, (char *)td->clientAddr.data);
842
gSendArr(td->clientPort.length, (char *)td->clientPort.data);
843
gSendInt(td->connectionType);
844
gSendArr(hosts->addrlen, (char *)hosts->addr);
845
sessionExit(EX_NORMAL);
856
struct timeval *to, tnow, nextPing;
859
static int xdmcpInited;
863
switch (cmd = ctrlGreeterWait(True)) {
872
sessionExit(EX_UNMANAGE_DPY);
875
if ((td->displayType & d_location) == dLocal) {
876
/* XXX the config reader should do the lookup already */
877
for (hostp = td->chooserHosts; *hostp; hostp++)
878
if (!registerForPing(*hostp))
879
logError("Unknown host %\"s specified for local chooser preload of display %s\n", *hostp, td->name);
881
forEachChooserHost(&td->clientAddr, td->connectionType,
884
gSendInt(0); /* entering async mode signal */
887
for (h = hostNamedb; h; h = h->next)
894
if (pingTry <= PING_TRIES) {
895
gettimeofday(&tnow, 0);
896
if (nextPing.tv_sec < tnow.tv_sec ||
897
(nextPing.tv_sec == tnow.tv_sec &&
898
nextPing.tv_usec < tnow.tv_usec))
900
if (pingTry < PING_TRIES) {
904
gettimeofday(&tnow, 0);
908
for (hp = &hostNamedb; *hp;)
911
disposeHostname(*hp);
912
gSendInt(G_Ch_RemoveHost);
913
gSendInt((int)(long)*hp); /* just an id */
922
tnow.tv_sec = nextPing.tv_sec - tnow.tv_sec;
923
tnow.tv_usec = nextPing.tv_usec - tnow.tv_usec;
924
if (tnow.tv_usec < 0) {
925
tnow.tv_usec += 1000000;
931
FD_SET(grtproc.pipe.fd.r, &rfds);
932
FD_SET(socketFD, &rfds);
933
#if defined(IPv6) && defined(AF_INET6)
935
FD_SET(socket6FD, &rfds);
937
n = grtproc.pipe.fd.r;
940
#if defined(IPv6) && defined(AF_INET6)
944
if (select(n + 1, &rfds, 0, 0, to) > 0) {
945
if (FD_ISSET(grtproc.pipe.fd.r, &rfds))
946
switch (cmd = ctrlGreeterWait(False)) {
951
case G_Ch_RegisterHost:
953
if (!registerForPing(host)) {
954
gSendInt(G_Ch_BadHost);
959
case G_Ch_DirectChoice:
961
directChooseHost(host);
962
gSendInt(G_Ch_BadHost);
967
chooseHost(gRecvInt());
974
if (FD_ISSET(socketFD, &rfds))
975
receivePacket(socketFD);
976
#if defined(IPv6) && defined(AF_INET6)
977
if (socket6FD >= 0 && FD_ISSET(socket6FD, &rfds))
978
receivePacket(socket6FD);