Document return values
[ACE_TAO.git] / ACE / ace / Sock_Connect.cpp
blob6d7fd6b1282e7ba02fd9b184a39818dafbd41374
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/Auto_Ptr.h"
6 #include "ace/SString.h"
7 #include "ace/OS_Memory.h"
8 #include "ace/OS_NS_stdio.h"
9 #include "ace/ACE.h"
10 #include "ace/OS_NS_stdlib.h"
11 #include "ace/OS_NS_string.h"
12 #include "ace/OS_NS_sys_socket.h"
13 #include "ace/OS_NS_netdb.h"
14 #include "ace/OS_NS_unistd.h"
15 #include "ace/os_include/net/os_if.h"
17 #if defined (ACE_HAS_IPV6)
18 # include "ace/Guard_T.h"
19 # include "ace/Recursive_Thread_Mutex.h"
20 #endif /* ACE_HAS_IPV6 */
22 #if defined (ACE_HAS_GETIFADDRS)
23 # include "ace/os_include/os_ifaddrs.h"
24 #endif /* ACE_HAS_GETIFADDRS */
26 #if defined (ACE_VXWORKS) && (ACE_VXWORKS <= 0x670) && defined (__RTP__) && defined (ACE_HAS_IPV6)
27 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
28 const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
29 const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
30 const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
31 #endif /* ACE_VXWORKS <= 0x670 && __RTP__ && ACE_HAS_IPV6 */
33 #if defined (ACE_WIN32)
34 # include "ace/OS_NS_stdio.h"
35 #endif
37 #if defined (ACE_HAS_IPV6)
39 // These defines support a generic usage based on
40 // the various SIGCF*IF ioctl implementations
42 # if defined (SIOCGLIFCONF)
43 # define SIOCGIFCONF_CMD SIOCGLIFCONF
44 # define IFREQ lifreq
45 # define IFCONF lifconf
46 # define IFC_REQ lifc_req
47 # define IFC_LEN lifc_len
48 # define IFC_BUF lifc_buf
49 # define IFR_ADDR lifr_addr
50 # define IFR_NAME lifr_name
51 # define IFR_FLAGS lifr_flags
52 # define SETFAMILY
53 # define IFC_FAMILY lifc_family
54 # define IFC_FLAGS lifc_flags
55 # define SA_FAMILY ss_family
56 # else
57 # define SIOCGIFCONF_CMD SIOCGIFCONF
58 # define IFREQ ifreq
59 # define IFCONF ifconf
60 # define IFC_REQ ifc_req
61 # define IFC_LEN ifc_len
62 # define IFC_BUF ifc_buf
63 # define IFR_ADDR ifr_addr
64 # define IFR_NAME ifr_name
65 # define IFR_FLAGS ifr_flags
66 # undef SETFAMILY
67 # define SA_FAMILY sa_family
68 # endif /* SIOCGLIFCONF */
70 # if defined (ACE_HAS_THREADS)
71 # include "ace/Object_Manager.h"
72 # endif /* ACE_HAS_THREADS */
74 namespace
76 // private:
77 // Used internally so not exported.
79 // Does this box have ipv4 turned on?
80 int ace_ipv4_enabled = -1;
82 // Does this box have ipv6 turned on?
83 int ace_ipv6_enabled = -1;
85 #else /* ACE_HAS_IPV6 */
86 # define SIOCGIFCONF_CMD SIOCGIFCONF
87 # define IFREQ ifreq
88 # define IFCONF ifconf
89 # define IFC_REQ ifc_req
90 # define IFC_LEN ifc_len
91 # define IFC_BUF ifc_buf
92 # define IFR_ADDR ifr_addr
93 # define IFR_NAME ifr_name
94 # define IFR_FLAGS ifr_flags
95 # undef SETFAMILY
96 # define SA_FAMILY sa_family
97 #endif /* ACE_HAS_IPV6 */
99 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
101 // Bind socket to an unused port.
104 ACE::bind_port (ACE_HANDLE handle, ACE_UINT32 ip_addr, int address_family)
106 ACE_TRACE ("ACE::bind_port");
108 ACE_INET_Addr addr;
110 #if defined (ACE_HAS_IPV6)
111 if (address_family != PF_INET6)
112 // What do we do if it is PF_"INET6? Since it's 4 bytes, it must be an
113 // IPV4 address. Is there a difference? Why is this test done? dhinton
114 #else /* ACE_HAS_IPV6 */
115 ACE_UNUSED_ARG (address_family);
116 #endif /* !ACE_HAS_IPV6 */
117 addr = ACE_INET_Addr ((u_short)0, ip_addr);
118 #if defined (ACE_HAS_IPV6)
119 else if (ip_addr != INADDR_ANY)
120 // address_family == PF_INET6 and a non default IP address means to bind
121 // to the IPv4-mapped IPv6 address
122 addr.set ((u_short)0, ip_addr, 1, 1);
123 #endif /* ACE_HAS_IPV6 */
125 // The OS kernel should select a free port for us.
126 return ACE_OS::bind (handle,
127 (sockaddr*)addr.get_addr(),
128 addr.get_size());
132 ACE::get_bcast_addr (ACE_UINT32 &bcast_addr,
133 const ACE_TCHAR *host_name,
134 ACE_UINT32 host_addr,
135 ACE_HANDLE handle)
137 ACE_TRACE ("ACE::get_bcast_addr");
139 #if defined (ACE_LACKS_GET_BCAST_ADDR)
140 ACE_UNUSED_ARG (bcast_addr);
141 ACE_UNUSED_ARG (host_name);
142 ACE_UNUSED_ARG (host_addr);
143 ACE_UNUSED_ARG (handle);
144 ACE_NOTSUP_RETURN (-1);
145 #elif !defined(ACE_WIN32)
146 ACE_HANDLE s = handle;
148 if (s == ACE_INVALID_HANDLE)
149 s = ACE_OS::socket (AF_INET, SOCK_STREAM, 0);
151 if (s == ACE_INVALID_HANDLE)
152 ACELIB_ERROR_RETURN ((LM_ERROR,
153 ACE_TEXT ("%p\n"),
154 ACE_TEXT ("ACE_OS::socket")),
155 -1);
157 struct ifconf ifc;
158 char buf[BUFSIZ];
160 ifc.ifc_len = sizeof buf;
161 ifc.ifc_buf = buf;
163 // Get interface structure and initialize the addresses using UNIX
164 // techniques
165 if (ACE_OS::ioctl (s, SIOCGIFCONF_CMD, (char *) &ifc) == -1)
166 ACELIB_ERROR_RETURN ((LM_ERROR,
167 ACE_TEXT ("%p\n"),
168 ACE_TEXT ("ACE::get_bcast_addr:")
169 ACE_TEXT ("ioctl (get interface configuration)")),
170 -1);
172 struct ifreq *ifr = ifc.ifc_req;
174 struct sockaddr_in ip_addr;
176 // Get host ip address if necessary.
177 if (host_name)
179 hostent *hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR (host_name));
181 if (hp == 0)
182 return -1;
183 else
184 ACE_OS::memcpy ((char *) &ip_addr.sin_addr.s_addr,
185 # ifdef ACE_HOSTENT_H_ADDR
186 (char *) hp->ACE_HOSTENT_H_ADDR,
187 # else
188 (char *) hp->h_addr,
189 # endif
190 hp->h_length);
192 else
194 ACE_OS::memset ((void *) &ip_addr, 0, sizeof ip_addr);
195 ACE_OS::memcpy ((void *) &ip_addr.sin_addr,
196 (void*) &host_addr,
197 sizeof ip_addr.sin_addr);
200 #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
201 for (int n = ifc.ifc_len / sizeof (struct ifreq) ; n > 0;
202 n--, ifr++)
203 #else
204 // see mk_broadcast@SOCK_Dgram_Bcast.cpp
205 for (int nbytes = ifc.ifc_len; nbytes >= (int) sizeof (struct ifreq) &&
206 ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
207 (nbytes >= (int) sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len) : 1);
208 ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
209 (nbytes -= sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len,
210 ifr = (struct ifreq *)
211 ((caddr_t) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) :
212 (nbytes -= sizeof (struct ifreq), ifr++)))
213 #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
215 struct sockaddr_in if_addr;
217 // Compare host ip address with interface ip address.
218 ACE_OS::memcpy (&if_addr,
219 &ifr->ifr_addr,
220 sizeof if_addr);
222 if (ip_addr.sin_addr.s_addr != if_addr.sin_addr.s_addr)
223 continue;
225 if (ifr->ifr_addr.sa_family != AF_INET)
227 ACELIB_ERROR ((LM_ERROR,
228 ACE_TEXT ("%p\n"),
229 ACE_TEXT ("ACE::get_bcast_addr:")
230 ACE_TEXT ("Not AF_INET")));
231 continue;
234 struct ifreq flags = *ifr;
235 struct ifreq if_req = *ifr;
237 if (ACE_OS::ioctl (s, SIOCGIFFLAGS, (char *) &flags) == -1)
239 ACELIB_ERROR ((LM_ERROR,
240 ACE_TEXT ("%p\n"),
241 ACE_TEXT ("ACE::get_bcast_addr:")
242 ACE_TEXT (" ioctl (get interface flags)")));
243 continue;
246 if (ACE_BIT_DISABLED (flags.ifr_flags, IFF_UP))
248 ACELIB_ERROR ((LM_ERROR,
249 ACE_TEXT ("%p\n"),
250 ACE_TEXT ("ACE::get_bcast_addr:")
251 ACE_TEXT ("Network interface is not up")));
252 continue;
255 if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_LOOPBACK))
256 continue;
258 if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_BROADCAST))
260 if (ACE_OS::ioctl (s,
261 SIOCGIFBRDADDR,
262 (char *) &if_req) == -1)
263 ACELIB_ERROR ((LM_ERROR,
264 ACE_TEXT ("%p\n"),
265 ACE_TEXT ("ACE::get_bcast_addr:")
266 ACE_TEXT ("ioctl (get broadaddr)")));
267 else
269 ACE_OS::memcpy (&ip_addr,
270 &if_req.ifr_broadaddr,
271 sizeof if_req.ifr_broadaddr);
273 ACE_OS::memcpy ((void *) &host_addr,
274 (void *) &ip_addr.sin_addr,
275 sizeof host_addr);
277 if (handle == ACE_INVALID_HANDLE)
278 ACE_OS::close (s);
280 bcast_addr = host_addr;
281 return 0;
284 else
285 ACELIB_ERROR ((LM_ERROR,
286 ACE_TEXT ("%p\n"),
287 ACE_TEXT ("ACE::get_bcast_addr:")
288 ACE_TEXT ("Broadcast is not enabled for this interface.")));
290 if (handle == ACE_INVALID_HANDLE)
291 ACE_OS::close (s);
293 bcast_addr = host_addr;
294 return 0;
297 return 0;
298 #else
299 ACE_UNUSED_ARG (handle);
300 ACE_UNUSED_ARG (host_addr);
301 ACE_UNUSED_ARG (host_name);
302 bcast_addr = (ACE_UINT32 (INADDR_BROADCAST));
303 return 0;
304 #endif /* !ACE_WIN32 */
308 ACE::get_fqdn (ACE_INET_Addr const & addr,
309 char hostname[],
310 size_t len)
312 #ifndef ACE_LACKS_GETNAMEINFO
314 const socklen_t addr_size =
315 # ifdef ACE_HAS_IPV6
316 (addr.get_type () == PF_INET6) ? sizeof (sockaddr_in6) :
317 # endif
318 sizeof (sockaddr_in);
320 if (ACE_OS::getnameinfo ((const sockaddr *) addr.get_addr (),
321 addr_size, hostname,
322 static_cast<ACE_SOCKET_LEN> (len),
323 0, 0, NI_NAMEREQD) != 0)
324 return -1;
326 if (ACE::debug ())
327 ACELIB_DEBUG ((LM_DEBUG,
328 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
329 ACE_TEXT ("canonical host name is %C\n"),
330 hostname));
332 return 0;
333 #else // below, ACE_LACKS_GETNAMEINFO
334 int h_error; // Not the same as errno!
335 hostent hentry;
336 ACE_HOSTENT_DATA buf;
338 char * ip_addr = 0;
339 int ip_addr_size = 0;
340 if (addr.get_type () == AF_INET)
342 sockaddr_in * const sock_addr =
343 reinterpret_cast<sockaddr_in *> (addr.get_addr ());
344 ip_addr_size = sizeof sock_addr->sin_addr;
345 ip_addr = (char*) &sock_addr->sin_addr;
347 # ifdef ACE_HAS_IPV6
348 else
350 sockaddr_in6 * sock_addr =
351 reinterpret_cast<sockaddr_in6 *> (addr.get_addr ());
353 ip_addr_size = sizeof sock_addr->sin6_addr;
354 ip_addr = (char*) &sock_addr->sin6_addr;
356 # endif /* ACE_HAS_IPV6 */
358 // get the host entry for the address in question
359 hostent * const hp = ACE_OS::gethostbyaddr_r (ip_addr,
360 ip_addr_size,
361 addr.get_type (),
362 &hentry,
363 buf,
364 &h_error);
366 // if it's not found in the host file or the DNS datase, there is nothing
367 // much we can do. embed the IP address
368 if (hp == 0 || hp->h_name == 0)
369 return -1;
371 if (ACE::debug())
372 ACELIB_DEBUG ((LM_DEBUG,
373 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
374 ACE_TEXT ("canonical host name is %C\n"),
375 hp->h_name));
377 // check if the canonical name is the FQDN
378 if (!ACE_OS::strchr(hp->h_name, '.'))
380 // list of address
381 char** p;
382 // list of aliases
383 char** q;
385 // for every address and for every alias within the address, check and
386 // see if we can locate a FQDN
387 for (p = hp->h_addr_list; *p != 0; ++p)
389 for (q = hp->h_aliases; *q != 0; ++q)
391 if (ACE_OS::strchr(*q, '.'))
393 // we got an FQDN from an alias. use this
394 if (ACE_OS::strlen (*q) >= len)
395 // the hostname is too huge to fit into a
396 // buffer of size MAXHOSTNAMELEN
397 // should we check other aliases as well
398 // before bailing out prematurely?
399 // for right now, let's do it. this (short name)
400 // is atleast better than embedding the IP
401 // address in the profile
402 continue;
404 if (ACE::debug ())
405 ACELIB_DEBUG ((LM_DEBUG,
406 ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ")
407 ACE_TEXT ("found fqdn within alias as %C\n"),
408 *q));
409 ACE_OS::strcpy (hostname, *q);
411 return 0;
417 // The canonical name may be an FQDN when we reach here.
418 // Alternatively, the canonical name (a non FQDN) may be the best
419 // we can do.
420 if (ACE_OS::strlen (hp->h_name) >= len)
422 // The hostname is too large to fit into a buffer of size
423 // MAXHOSTNAMELEN.
424 return -2;
426 else
428 ACE_OS::strcpy (hostname, hp->h_name);
431 return 0;
432 #endif /* ACE_LACKS_GETNAMEINFO */
435 #if defined (ACE_WIN32)
437 static int
438 get_ip_interfaces_win32 (size_t &count,
439 ACE_INET_Addr *&addrs)
441 int i, n_interfaces, status;
443 INTERFACE_INFO info[64];
444 SOCKET sock;
446 // Get an (overlapped) DGRAM socket to test with
447 sock = socket (AF_INET, SOCK_DGRAM, 0);
448 if (sock == INVALID_SOCKET)
449 return -1;
451 DWORD bytes;
452 status = WSAIoctl(sock,
453 SIO_GET_INTERFACE_LIST,
456 info,
457 sizeof(info),
458 &bytes,
461 closesocket (sock);
462 if (status == SOCKET_ERROR)
463 return -1;
465 n_interfaces = bytes / sizeof(INTERFACE_INFO);
467 // SIO_GET_INTERFACE_LIST does not work for IPv6
468 // Instead recent versions of Winsock2 add the new opcode
469 // SIO_ADDRESS_LIST_QUERY.
470 // If this is not available forget about IPv6 local interfaces:-/
471 int n_v6_interfaces = 0;
473 # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY)
475 LPSOCKET_ADDRESS_LIST v6info;
476 char *buffer;
477 DWORD buflen = sizeof (SOCKET_ADDRESS_LIST) + (63 * sizeof (SOCKET_ADDRESS));
478 ACE_NEW_RETURN (buffer,
479 char[buflen],
480 -1);
481 v6info = reinterpret_cast<LPSOCKET_ADDRESS_LIST> (buffer);
483 // Get an (overlapped) DGRAM socket to test with.
484 // If it fails only return IPv4 interfaces.
485 sock = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
486 if (sock != INVALID_SOCKET)
488 status = WSAIoctl(sock,
489 SIO_ADDRESS_LIST_QUERY,
492 v6info,
493 buflen,
494 &bytes,
497 closesocket (sock);
498 if (status != SOCKET_ERROR)
499 n_v6_interfaces = v6info->iAddressCount;
501 # endif /* ACE_HAS_IPV6 */
503 ACE_NEW_RETURN (addrs,
504 ACE_INET_Addr[n_interfaces + n_v6_interfaces],
505 -1);
507 // Now go through the list and transfer the good ones to the list of
508 // because they're down or don't have an IP address.
509 for (count = 0, i = 0; i < n_interfaces; ++i)
511 LPINTERFACE_INFO lpii;
512 struct sockaddr_in *addrp = 0;
514 lpii = &info[i];
515 if (!(lpii->iiFlags & IFF_UP))
516 continue;
518 // We assume IPv4 addresses here
519 addrp = reinterpret_cast<struct sockaddr_in *> (&lpii->iiAddress.AddressIn);
520 if (addrp->sin_addr.s_addr == INADDR_ANY)
521 continue;
523 // Set the address for the caller.
524 addrs[count].set(addrp, sizeof(sockaddr_in));
525 ++count;
528 # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY)
529 // Now go through the list and transfer the good ones to the list of
530 // because they're down or don't have an IP address.
531 for (i = 0; i < n_v6_interfaces; i++)
533 struct sockaddr_in6 *addr6p;
535 if (v6info->Address[i].lpSockaddr->sa_family != AF_INET6)
536 continue;
538 addr6p = reinterpret_cast<struct sockaddr_in6 *> (v6info->Address[i].lpSockaddr);
539 if (IN6_IS_ADDR_UNSPECIFIED(&addr6p->sin6_addr)) // IN6ADDR_ANY?
540 continue;
542 // Set the address for the caller.
543 addrs[count].set(reinterpret_cast<struct sockaddr_in *> (addr6p), sizeof(sockaddr_in6));
544 ++count;
547 delete [] buffer; // Clean up
548 # endif /* ACE_HAS_IPV6 */
550 if (count == 0)
552 delete [] addrs;
553 addrs = 0;
556 return 0;
559 #elif defined (ACE_HAS_GETIFADDRS)
560 static int
561 get_ip_interfaces_getifaddrs (size_t &count,
562 ACE_INET_Addr *&addrs)
564 // Take advantage of the BSD getifaddrs function that simplifies
565 // access to connected interfaces.
566 struct ifaddrs *ifap = 0;
567 struct ifaddrs *p_if = 0;
569 if (::getifaddrs (&ifap) != 0)
570 return -1;
572 // Count number of interfaces.
573 size_t num_ifs = 0;
574 for (p_if = ifap; p_if != 0; p_if = p_if->ifa_next)
575 ++num_ifs;
577 // Now create and initialize output array.
578 ACE_NEW_RETURN (addrs,
579 ACE_INET_Addr[num_ifs],
580 -1); // caller must free
582 // Pull the address out of each INET interface. Not every interface
583 // is for IP, so be careful to count properly. When setting the
584 // INET_Addr, note that the 3rd arg (0) says to leave the byte order
585 // (already in net byte order from the interface structure) as is.
586 count = 0;
588 for (p_if = ifap;
589 p_if != 0;
590 p_if = p_if->ifa_next)
592 if (p_if->ifa_addr == 0)
593 continue;
595 // Check to see if it's up.
596 if ((p_if->ifa_flags & IFF_UP) != IFF_UP)
597 continue;
599 if (p_if->ifa_addr->sa_family == AF_INET)
601 struct sockaddr_in *addr =
602 reinterpret_cast<sockaddr_in *> (p_if->ifa_addr);
604 // Sometimes the kernel returns 0.0.0.0 as the interface
605 // address, skip those...
606 if (addr->sin_addr.s_addr != INADDR_ANY)
608 addrs[count].set ((u_short) 0,
609 addr->sin_addr.s_addr,
611 ++count;
614 # if defined (ACE_HAS_IPV6)
615 else if (p_if->ifa_addr->sa_family == AF_INET6)
617 struct sockaddr_in6 *addr =
618 reinterpret_cast<sockaddr_in6 *> (p_if->ifa_addr);
620 // Skip the ANY address
621 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr))
623 addrs[count].set(reinterpret_cast<struct sockaddr_in *> (addr),
624 sizeof(sockaddr_in6));
625 ++count;
628 # endif /* ACE_HAS_IPV6 */
631 ::freeifaddrs (ifap);
633 return 0;
635 #endif // ACE_WIN32 || ACE_HAS_GETIFADDRS
638 // return an array of all configured IP interfaces on this host, count
639 // rc = 0 on success (count == number of interfaces else -1 caller is
640 // responsible for calling delete [] on parray
643 ACE::get_ip_interfaces (size_t &count, ACE_INET_Addr *&addrs)
645 ACE_TRACE ("ACE::get_ip_interfaces");
647 count = 0;
648 addrs = 0;
650 #if defined (ACE_WIN32)
651 return get_ip_interfaces_win32 (count, addrs);
652 #elif defined (ACE_HAS_GETIFADDRS)
653 return get_ip_interfaces_getifaddrs (count, addrs);
654 #elif (defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS))) && !defined (ACE_LACKS_NETWORKING)
655 // COMMON (SVR4 and BSD) UNIX CODE
657 // Call specific routine as necessary.
658 ACE_HANDLE handle = ACE::get_handle();
660 if (handle == ACE_INVALID_HANDLE)
661 ACELIB_ERROR_RETURN ((LM_ERROR,
662 ACE_TEXT ("%p\n"),
663 ACE_TEXT ("ACE::get_ip_interfaces:open")),
664 -1);
666 size_t num_ifs = 0;
668 if (ACE::count_interfaces (handle, num_ifs))
670 ACE_OS::close (handle);
671 return -1;
674 // ioctl likes to have an extra ifreq structure to mark the end of
675 // what it returned, so increase the num_ifs by one.
676 ++num_ifs;
678 struct IFREQ *ifs = 0;
679 ACE_NEW_RETURN (ifs,
680 struct IFREQ[num_ifs],
681 -1);
682 ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct IFREQ));
684 ACE_Auto_Array_Ptr<struct IFREQ> p_ifs (ifs);
686 if (p_ifs.get() == 0)
688 ACE_OS::close (handle);
689 errno = ENOMEM;
690 return -1;
693 struct IFCONF ifcfg;
694 ACE_OS::memset (&ifcfg, 0, sizeof (struct IFCONF));
696 # ifdef SETFAMILY
697 ifcfg.IFC_FAMILY = AF_UNSPEC; // request all families be returned
698 ifcfg.IFC_FLAGS = 0;
699 # endif
701 ifcfg.IFC_REQ = p_ifs.get ();
702 ifcfg.IFC_LEN = num_ifs * sizeof (struct IFREQ);
704 if (ACE_OS::ioctl (handle,
705 SIOCGIFCONF_CMD,
706 (caddr_t) &ifcfg) == -1)
708 ACE_OS::close (handle);
709 ACELIB_ERROR_RETURN ((LM_ERROR,
710 ACE_TEXT ("%p\n"),
711 ACE_TEXT ("ACE::get_ip_interfaces:")
712 ACE_TEXT ("ioctl - SIOCGIFCONF failed")),
713 -1);
716 ACE_OS::close (handle);
718 // Now create and initialize output array.
720 ACE_NEW_RETURN (addrs,
721 ACE_INET_Addr[num_ifs],
722 -1); // caller must free
724 struct IFREQ *pcur = p_ifs.get ();
725 size_t num_ifs_found = ifcfg.IFC_LEN / sizeof (struct IFREQ); // get the number of returned ifs
727 // Pull the address out of each INET interface. Not every interface
728 // is for IP, so be careful to count properly. When setting the
729 // INET_Addr, note that the 3rd arg (0) says to leave the byte order
730 // (already in net byte order from the interface structure) as is.
731 count = 0;
733 for (size_t i = 0;
734 i < num_ifs_found;
735 i++)
737 if (pcur->IFR_ADDR.SA_FAMILY == AF_INET
738 # if defined (ACE_HAS_IPV6)
739 || pcur->IFR_ADDR.SA_FAMILY == AF_INET6
740 # endif
744 struct sockaddr_in *addr =
745 reinterpret_cast<sockaddr_in *> (&pcur->IFR_ADDR);
747 // Sometimes the kernel returns 0.0.0.0 as an IPv4 interface
748 // address; skip those...
749 if (addr->sin_addr.s_addr != 0
750 # if defined (ACE_HAS_IPV6)
751 || (addr->sin_family == AF_INET6 &&
752 !IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast<sockaddr_in6 *>(addr)->sin6_addr))
753 # endif
756 int addrlen = static_cast<int> (sizeof (struct sockaddr_in));
757 # if defined (ACE_HAS_IPV6)
758 if (addr->sin_family == AF_INET6)
759 addrlen = static_cast<int> (sizeof (struct sockaddr_in6));
760 # endif
761 addrs[count].set (addr, addrlen);
762 ++count;
766 #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
767 ++pcur;
768 #else
769 if (pcur->ifr_addr.sa_len <= sizeof (struct sockaddr))
771 ++pcur;
773 else
775 pcur = (struct ifreq *)
776 (pcur->ifr_addr.sa_len + (caddr_t) &pcur->ifr_addr);
778 #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
781 # if defined (ACE_HAS_IPV6) && !defined (ACE_LACKS_FSCANF)
782 // Retrieve IPv6 local interfaces by scanning /proc/net/if_inet6 if
783 // it exists. If we cannot open it then ignore possible IPv6
784 // interfaces, we did our best;-)
785 FILE* fp = 0;
786 char addr_p[8][5];
787 char s_ipaddr[64];
788 int scopeid;
789 struct addrinfo hints, *res0;
790 int error;
792 ACE_OS::memset (&hints, 0, sizeof (hints));
793 hints.ai_flags = AI_NUMERICHOST;
794 hints.ai_family = AF_INET6;
796 if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0)
798 while (fscanf (fp,
799 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*8s\n",
800 addr_p[0], addr_p[1], addr_p[2], addr_p[3],
801 addr_p[4], addr_p[5], addr_p[6], addr_p[7], &scopeid) != EOF)
803 // Format the address intoa proper IPv6 decimal address specification and
804 // resolve the resulting text using getaddrinfo().
806 const char* ip_fmt = "%s:%s:%s:%s:%s:%s:%s:%s%%%d";
807 ACE_OS::snprintf (s_ipaddr, 64, ip_fmt,
808 addr_p[0], addr_p[1], addr_p[2], addr_p[3],
809 addr_p[4], addr_p[5], addr_p[6], addr_p[7],
810 scopeid);
812 error = ACE_OS::getaddrinfo (s_ipaddr, 0, &hints, &res0);
813 if (error)
814 continue;
816 if (res0->ai_family == AF_INET6 &&
817 !IN6_IS_ADDR_UNSPECIFIED (&reinterpret_cast<sockaddr_in6 *> (res0->ai_addr)->sin6_addr))
819 addrs[count].set(reinterpret_cast<sockaddr_in *> (res0->ai_addr), res0->ai_addrlen);
820 ++count;
822 ACE_OS::freeaddrinfo (res0);
824 ACE_OS::fclose (fp);
826 # endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */
828 return 0;
829 #else
830 ACE_UNUSED_ARG (count);
831 ACE_UNUSED_ARG (addrs);
832 ACE_NOTSUP_RETURN (-1); // no implementation
833 #endif /* ACE_WIN32 */
836 // Helper routine for get_ip_interfaces, differs by UNIX platform so
837 // put into own subroutine. perform some ioctls to retrieve ifconf
838 // list of ifreq structs.
841 ACE::count_interfaces (ACE_HANDLE handle, size_t &how_many)
843 #if defined (SIOCGIFNUM)
844 # if defined (SIOCGLIFNUM)
845 int cmd = SIOCGLIFNUM;
846 struct lifnum if_num = {AF_UNSPEC,0,0};
847 # else
848 int cmd = SIOCGIFNUM;
849 int if_num = 0;
850 # endif /* SIOCGLIFNUM */
851 if (ACE_OS::ioctl (handle, cmd, (caddr_t)&if_num) == -1)
852 ACELIB_ERROR_RETURN ((LM_ERROR,
853 ACE_TEXT ("%p\n"),
854 ACE_TEXT ("ACE::count_interfaces:")
855 ACE_TEXT ("ioctl - SIOCGLIFNUM failed")),
856 -1);
857 # if defined (SIOCGLIFNUM)
858 how_many = if_num.lifn_count;
859 # else
860 how_many = if_num;
861 # endif /* SIOCGLIFNUM */
862 return 0;
864 #elif (defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS))) && !defined (ACE_LACKS_NETWORKING)
865 // Note: DEC CXX doesn't define "unix". BSD compatible OS: HP UX,
866 // SunOS 4.x perform some ioctls to retrieve ifconf list of
867 // ifreq structs no SIOCGIFNUM on SunOS 4.x, so use guess and scan
868 // algorithm
870 // Probably hard to put this many ifs in a unix box..
871 int const MAX_INTERFACES = 50;
873 // HACK - set to an unreasonable number
874 int const num_ifs = MAX_INTERFACES;
876 struct ifconf ifcfg;
877 size_t ifreq_size = num_ifs * sizeof (struct ifreq);
878 struct ifreq *p_ifs;
880 #if defined (ACE_HAS_ALLOC_HOOKS)
881 p_ifs = (struct IFREQ *)ACE_Allocator::instance()->malloc (ifreq_size);
882 #else
883 p_ifs = (struct ifreq *) ACE_OS::malloc (ifreq_size);
884 #endif /* ACE_HAS_ALLOC_HOOKS */
886 if (!p_ifs)
888 errno = ENOMEM;
889 return -1;
892 ACE_OS::memset (p_ifs, 0, ifreq_size);
893 ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf));
895 ifcfg.ifc_req = p_ifs;
896 ifcfg.ifc_len = ifreq_size;
898 if (ACE_OS::ioctl (handle,
899 SIOCGIFCONF_CMD,
900 (caddr_t) &ifcfg) == -1)
902 #if defined (ACE_HAS_ALLOC_HOOKS)
903 ACE_Allocator::instance()->free (ifcfg.ifc_req);
904 #else
905 ACE_OS::free (ifcfg.ifc_req);
906 #endif /* ACE_HAS_ALLOC_HOOKS */
908 ACELIB_ERROR_RETURN ((LM_ERROR,
909 ACE_TEXT ("%p\n"),
910 ACE_TEXT ("ACE::count_interfaces:")
911 ACE_TEXT ("ioctl - SIOCGIFCONF failed")),
912 -1);
915 int if_count = 0;
916 int i = 0;
918 // get if address out of ifreq buffers. ioctl puts a blank-named
919 // interface to mark the end of the returned interfaces.
920 for (i = 0;
921 i < num_ifs;
922 i++)
924 /* In OpenBSD, the length of the list is returned. */
925 ifcfg.ifc_len -= sizeof (struct ifreq);
926 if (ifcfg.ifc_len < 0)
927 break;
929 ++if_count;
930 # if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__)
931 ++p_ifs;
932 # else
933 if (p_ifs->ifr_addr.sa_len <= sizeof (struct sockaddr))
935 ++p_ifs;
937 else
939 p_ifs = (struct ifreq *)
940 (p_ifs->ifr_addr.sa_len + (caddr_t) &p_ifs->ifr_addr);
942 # endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */
945 #if defined (ACE_HAS_ALLOC_HOOKS)
946 ACE_Allocator::instance()->free (ifcfg.ifc_req);
947 #else
948 ACE_OS::free (ifcfg.ifc_req);
949 #endif /* ACE_HAS_ALLOC_HOOKS */
951 # if defined (ACE_HAS_IPV6)
952 FILE* fp = 0;
954 if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0)
956 // Scan the lines according to the expected format but don't really read any input
957 while (fscanf (fp, "%*32s %*02x %*02x %*02x %*02x %*8s\n") != EOF)
959 ++if_count;
961 ACE_OS::fclose (fp);
963 # endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */
965 how_many = if_count;
966 return 0;
967 #else
968 ACE_UNUSED_ARG (handle);
969 ACE_UNUSED_ARG (how_many);
970 ACE_NOTSUP_RETURN (-1); // no implementation
971 #endif /* sparc && SIOCGIFNUM */
974 // Routine to return a handle from which ioctl() requests can be made.
975 ACE_HANDLE
976 ACE::get_handle ()
978 ACE_HANDLE handle = ACE_INVALID_HANDLE;
979 #if defined (__unix) || defined (__unix__) || (defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600))
980 // Note: DEC CXX doesn't define "unix" BSD compatible OS: SunOS 4.x
981 handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0);
982 #endif /* __unux */
983 return handle;
986 #if defined (ACE_HAS_IPV6)
987 static int
988 ip_check (int &ipvn_enabled, int pf)
990 // We only get to this point if ipvn_enabled was -1 in the caller.
991 // Perform Double-Checked Locking Optimization.
992 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
993 *ACE_Static_Object_Lock::instance (), 0));
995 if (ipvn_enabled == -1)
997 #if defined (ACE_WIN32)
998 static bool recursing = false;
999 if (recursing) return 1;
1001 // as of the release of Windows 2008, even hosts that have IPv6 interfaces disabled
1002 // will still permit the creation of a PF_INET6 socket, thus rendering the socket
1003 // creation test inconsistent. The recommended solution is to get the list of
1004 // endpoint addresses and see if any match the desired family.
1005 ACE_INET_Addr *if_addrs = 0;
1006 size_t if_cnt = 0;
1008 // assume enabled to avoid recursion during interface lookup.
1009 recursing = true;
1010 ACE::get_ip_interfaces (if_cnt, if_addrs);
1011 recursing = false;
1013 bool found = false;
1014 for (size_t i = 0; !found && i < if_cnt; i++)
1016 found = (if_addrs[i].get_type () == pf);
1018 delete [] if_addrs;
1020 // If the list of interfaces is empty, we've tried too quickly. Assume enabled, but don't cache the result
1021 if (!if_cnt) return 1;
1023 ipvn_enabled = found ? 1 : 0;
1024 #else
1025 // Determine if the kernel has IPv6 support by attempting to
1026 // create a PF_INET6 socket and see if it fails.
1027 ACE_HANDLE const s = ACE_OS::socket (pf, SOCK_DGRAM, 0);
1028 if (s == ACE_INVALID_HANDLE)
1030 ipvn_enabled = 0;
1032 else
1034 ipvn_enabled = 1;
1035 ACE_OS::closesocket (s);
1037 #endif
1039 return ipvn_enabled;
1041 #endif /* ACE_HAS_IPV6 */
1043 bool
1044 ACE::ipv4_enabled ()
1046 #if defined (ACE_HAS_IPV6)
1047 return static_cast<bool> (ace_ipv4_enabled == -1 ?
1048 ::ip_check (ace_ipv4_enabled, PF_INET) :
1049 ace_ipv4_enabled);
1050 #else
1051 // Assume it's always enabled since ACE requires some version of
1052 // TCP/IP to exist.
1053 return true;
1054 #endif /* ACE_HAS_IPV6*/
1058 ACE::ipv6_enabled ()
1060 #if defined (ACE_HAS_IPV6)
1061 return ace_ipv6_enabled == -1 ?
1062 ::ip_check (ace_ipv6_enabled, PF_INET6) :
1063 ace_ipv6_enabled;
1064 #else /* ACE_HAS_IPV6 */
1065 return 0;
1066 #endif /* !ACE_HAS_IPV6 */
1069 ACE_END_VERSIONED_NAMESPACE_DECL