Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / ACE / ace / Sock_Connect.cpp
blobae3ce1ace0f3229324d25c602046902e9e65e9fa
1 #include "ace/Sock_Connect.h"
2 #include "ace/INET_Addr.h"
3 #include "ace/Log_Category.h"
4 #include "ace/Handle_Set.h"
5 #include "ace/SString.h"
6 #include "ace/OS_Memory.h"
7 #include "ace/OS_NS_stdio.h"
8 #include "ace/ACE.h"
9 #include "ace/OS_NS_stdlib.h"
10 #include "ace/OS_NS_string.h"
11 #include "ace/OS_NS_sys_socket.h"
12 #include "ace/OS_NS_netdb.h"
13 #include "ace/OS_NS_unistd.h"
14 #include "ace/os_include/net/os_if.h"
16 #if defined (ACE_HAS_IPV6)
17 # include "ace/Guard_T.h"
18 # include "ace/Recursive_Thread_Mutex.h"
19 #endif /* ACE_HAS_IPV6 */
21 #if defined (ACE_HAS_GETIFADDRS)
22 # include "ace/os_include/os_ifaddrs.h"
23 #endif /* ACE_HAS_GETIFADDRS */
25 #if defined (ACE_VXWORKS) && (ACE_VXWORKS <= 0x670) && defined (__RTP__) && defined (ACE_HAS_IPV6)
26 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
27 const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
28 const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
29 const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
30 #endif /* ACE_VXWORKS <= 0x670 && __RTP__ && ACE_HAS_IPV6 */
32 #if defined (ACE_WIN32)
33 # include "ace/OS_NS_stdio.h"
34 #endif
36 #if defined (ACE_HAS_IPV6)
38 // These defines support a generic usage based on
39 // the various SIGCF*IF ioctl implementations
41 # if defined (SIOCGLIFCONF)
42 # define SIOCGIFCONF_CMD SIOCGLIFCONF
43 # define IFREQ lifreq
44 # define IFCONF lifconf
45 # define IFC_REQ lifc_req
46 # define IFC_LEN lifc_len
47 # define IFC_BUF lifc_buf
48 # define IFR_ADDR lifr_addr
49 # define IFR_NAME lifr_name
50 # define IFR_FLAGS lifr_flags
51 # define SETFAMILY
52 # define IFC_FAMILY lifc_family
53 # define IFC_FLAGS lifc_flags
54 # define SA_FAMILY ss_family
55 # else
56 # define SIOCGIFCONF_CMD SIOCGIFCONF
57 # define IFREQ ifreq
58 # define IFCONF ifconf
59 # define IFC_REQ ifc_req
60 # define IFC_LEN ifc_len
61 # define IFC_BUF ifc_buf
62 # define IFR_ADDR ifr_addr
63 # define IFR_NAME ifr_name
64 # define IFR_FLAGS ifr_flags
65 # undef SETFAMILY
66 # define SA_FAMILY sa_family
67 # endif /* SIOCGLIFCONF */
69 # if defined (ACE_HAS_THREADS)
70 # include "ace/Object_Manager.h"
71 # endif /* ACE_HAS_THREADS */
73 namespace
75 // private:
76 // Used internally so not exported.
78 // Does this box have ipv4 turned on?
79 int ace_ipv4_enabled = -1;
81 // Does this box have ipv6 turned on?
82 int ace_ipv6_enabled = -1;
84 #else /* ACE_HAS_IPV6 */
85 # define SIOCGIFCONF_CMD SIOCGIFCONF
86 # define IFREQ ifreq
87 # define IFCONF ifconf
88 # define IFC_REQ ifc_req
89 # define IFC_LEN ifc_len
90 # define IFC_BUF ifc_buf
91 # define IFR_ADDR ifr_addr
92 # define IFR_NAME ifr_name
93 # define IFR_FLAGS ifr_flags
94 # undef SETFAMILY
95 # define SA_FAMILY sa_family
96 #endif /* ACE_HAS_IPV6 */
98 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
100 // Bind socket to an unused port.
103 ACE::bind_port (ACE_HANDLE handle, ACE_UINT32 ip_addr, int address_family)
105 ACE_TRACE ("ACE::bind_port");
107 ACE_INET_Addr addr;
109 #if defined (ACE_HAS_IPV6)
110 if (address_family != PF_INET6)
111 // What do we do if it is PF_"INET6? Since it's 4 bytes, it must be an
112 // IPV4 address. Is there a difference? Why is this test done? dhinton
113 #else /* ACE_HAS_IPV6 */
114 ACE_UNUSED_ARG (address_family);
115 #endif /* !ACE_HAS_IPV6 */
116 addr = ACE_INET_Addr ((u_short)0, ip_addr);
117 #if defined (ACE_HAS_IPV6)
118 else if (ip_addr != INADDR_ANY)
119 // address_family == PF_INET6 and a non default IP address means to bind
120 // to the IPv4-mapped IPv6 address
121 addr.set ((u_short)0, ip_addr, 1, 1);
122 #endif /* ACE_HAS_IPV6 */
124 // The OS kernel should select a free port for us.
125 return ACE_OS::bind (handle,
126 (sockaddr*)addr.get_addr(),
127 addr.get_size());
131 ACE::get_bcast_addr (ACE_UINT32 &bcast_addr,
132 const ACE_TCHAR *host_name,
133 ACE_UINT32 host_addr,
134 ACE_HANDLE handle)
136 ACE_TRACE ("ACE::get_bcast_addr");
138 #if defined (ACE_LACKS_GET_BCAST_ADDR)
139 ACE_UNUSED_ARG (bcast_addr);
140 ACE_UNUSED_ARG (host_name);
141 ACE_UNUSED_ARG (host_addr);
142 ACE_UNUSED_ARG (handle);
143 ACE_NOTSUP_RETURN (-1);
144 #elif !defined(ACE_WIN32)
145 ACE_HANDLE s = handle;
147 if (s == ACE_INVALID_HANDLE)
148 s = ACE_OS::socket (AF_INET, SOCK_STREAM, 0);
150 if (s == ACE_INVALID_HANDLE)
151 ACELIB_ERROR_RETURN ((LM_ERROR,
152 ACE_TEXT ("%p\n"),
153 ACE_TEXT ("ACE_OS::socket")),
154 -1);
156 struct ifconf ifc;
157 char buf[BUFSIZ];
159 ifc.ifc_len = sizeof buf;
160 ifc.ifc_buf = buf;
162 // Get interface structure and initialize the addresses using UNIX
163 // techniques
164 if (ACE_OS::ioctl (s, SIOCGIFCONF_CMD, (char *) &ifc) == -1)
165 ACELIB_ERROR_RETURN ((LM_ERROR,
166 ACE_TEXT ("%p\n"),
167 ACE_TEXT ("ACE::get_bcast_addr:")
168 ACE_TEXT ("ioctl (get interface configuration)")),
169 -1);
171 struct ifreq *ifr = ifc.ifc_req;
173 struct sockaddr_in ip_addr;
175 // Get host ip address if necessary.
176 if (host_name)
178 hostent *hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR (host_name));
180 if (hp == 0)
181 return -1;
182 else
183 ACE_OS::memcpy ((char *) &ip_addr.sin_addr.s_addr,
184 # ifdef ACE_HOSTENT_H_ADDR
185 (char *) hp->ACE_HOSTENT_H_ADDR,
186 # else
187 (char *) hp->h_addr,
188 # endif
189 hp->h_length);
191 else
193 ACE_OS::memset ((void *) &ip_addr, 0, sizeof ip_addr);
194 ACE_OS::memcpy ((void *) &ip_addr.sin_addr,
195 (void*) &host_addr,
196 sizeof ip_addr.sin_addr);
199 #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
200 for (int n = ifc.ifc_len / sizeof (struct ifreq) ; n > 0;
201 n--, ifr++)
202 #else
203 // see mk_broadcast@SOCK_Dgram_Bcast.cpp
204 for (int nbytes = ifc.ifc_len; nbytes >= (int) sizeof (struct ifreq) &&
205 ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
206 (nbytes >= (int) sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len) : 1);
207 ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
208 (nbytes -= sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len,
209 ifr = (struct ifreq *)
210 ((caddr_t) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) :
211 (nbytes -= sizeof (struct ifreq), ifr++)))
212 #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
214 struct sockaddr_in if_addr;
216 // Compare host ip address with interface ip address.
217 ACE_OS::memcpy (&if_addr,
218 &ifr->ifr_addr,
219 sizeof if_addr);
221 if (ip_addr.sin_addr.s_addr != if_addr.sin_addr.s_addr)
222 continue;
224 if (ifr->ifr_addr.sa_family != AF_INET)
226 ACELIB_ERROR ((LM_ERROR,
227 ACE_TEXT ("%p\n"),
228 ACE_TEXT ("ACE::get_bcast_addr:")
229 ACE_TEXT ("Not AF_INET")));
230 continue;
233 struct ifreq flags = *ifr;
234 struct ifreq if_req = *ifr;
236 if (ACE_OS::ioctl (s, SIOCGIFFLAGS, (char *) &flags) == -1)
238 ACELIB_ERROR ((LM_ERROR,
239 ACE_TEXT ("%p\n"),
240 ACE_TEXT ("ACE::get_bcast_addr:")
241 ACE_TEXT (" ioctl (get interface flags)")));
242 continue;
245 if (ACE_BIT_DISABLED (flags.ifr_flags, IFF_UP))
247 ACELIB_ERROR ((LM_ERROR,
248 ACE_TEXT ("%p\n"),
249 ACE_TEXT ("ACE::get_bcast_addr:")
250 ACE_TEXT ("Network interface is not up")));
251 continue;
254 if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_LOOPBACK))
255 continue;
257 if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_BROADCAST))
259 if (ACE_OS::ioctl (s,
260 SIOCGIFBRDADDR,
261 (char *) &if_req) == -1)
262 ACELIB_ERROR ((LM_ERROR,
263 ACE_TEXT ("%p\n"),
264 ACE_TEXT ("ACE::get_bcast_addr:")
265 ACE_TEXT ("ioctl (get broadaddr)")));
266 else
268 ACE_OS::memcpy (&ip_addr,
269 &if_req.ifr_broadaddr,
270 sizeof if_req.ifr_broadaddr);
272 ACE_OS::memcpy ((void *) &host_addr,
273 (void *) &ip_addr.sin_addr,
274 sizeof host_addr);
276 if (handle == ACE_INVALID_HANDLE)
277 ACE_OS::close (s);
279 bcast_addr = host_addr;
280 return 0;
283 else
284 ACELIB_ERROR ((LM_ERROR,
285 ACE_TEXT ("%p\n"),
286 ACE_TEXT ("ACE::get_bcast_addr:")
287 ACE_TEXT ("Broadcast is not enabled for this interface.")));
289 if (handle == ACE_INVALID_HANDLE)
290 ACE_OS::close (s);
292 bcast_addr = host_addr;
293 return 0;
296 return 0;
297 #else
298 ACE_UNUSED_ARG (handle);
299 ACE_UNUSED_ARG (host_addr);
300 ACE_UNUSED_ARG (host_name);
301 bcast_addr = (ACE_UINT32 (INADDR_BROADCAST));
302 return 0;
303 #endif /* !ACE_WIN32 */
307 ACE::get_fqdn (ACE_INET_Addr const & addr,
308 char hostname[],
309 size_t len)
311 #ifndef ACE_LACKS_GETNAMEINFO
313 const socklen_t addr_size =
314 # ifdef ACE_HAS_IPV6
315 (addr.get_type () == PF_INET6) ? sizeof (sockaddr_in6) :
316 # endif
317 sizeof (sockaddr_in);
319 if (ACE_OS::getnameinfo ((const sockaddr *) addr.get_addr (),
320 addr_size, hostname,
321 static_cast<ACE_SOCKET_LEN> (len),
322 0, 0, NI_NAMEREQD) != 0)
323 return -1;
325 if (ACE::debug ())
326 ACELIB_DEBUG ((LM_DEBUG,
327 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
328 ACE_TEXT ("canonical host name is %C\n"),
329 hostname));
331 return 0;
332 #else // below, ACE_LACKS_GETNAMEINFO
333 int h_error; // Not the same as errno!
334 hostent hentry;
335 ACE_HOSTENT_DATA buf;
337 char * ip_addr = 0;
338 int ip_addr_size = 0;
339 if (addr.get_type () == AF_INET)
341 sockaddr_in * const sock_addr =
342 reinterpret_cast<sockaddr_in *> (addr.get_addr ());
343 ip_addr_size = sizeof sock_addr->sin_addr;
344 ip_addr = (char*) &sock_addr->sin_addr;
346 # ifdef ACE_HAS_IPV6
347 else
349 sockaddr_in6 * sock_addr =
350 reinterpret_cast<sockaddr_in6 *> (addr.get_addr ());
352 ip_addr_size = sizeof sock_addr->sin6_addr;
353 ip_addr = (char*) &sock_addr->sin6_addr;
355 # endif /* ACE_HAS_IPV6 */
357 // get the host entry for the address in question
358 hostent * const hp = ACE_OS::gethostbyaddr_r (ip_addr,
359 ip_addr_size,
360 addr.get_type (),
361 &hentry,
362 buf,
363 &h_error);
365 // if it's not found in the host file or the DNS datase, there is nothing
366 // much we can do. embed the IP address
367 if (hp == 0 || hp->h_name == 0)
368 return -1;
370 if (ACE::debug())
371 ACELIB_DEBUG ((LM_DEBUG,
372 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
373 ACE_TEXT ("canonical host name is %C\n"),
374 hp->h_name));
376 // check if the canonical name is the FQDN
377 if (!ACE_OS::strchr(hp->h_name, '.'))
379 // list of address
380 char** p;
381 // list of aliases
382 char** q;
384 // for every address and for every alias within the address, check and
385 // see if we can locate a FQDN
386 for (p = hp->h_addr_list; *p != 0; ++p)
388 for (q = hp->h_aliases; *q != 0; ++q)
390 if (ACE_OS::strchr(*q, '.'))
392 // we got an FQDN from an alias. use this
393 if (ACE_OS::strlen (*q) >= len)
394 // the hostname is too huge to fit into a
395 // buffer of size MAXHOSTNAMELEN
396 // should we check other aliases as well
397 // before bailing out prematurely?
398 // for right now, let's do it. this (short name)
399 // is atleast better than embedding the IP
400 // address in the profile
401 continue;
403 if (ACE::debug ())
404 ACELIB_DEBUG ((LM_DEBUG,
405 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
406 ACE_TEXT ("found fqdn within alias as %C\n"),
407 *q));
408 ACE_OS::strcpy (hostname, *q);
410 return 0;
416 // The canonical name may be an FQDN when we reach here.
417 // Alternatively, the canonical name (a non FQDN) may be the best
418 // we can do.
419 if (ACE_OS::strlen (hp->h_name) >= len)
421 // The hostname is too large to fit into a buffer of size
422 // MAXHOSTNAMELEN.
423 return -2;
425 else
427 ACE_OS::strcpy (hostname, hp->h_name);
430 return 0;
431 #endif /* ACE_LACKS_GETNAMEINFO */
434 #if defined (ACE_WIN32)
436 static int
437 get_ip_interfaces_win32 (size_t &count,
438 ACE_INET_Addr *&addrs)
440 int i, n_interfaces, status;
442 INTERFACE_INFO info[64];
443 SOCKET sock;
445 // Get an (overlapped) DGRAM socket to test with
446 sock = socket (AF_INET, SOCK_DGRAM, 0);
447 if (sock == INVALID_SOCKET)
448 return -1;
450 DWORD bytes;
451 status = WSAIoctl(sock,
452 SIO_GET_INTERFACE_LIST,
455 info,
456 sizeof(info),
457 &bytes,
460 closesocket (sock);
461 if (status == SOCKET_ERROR)
462 return -1;
464 n_interfaces = bytes / sizeof(INTERFACE_INFO);
466 // SIO_GET_INTERFACE_LIST does not work for IPv6
467 // Instead recent versions of Winsock2 add the new opcode
468 // SIO_ADDRESS_LIST_QUERY.
469 // If this is not available forget about IPv6 local interfaces:-/
470 int n_v6_interfaces = 0;
472 # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY)
474 LPSOCKET_ADDRESS_LIST v6info;
475 char *buffer;
476 DWORD buflen = sizeof (SOCKET_ADDRESS_LIST) + (63 * sizeof (SOCKET_ADDRESS));
477 ACE_NEW_RETURN (buffer,
478 char[buflen],
479 -1);
480 v6info = reinterpret_cast<LPSOCKET_ADDRESS_LIST> (buffer);
482 // Get an (overlapped) DGRAM socket to test with.
483 // If it fails only return IPv4 interfaces.
484 sock = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
485 if (sock != INVALID_SOCKET)
487 status = WSAIoctl(sock,
488 SIO_ADDRESS_LIST_QUERY,
491 v6info,
492 buflen,
493 &bytes,
496 closesocket (sock);
497 if (status != SOCKET_ERROR)
498 n_v6_interfaces = v6info->iAddressCount;
500 # endif /* ACE_HAS_IPV6 */
502 ACE_NEW_RETURN (addrs,
503 ACE_INET_Addr[n_interfaces + n_v6_interfaces],
504 -1);
506 // Now go through the list and transfer the good ones to the list of
507 // because they're down or don't have an IP address.
508 for (count = 0, i = 0; i < n_interfaces; ++i)
510 LPINTERFACE_INFO lpii;
511 struct sockaddr_in *addrp = 0;
513 lpii = &info[i];
514 if (!(lpii->iiFlags & IFF_UP))
515 continue;
517 // We assume IPv4 addresses here
518 addrp = reinterpret_cast<struct sockaddr_in *> (&lpii->iiAddress.AddressIn);
519 if (addrp->sin_addr.s_addr == INADDR_ANY)
520 continue;
522 // Set the address for the caller.
523 addrs[count].set(addrp, sizeof(sockaddr_in));
524 ++count;
527 # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY)
528 // Now go through the list and transfer the good ones to the list of
529 // because they're down or don't have an IP address.
530 for (i = 0; i < n_v6_interfaces; i++)
532 struct sockaddr_in6 *addr6p;
534 if (v6info->Address[i].lpSockaddr->sa_family != AF_INET6)
535 continue;
537 addr6p = reinterpret_cast<struct sockaddr_in6 *> (v6info->Address[i].lpSockaddr);
538 if (IN6_IS_ADDR_UNSPECIFIED(&addr6p->sin6_addr)) // IN6ADDR_ANY?
539 continue;
541 // Set the address for the caller.
542 addrs[count].set(reinterpret_cast<struct sockaddr_in *> (addr6p), sizeof(sockaddr_in6));
543 ++count;
546 delete [] buffer; // Clean up
547 # endif /* ACE_HAS_IPV6 */
549 if (count == 0)
551 delete [] addrs;
552 addrs = 0;
555 return 0;
558 #elif defined (ACE_HAS_GETIFADDRS)
559 static int
560 get_ip_interfaces_getifaddrs (size_t &count,
561 ACE_INET_Addr *&addrs)
563 // Take advantage of the BSD getifaddrs function that simplifies
564 // access to connected interfaces.
565 struct ifaddrs *ifap = 0;
566 struct ifaddrs *p_if = 0;
568 if (::getifaddrs (&ifap) != 0)
569 return -1;
571 // Count number of interfaces.
572 size_t num_ifs = 0;
573 for (p_if = ifap; p_if != 0; p_if = p_if->ifa_next)
574 ++num_ifs;
576 // Now create and initialize output array.
577 ACE_NEW_RETURN (addrs,
578 ACE_INET_Addr[num_ifs],
579 -1); // caller must free
581 // Pull the address out of each INET interface. Not every interface
582 // is for IP, so be careful to count properly. When setting the
583 // INET_Addr, note that the 3rd arg (0) says to leave the byte order
584 // (already in net byte order from the interface structure) as is.
585 count = 0;
587 for (p_if = ifap;
588 p_if != 0;
589 p_if = p_if->ifa_next)
591 if (p_if->ifa_addr == 0)
592 continue;
594 // Check to see if it's up.
595 if ((p_if->ifa_flags & IFF_UP) != IFF_UP)
596 continue;
598 if (p_if->ifa_addr->sa_family == AF_INET)
600 struct sockaddr_in *addr =
601 reinterpret_cast<sockaddr_in *> (p_if->ifa_addr);
603 // Sometimes the kernel returns 0.0.0.0 as the interface
604 // address, skip those...
605 if (addr->sin_addr.s_addr != INADDR_ANY)
607 addrs[count].set ((u_short) 0,
608 addr->sin_addr.s_addr,
610 ++count;
613 # if defined (ACE_HAS_IPV6)
614 else if (p_if->ifa_addr->sa_family == AF_INET6)
616 struct sockaddr_in6 *addr =
617 reinterpret_cast<sockaddr_in6 *> (p_if->ifa_addr);
619 // Skip the ANY address
620 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr))
622 addrs[count].set(reinterpret_cast<struct sockaddr_in *> (addr),
623 sizeof(sockaddr_in6));
624 ++count;
627 # endif /* ACE_HAS_IPV6 */
630 ::freeifaddrs (ifap);
632 return 0;
634 #endif // ACE_WIN32 || ACE_HAS_GETIFADDRS
637 // return an array of all configured IP interfaces on this host, count
638 // rc = 0 on success (count == number of interfaces else -1 caller is
639 // responsible for calling delete [] on parray
642 ACE::get_ip_interfaces (size_t &count, ACE_INET_Addr *&addrs)
644 ACE_TRACE ("ACE::get_ip_interfaces");
646 count = 0;
647 addrs = 0;
649 #if defined (ACE_WIN32)
650 return get_ip_interfaces_win32 (count, addrs);
651 #elif defined (ACE_HAS_GETIFADDRS)
652 return get_ip_interfaces_getifaddrs (count, addrs);
653 #elif (defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS))) && !defined (ACE_LACKS_NETWORKING)
654 // COMMON (SVR4 and BSD) UNIX CODE
656 // Call specific routine as necessary.
657 ACE_HANDLE handle = ACE::get_handle();
659 if (handle == ACE_INVALID_HANDLE)
660 ACELIB_ERROR_RETURN ((LM_ERROR,
661 ACE_TEXT ("%p\n"),
662 ACE_TEXT ("ACE::get_ip_interfaces:open")),
663 -1);
665 size_t num_ifs = 0;
667 if (ACE::count_interfaces (handle, num_ifs))
669 ACE_OS::close (handle);
670 return -1;
673 // ioctl likes to have an extra ifreq structure to mark the end of
674 // what it returned, so increase the num_ifs by one.
675 ++num_ifs;
677 struct IFREQ *ifs = 0;
678 ACE_NEW_RETURN (ifs,
679 struct IFREQ[num_ifs],
680 -1);
681 ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct IFREQ));
683 std::unique_ptr<struct IFREQ[]> p_ifs (ifs);
685 if (p_ifs.get() == 0)
687 ACE_OS::close (handle);
688 errno = ENOMEM;
689 return -1;
692 struct IFCONF ifcfg;
693 ACE_OS::memset (&ifcfg, 0, sizeof (struct IFCONF));
695 # ifdef SETFAMILY
696 ifcfg.IFC_FAMILY = AF_UNSPEC; // request all families be returned
697 ifcfg.IFC_FLAGS = 0;
698 # endif
700 ifcfg.IFC_REQ = p_ifs.get ();
701 ifcfg.IFC_LEN = num_ifs * sizeof (struct IFREQ);
703 if (ACE_OS::ioctl (handle,
704 SIOCGIFCONF_CMD,
705 (caddr_t) &ifcfg) == -1)
707 ACE_OS::close (handle);
708 ACELIB_ERROR_RETURN ((LM_ERROR,
709 ACE_TEXT ("%p\n"),
710 ACE_TEXT ("ACE::get_ip_interfaces:")
711 ACE_TEXT ("ioctl - SIOCGIFCONF failed")),
712 -1);
715 ACE_OS::close (handle);
717 // Now create and initialize output array.
719 ACE_NEW_RETURN (addrs,
720 ACE_INET_Addr[num_ifs],
721 -1); // caller must free
723 struct IFREQ *pcur = p_ifs.get ();
724 size_t num_ifs_found = ifcfg.IFC_LEN / sizeof (struct IFREQ); // get the number of returned ifs
726 // Pull the address out of each INET interface. Not every interface
727 // is for IP, so be careful to count properly. When setting the
728 // INET_Addr, note that the 3rd arg (0) says to leave the byte order
729 // (already in net byte order from the interface structure) as is.
730 count = 0;
732 for (size_t i = 0;
733 i < num_ifs_found;
734 i++)
736 if (pcur->IFR_ADDR.SA_FAMILY == AF_INET
737 # if defined (ACE_HAS_IPV6)
738 || pcur->IFR_ADDR.SA_FAMILY == AF_INET6
739 # endif
743 struct sockaddr_in *addr =
744 reinterpret_cast<sockaddr_in *> (&pcur->IFR_ADDR);
746 // Sometimes the kernel returns 0.0.0.0 as an IPv4 interface
747 // address; skip those...
748 if (addr->sin_addr.s_addr != 0
749 # if defined (ACE_HAS_IPV6)
750 || (addr->sin_family == AF_INET6 &&
751 !IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast<sockaddr_in6 *>(addr)->sin6_addr))
752 # endif
755 int addrlen = static_cast<int> (sizeof (struct sockaddr_in));
756 # if defined (ACE_HAS_IPV6)
757 if (addr->sin_family == AF_INET6)
758 addrlen = static_cast<int> (sizeof (struct sockaddr_in6));
759 # endif
760 addrs[count].set (addr, addrlen);
761 ++count;
765 #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
766 ++pcur;
767 #else
768 if (pcur->ifr_addr.sa_len <= sizeof (struct sockaddr))
770 ++pcur;
772 else
774 pcur = (struct ifreq *)
775 (pcur->ifr_addr.sa_len + (caddr_t) &pcur->ifr_addr);
777 #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
780 # if defined (ACE_HAS_IPV6) && !defined (ACE_LACKS_FSCANF)
781 // Retrieve IPv6 local interfaces by scanning /proc/net/if_inet6 if
782 // it exists. If we cannot open it then ignore possible IPv6
783 // interfaces, we did our best;-)
784 FILE* fp = 0;
785 char addr_p[8][5];
786 char s_ipaddr[64];
787 int scopeid;
788 struct addrinfo hints, *res0;
789 int error;
791 ACE_OS::memset (&hints, 0, sizeof (hints));
792 hints.ai_flags = AI_NUMERICHOST;
793 hints.ai_family = AF_INET6;
795 if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0)
797 while (fscanf (fp,
798 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*8s\n",
799 addr_p[0], addr_p[1], addr_p[2], addr_p[3],
800 addr_p[4], addr_p[5], addr_p[6], addr_p[7], &scopeid) != EOF)
802 // Format the address intoa proper IPv6 decimal address specification and
803 // resolve the resulting text using getaddrinfo().
805 const char* ip_fmt = "%s:%s:%s:%s:%s:%s:%s:%s%%%d";
806 ACE_OS::snprintf (s_ipaddr, 64, ip_fmt,
807 addr_p[0], addr_p[1], addr_p[2], addr_p[3],
808 addr_p[4], addr_p[5], addr_p[6], addr_p[7],
809 scopeid);
811 error = ACE_OS::getaddrinfo (s_ipaddr, 0, &hints, &res0);
812 if (error)
813 continue;
815 if (res0->ai_family == AF_INET6 &&
816 !IN6_IS_ADDR_UNSPECIFIED (&reinterpret_cast<sockaddr_in6 *> (res0->ai_addr)->sin6_addr))
818 addrs[count].set(reinterpret_cast<sockaddr_in *> (res0->ai_addr), res0->ai_addrlen);
819 ++count;
821 ACE_OS::freeaddrinfo (res0);
823 ACE_OS::fclose (fp);
825 # endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */
827 return 0;
828 #else
829 ACE_UNUSED_ARG (count);
830 ACE_UNUSED_ARG (addrs);
831 ACE_NOTSUP_RETURN (-1); // no implementation
832 #endif /* ACE_WIN32 */
835 // Helper routine for get_ip_interfaces, differs by UNIX platform so
836 // put into own subroutine. perform some ioctls to retrieve ifconf
837 // list of ifreq structs.
840 ACE::count_interfaces (ACE_HANDLE handle, size_t &how_many)
842 #if defined (SIOCGIFNUM)
843 # if defined (SIOCGLIFNUM)
844 int cmd = SIOCGLIFNUM;
845 struct lifnum if_num = {AF_UNSPEC,0,0};
846 # else
847 int cmd = SIOCGIFNUM;
848 int if_num = 0;
849 # endif /* SIOCGLIFNUM */
850 if (ACE_OS::ioctl (handle, cmd, (caddr_t)&if_num) == -1)
851 ACELIB_ERROR_RETURN ((LM_ERROR,
852 ACE_TEXT ("%p\n"),
853 ACE_TEXT ("ACE::count_interfaces:")
854 ACE_TEXT ("ioctl - SIOCGLIFNUM failed")),
855 -1);
856 # if defined (SIOCGLIFNUM)
857 how_many = if_num.lifn_count;
858 # else
859 how_many = if_num;
860 # endif /* SIOCGLIFNUM */
861 return 0;
863 #elif (defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS))) && !defined (ACE_LACKS_NETWORKING)
864 // Note: DEC CXX doesn't define "unix". BSD compatible OS: HP UX,
865 // SunOS 4.x perform some ioctls to retrieve ifconf list of
866 // ifreq structs no SIOCGIFNUM on SunOS 4.x, so use guess and scan
867 // algorithm
869 // Probably hard to put this many ifs in a unix box..
870 int const MAX_INTERFACES = 50;
872 // HACK - set to an unreasonable number
873 int const num_ifs = MAX_INTERFACES;
875 struct ifconf ifcfg;
876 size_t ifreq_size = num_ifs * sizeof (struct ifreq);
877 struct ifreq *p_ifs;
879 #if defined (ACE_HAS_ALLOC_HOOKS)
880 p_ifs = (struct IFREQ *)ACE_Allocator::instance()->malloc (ifreq_size);
881 #else
882 p_ifs = (struct ifreq *) ACE_OS::malloc (ifreq_size);
883 #endif /* ACE_HAS_ALLOC_HOOKS */
885 if (!p_ifs)
887 errno = ENOMEM;
888 return -1;
891 ACE_OS::memset (p_ifs, 0, ifreq_size);
892 ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf));
894 ifcfg.ifc_req = p_ifs;
895 ifcfg.ifc_len = ifreq_size;
897 if (ACE_OS::ioctl (handle,
898 SIOCGIFCONF_CMD,
899 (caddr_t) &ifcfg) == -1)
901 #if defined (ACE_HAS_ALLOC_HOOKS)
902 ACE_Allocator::instance()->free (ifcfg.ifc_req);
903 #else
904 ACE_OS::free (ifcfg.ifc_req);
905 #endif /* ACE_HAS_ALLOC_HOOKS */
907 ACELIB_ERROR_RETURN ((LM_ERROR,
908 ACE_TEXT ("%p\n"),
909 ACE_TEXT ("ACE::count_interfaces:")
910 ACE_TEXT ("ioctl - SIOCGIFCONF failed")),
911 -1);
914 int if_count = 0;
915 int i = 0;
917 // get if address out of ifreq buffers. ioctl puts a blank-named
918 // interface to mark the end of the returned interfaces.
919 for (i = 0;
920 i < num_ifs;
921 i++)
923 /* In OpenBSD, the length of the list is returned. */
924 ifcfg.ifc_len -= sizeof (struct ifreq);
925 if (ifcfg.ifc_len < 0)
926 break;
928 ++if_count;
929 # if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
930 ++p_ifs;
931 # else
932 if (p_ifs->ifr_addr.sa_len <= sizeof (struct sockaddr))
934 ++p_ifs;
936 else
938 p_ifs = (struct ifreq *)
939 (p_ifs->ifr_addr.sa_len + (caddr_t) &p_ifs->ifr_addr);
941 # endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
944 #if defined (ACE_HAS_ALLOC_HOOKS)
945 ACE_Allocator::instance()->free (ifcfg.ifc_req);
946 #else
947 ACE_OS::free (ifcfg.ifc_req);
948 #endif /* ACE_HAS_ALLOC_HOOKS */
950 # if defined (ACE_HAS_IPV6)
951 FILE* fp = 0;
953 if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0)
955 // Scan the lines according to the expected format but don't really read any input
956 while (fscanf (fp, "%*32s %*02x %*02x %*02x %*02x %*8s\n") != EOF)
958 ++if_count;
960 ACE_OS::fclose (fp);
962 # endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */
964 how_many = if_count;
965 return 0;
966 #else
967 ACE_UNUSED_ARG (handle);
968 ACE_UNUSED_ARG (how_many);
969 ACE_NOTSUP_RETURN (-1); // no implementation
970 #endif /* sparc && SIOCGIFNUM */
973 // Routine to return a handle from which ioctl() requests can be made.
974 ACE_HANDLE
975 ACE::get_handle ()
977 ACE_HANDLE handle = ACE_INVALID_HANDLE;
978 #if defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600))
979 // Note: DEC CXX doesn't define "unix" BSD compatible OS: SunOS 4.x
980 handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0);
981 #endif /* __unux */
982 return handle;
985 #if defined (ACE_HAS_IPV6)
986 static int
987 ip_check (int &ipvn_enabled, int pf)
989 // We only get to this point if ipvn_enabled was -1 in the caller.
990 // Perform Double-Checked Locking Optimization.
991 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
992 *ACE_Static_Object_Lock::instance (), 0));
994 if (ipvn_enabled == -1)
996 #if defined (ACE_WIN32)
997 static bool recursing = false;
998 if (recursing) return 1;
1000 // as of the release of Windows 2008, even hosts that have IPv6 interfaces disabled
1001 // will still permit the creation of a PF_INET6 socket, thus rendering the socket
1002 // creation test inconsistent. The recommended solution is to get the list of
1003 // endpoint addresses and see if any match the desired family.
1004 ACE_INET_Addr *if_addrs = 0;
1005 size_t if_cnt = 0;
1007 // assume enabled to avoid recursion during interface lookup.
1008 recursing = true;
1009 ACE::get_ip_interfaces (if_cnt, if_addrs);
1010 recursing = false;
1012 bool found = false;
1013 for (size_t i = 0; !found && i < if_cnt; i++)
1015 found = (if_addrs[i].get_type () == pf);
1017 delete [] if_addrs;
1019 // If the list of interfaces is empty, we've tried too quickly. Assume enabled, but don't cache the result
1020 if (!if_cnt) return 1;
1022 ipvn_enabled = found ? 1 : 0;
1023 #else
1024 // Determine if the kernel has IPv6 support by attempting to
1025 // create a PF_INET6 socket and see if it fails.
1026 ACE_HANDLE const s = ACE_OS::socket (pf, SOCK_DGRAM, 0);
1027 if (s == ACE_INVALID_HANDLE)
1029 ipvn_enabled = 0;
1031 else
1033 ipvn_enabled = 1;
1034 ACE_OS::closesocket (s);
1036 #endif
1038 return ipvn_enabled;
1040 #endif /* ACE_HAS_IPV6 */
1042 bool
1043 ACE::ipv4_enabled ()
1045 #if defined (ACE_HAS_IPV6)
1046 return static_cast<bool> (ace_ipv4_enabled == -1 ?
1047 ::ip_check (ace_ipv4_enabled, PF_INET) :
1048 ace_ipv4_enabled);
1049 #else
1050 // Assume it's always enabled since ACE requires some version of
1051 // TCP/IP to exist.
1052 return true;
1053 #endif /* ACE_HAS_IPV6*/
1057 ACE::ipv6_enabled ()
1059 #if defined (ACE_HAS_IPV6)
1060 return ace_ipv6_enabled == -1 ?
1061 ::ip_check (ace_ipv6_enabled, PF_INET6) :
1062 ace_ipv6_enabled;
1063 #else /* ACE_HAS_IPV6 */
1064 return 0;
1065 #endif /* !ACE_HAS_IPV6 */
1068 ACE_END_VERSIONED_NAMESPACE_DECL