// $Id$ #include "ace/Sock_Connect.h" #include "ace/INET_Addr.h" #include "ace/Log_Msg.h" #include "ace/Handle_Set.h" #include "ace/Auto_Ptr.h" #include "ace/SString.h" #include "ace/OS_Memory.h" #include "ace/OS_NS_stdio.h" #include "ace/ACE.h" #if defined (sparc) # include "ace/OS_NS_fcntl.h" #endif // sparc #include "ace/OS_NS_stdlib.h" #include "ace/OS_NS_string.h" #include "ace/OS_NS_sys_socket.h" #include "ace/OS_NS_netdb.h" #include "ace/OS_NS_unistd.h" #include "ace/os_include/net/os_if.h" #if defined (ACE_HAS_IPV6) # include "ace/Guard_T.h" # include "ace/Recursive_Thread_Mutex.h" # if defined (_AIX) # include /**/ # endif /* _AIX */ #endif /* ACE_HAS_IPV6 */ # if defined (ACE_HAS_GETIFADDRS) # if defined (ACE_VXWORKS) # include /**/ # else # include /**/ # endif /*ACE_VXWORKS */ # endif /* ACE_HAS_GETIFADDRS */ #if defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600) #include /**/ #include /**/ #if defined (ACE_HAS_IPV6) #include /**/ extern "C" { extern struct in_ifaddr* in_ifaddr; extern LIST_HEAD(in_ifaddrhashhead, in_ifaddr) *in_ifaddrhashtbl; } #endif /* ACE_HAS_IPV6 */ #include "ace/OS_NS_stdio.h" #endif /* ACE_VXWORKS < 0x600 */ #if defined (ACE_VXWORKS) && ((ACE_VXWORKS == 0x630) || (ACE_VXWORKS == 0x640)) && defined (__RTP__) && defined (ACE_HAS_IPV6) const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT; const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; #endif /* ACE_VXWORKS == 0x630 && __RTP__ && ACE_HAS_IPV6 */ #if defined (ACE_HAS_WINCE) #include /**/ # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) // The following code is suggested by microsoft as a workaround to the fact // that on Windows CE, these constants are exported as function addresses // rather than simply values. # include /**/ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; # endif #endif // ACE_HAS_WINCE #if defined (ACE_WIN32) && defined (ACE_HAS_PHARLAP) # include "ace/OS_NS_stdio.h" #endif #if defined (ACE_HAS_IPV6) // These defines support a generic usage based on // the various SIGCF*IF ioctl implementations # if defined (SIOCGLIFCONF) # define SIOCGIFCONF_CMD SIOCGLIFCONF # if defined (__hpux) # define IFREQ if_laddrreq # define IFCONF if_laddrconf # define IFC_REQ iflc_req # define IFC_LEN iflc_len # define IFC_BUF iflc_buf # define IFR_ADDR iflr_addr # define IFR_NAME iflr_name # define IFR_FLAGS iflr_flags # undef SETFAMILY # define SA_FAMILY sa_family # else # define IFREQ lifreq # define IFCONF lifconf # define IFC_REQ lifc_req # define IFC_LEN lifc_len # define IFC_BUF lifc_buf # define IFR_ADDR lifr_addr # define IFR_NAME lifr_name # define IFR_FLAGS lifr_flags # define SETFAMILY # define IFC_FAMILY lifc_family # define IFC_FLAGS lifc_flags # define SA_FAMILY ss_family # endif # else # define SIOCGIFCONF_CMD SIOCGIFCONF # define IFREQ ifreq # define IFCONF ifconf # define IFC_REQ ifc_req # define IFC_LEN ifc_len # define IFC_BUF ifc_buf # define IFR_ADDR ifr_addr # define IFR_NAME ifr_name # define IFR_FLAGS ifr_flags # undef SETFAMILY # define SA_FAMILY sa_family # endif /* SIOCGLIFCONF */ # if defined (ACE_HAS_THREADS) # include "ace/Object_Manager.h" # endif /* ACE_HAS_THREADS */ namespace { // private: // Used internally so not exported. // Does this box have ipv4 turned on? int ace_ipv4_enabled = -1; // Does this box have ipv6 turned on? int ace_ipv6_enabled = -1; } #else /* ACE_HAS_IPV6 */ # define SIOCGIFCONF_CMD SIOCGIFCONF # define IFREQ ifreq # define IFCONF ifconf # define IFC_REQ ifc_req # define IFC_LEN ifc_len # define IFC_BUF ifc_buf # define IFR_ADDR ifr_addr # define IFR_NAME ifr_name # define IFR_FLAGS ifr_flags # undef SETFAMILY # define SA_FAMILY sa_family #endif /* ACE_HAS_IPV6 */ // This is a hack to work around a problem with Visual Age C++ 5 and 6 on AIX. // Without this, the compiler auto-instantiates the ACE_Auto_Array_Ptr for // ifreq (contained in this module) but only adds the #include for // and not the one for which is also needed. Although we // don't need the template defined here, it makes the compiler pull in // and the build runs clean. #if defined (AIX) && defined (__IBMCPP__) && (__IBMCPP__ >= 500) && (__IBMCPP__ < 700) static ACE_Auto_Array_Ptr force_compiler_to_include_socket_h; #endif /* AIX && __IBMCPP__ >= 500 */ ACE_RCSID (ace, Sock_Connect, "$Id$") ACE_BEGIN_VERSIONED_NAMESPACE_DECL // Bind socket to an unused port. int ACE::bind_port (ACE_HANDLE handle, ACE_UINT32 ip_addr, int address_family) { ACE_TRACE ("ACE::bind_port"); ACE_INET_Addr addr; #if defined (ACE_HAS_IPV6) if (address_family != PF_INET6) // What do we do if it is PF_"INET6? Since it's 4 bytes, it must be an // IPV4 address. Is there a difference? Why is this test done? dhinton #else /* ACE_HAS_IPV6 */ ACE_UNUSED_ARG (address_family); #endif /* !ACE_HAS_IPV6 */ addr = ACE_INET_Addr ((u_short)0, ip_addr); #if defined (ACE_HAS_IPV6) else if (ip_addr != INADDR_ANY) // address_family == PF_INET6 and a non default IP address means to bind // to the IPv4-mapped IPv6 address addr.set ((u_short)0, ip_addr, 1, 1); #endif /* ACE_HAS_IPV6 */ // The OS kernel should select a free port for us. return ACE_OS::bind (handle, (sockaddr*)addr.get_addr(), addr.get_size()); } int ACE::get_bcast_addr (ACE_UINT32 &bcast_addr, const ACE_TCHAR *host_name, ACE_UINT32 host_addr, ACE_HANDLE handle) { ACE_TRACE ("ACE::get_bcast_addr"); #if defined (ACE_LACKS_GET_BCAST_ADDR) ACE_UNUSED_ARG (bcast_addr); ACE_UNUSED_ARG (host_name); ACE_UNUSED_ARG (host_addr); ACE_UNUSED_ARG (handle); ACE_NOTSUP_RETURN (-1); #elif !defined(ACE_WIN32) && !defined(__INTERIX) ACE_HANDLE s = handle; if (s == ACE_INVALID_HANDLE) s = ACE_OS::socket (AF_INET, SOCK_STREAM, 0); if (s == ACE_INVALID_HANDLE) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_OS::socket")), -1); struct ifconf ifc; char buf[BUFSIZ]; ifc.ifc_len = sizeof buf; ifc.ifc_buf = buf; // Get interface structure and initialize the addresses using UNIX // techniques if (ACE_OS::ioctl (s, SIOCGIFCONF_CMD, (char *) &ifc) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT ("ioctl (get interface configuration)")), -1); struct ifreq *ifr = ifc.ifc_req; struct sockaddr_in ip_addr; // Get host ip address if necessary. if (host_name) { hostent *hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR (host_name)); if (hp == 0) return -1; else #if !defined(_UNICOS) ACE_OS::memcpy ((char *) &ip_addr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length); #else /* _UNICOS */ { ACE_UINT64 haddr; // a place to put the address char * haddrp = (char *) &haddr; // convert to char pointer ACE_OS::memcpy(haddrp,(char *) hp->h_addr,hp->h_length); ip_addr.sin_addr.s_addr = haddr; } #endif /* ! _UNICOS */ } else { ACE_OS::memset ((void *) &ip_addr, 0, sizeof ip_addr); #if !defined(_UNICOS) ACE_OS::memcpy ((void *) &ip_addr.sin_addr, (void*) &host_addr, sizeof ip_addr.sin_addr); #else /* _UNICOS */ ip_addr.sin_addr.s_addr = host_addr; // just copy to the bitfield #endif /* ! _UNICOS */ } #if !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) for (int n = ifc.ifc_len / sizeof (struct ifreq) ; n > 0; n--, ifr++) #else // see mk_broadcast@SOCK_Dgram_Bcast.cpp for (int nbytes = ifc.ifc_len; nbytes >= (int) sizeof (struct ifreq) && ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ? (nbytes >= (int) sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len) : 1); ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ? (nbytes -= sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len, ifr = (struct ifreq *) ((caddr_t) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) : (nbytes -= sizeof (struct ifreq), ifr++))) #endif /* !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) */ { struct sockaddr_in if_addr; // Compare host ip address with interface ip address. ACE_OS::memcpy (&if_addr, &ifr->ifr_addr, sizeof if_addr); if (ip_addr.sin_addr.s_addr != if_addr.sin_addr.s_addr) continue; if (ifr->ifr_addr.sa_family != AF_INET) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT ("Not AF_INET"))); continue; } struct ifreq flags = *ifr; struct ifreq if_req = *ifr; if (ACE_OS::ioctl (s, SIOCGIFFLAGS, (char *) &flags) == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT (" ioctl (get interface flags)"))); continue; } if (ACE_BIT_DISABLED (flags.ifr_flags, IFF_UP)) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT ("Network interface is not up"))); continue; } if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_LOOPBACK)) continue; if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_BROADCAST)) { if (ACE_OS::ioctl (s, SIOCGIFBRDADDR, (char *) &if_req) == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT ("ioctl (get broadaddr)"))); else { ACE_OS::memcpy (&ip_addr, &if_req.ifr_broadaddr, sizeof if_req.ifr_broadaddr); ACE_OS::memcpy ((void *) &host_addr, (void *) &ip_addr.sin_addr, sizeof host_addr); if (handle == ACE_INVALID_HANDLE) ACE_OS::close (s); bcast_addr = host_addr; return 0; } } else ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_bcast_addr:") ACE_TEXT ("Broadcast is not enable for this interface."))); if (handle == ACE_INVALID_HANDLE) ACE_OS::close (s); bcast_addr = host_addr; return 0; } return 0; #else ACE_UNUSED_ARG (handle); ACE_UNUSED_ARG (host_addr); ACE_UNUSED_ARG (host_name); bcast_addr = (ACE_UINT32 (INADDR_BROADCAST)); return 0; #endif /* !ACE_WIN32 && !__INTERIX */ } int ACE::get_fqdn (ACE_INET_Addr const & addr, char hostname[], size_t len) { int h_error; // Not the same as errno! hostent hentry; ACE_HOSTENT_DATA buf; char * ip_addr = 0; int ip_addr_size = 0; if (addr.get_type () == AF_INET) { sockaddr_in * const sock_addr = reinterpret_cast (addr.get_addr ()); ip_addr_size = sizeof sock_addr->sin_addr; ip_addr = (char*) &sock_addr->sin_addr; } #ifdef ACE_HAS_IPV6 else { sockaddr_in6 * sock_addr = reinterpret_cast (addr.get_addr ()); ip_addr_size = sizeof sock_addr->sin6_addr; ip_addr = (char*) &sock_addr->sin6_addr; } #endif /* ACE_HAS_IPV6 */ // get the host entry for the address in question hostent * const hp = ACE_OS::gethostbyaddr_r (ip_addr, ip_addr_size, addr.get_type (), &hentry, buf, &h_error); // if it's not found in the host file or the DNS datase, there is nothing // much we can do. embed the IP address if (hp == 0 || hp->h_name == 0) return -1; if (ACE::debug()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ") ACE_TEXT ("canonical host name is %C\n"), hp->h_name)); // check if the canonical name is the FQDN if (!ACE_OS::strchr(hp->h_name, '.')) { // list of address char** p; // list of aliases char** q; // for every address and for every alias within the address, check and // see if we can locate a FQDN for (p = hp->h_addr_list; *p != 0; ++p) { for (q = hp->h_aliases; *q != 0; ++q) { if (ACE_OS::strchr(*q, '.')) { // we got an FQDN from an alias. use this if (ACE_OS::strlen (*q) >= len) // the hostname is too huge to fit into a // buffer of size MAXHOSTNAMELEN // should we check other aliases as well // before bailing out prematurely? // for right now, let's do it. this (short name) // is atleast better than embedding the IP // address in the profile continue; if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ") ACE_TEXT ("found fqdn within alias as %C\n"), *q)); ACE_OS::strcpy (hostname, *q); return 0; } } } } // The canonical name may be an FQDN when we reach here. // Alternatively, the canonical name (a non FQDN) may be the best // we can do. if (ACE_OS::strlen (hp->h_name) >= len) { // The hostname is too large to fit into a buffer of size // MAXHOSTNAMELEN. return -2; } else { ACE_OS::strcpy (hostname, hp->h_name); } return 0; } #if defined (ACE_WIN32) static int get_ip_interfaces_win32 (size_t &count, ACE_INET_Addr *&addrs) { # if defined (ACE_HAS_WINCE) && defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) // moved the ACE_HAS_WINCE impl ahaid of ACE_HAS_WINSOCK2 because // WINCE in fact has winsock2, but doesn't properly support the // WSAIoctl for obtaining IPv6 address info. PIP_ADAPTER_ADDRESSES AdapterAddresses = 0; ULONG OutBufferLength = 0; ULONG RetVal = 0; unsigned char *octet_buffer = 0; RetVal = GetAdaptersAddresses(AF_UNSPEC, 0, 0, AdapterAddresses, &OutBufferLength); if (RetVal != ERROR_BUFFER_OVERFLOW) { return -1; } ACE_NEW_RETURN (octet_buffer, unsigned char[OutBufferLength],-1); AdapterAddresses = (IP_ADAPTER_ADDRESSES *)octet_buffer; RetVal = GetAdaptersAddresses(AF_UNSPEC, 0, 0, AdapterAddresses, &OutBufferLength); if (RetVal != NO_ERROR) { delete [] octet_buffer; return -1; } // If successful, output some information from the data we received PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; while (AdapterList) { if (AdapterList->OperStatus == IfOperStatusUp) { if (AdapterList->IfIndex != 0) ++count; if (AdapterList->Ipv6IfIndex != 0) ++count; } AdapterList = AdapterList->Next; } AdapterList = AdapterAddresses; ACE_NEW_RETURN (addrs, ACE_INET_Addr[count],-1); count = 0; for (AdapterList = AdapterAddresses; AdapterList != 0; AdapterList = AdapterList->Next) { if (AdapterList->OperStatus != IfOperStatusUp) continue; IP_ADAPTER_UNICAST_ADDRESS *uni = 0; if (AdapterList->IfIndex != 0) for (uni = AdapterList->FirstUnicastAddress; uni != 0; uni = uni->Next) { SOCKET_ADDRESS *sa_addr = &uni->Address; if (sa_addr->lpSockaddr->sa_family == AF_INET) { sockaddr_in *sin = (sockaddr_in*)sa_addr->lpSockaddr; addrs[count].set(sin,sa_addr->iSockaddrLength); ++count; break; } } if (AdapterList->Ipv6IfIndex != 0) { for (uni = AdapterList->FirstUnicastAddress; uni != 0; uni = uni->Next) { SOCKET_ADDRESS *sa_addr = &uni->Address; if (sa_addr->lpSockaddr->sa_family == AF_INET6) { sockaddr_in *sin = (sockaddr_in*)sa_addr->lpSockaddr; addrs[count].set(sin,sa_addr->iSockaddrLength); ++count; break; } } } } delete [] octet_buffer; return 0; # elif defined (ACE_HAS_PHARLAP) // PharLap ETS has its own kernel routines to rummage through the device // configs and extract the interface info, but only for Pharlap RT. # if !defined (ACE_HAS_PHARLAP_RT) ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_PHARLAP_RT */ // Locate all of the IP devices in the system, saving a DEVHANDLE // for each. Then allocate the ACE_INET_Addrs needed and fetch all // the IP addresses. To locate the devices, try the available // device name roots and increment the device number until the // kernel says there are no more of that type. const size_t ACE_MAX_ETS_DEVICES = 64; // Arbitrary, but should be enough. DEVHANDLE ip_dev[ACE_MAX_ETS_DEVICES]; EK_TCPIPCFG *devp = 0; size_t i, j; ACE_TCHAR dev_name[16]; count = 0; for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) { // Ethernet. ACE_OS::sprintf (dev_name, "ether%d", i); ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); if (ip_dev[count] == 0) break; } for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) { // SLIP. ACE_OS::sprintf (dev_name, "sl%d", i); ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); if (ip_dev[count] == 0) break; } for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) { // PPP. ACE_OS::sprintf (dev_name, "ppp%d", i); ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); if (ip_dev[count] == 0) break; } if (count > 0) ACE_NEW_RETURN (addrs, ACE_INET_Addr[count], -1); else addrs = 0; for (i = 0, j = 0; i < count; i++) { devp = EtsTCPGetDeviceCfg (ip_dev[i]); if (devp != 0) { addrs[j].set (0, devp->nwIPAddress, 0); // Already in net order. ++j; } // There's no call to close the DEVHANDLE. } count = j; if (count == 0 && addrs != 0) { delete [] addrs; addrs = 0; } return 0; # else // All non-CE, non-Pharlap Windows. Must support Winsock2. int i, n_interfaces, status; INTERFACE_INFO info[64]; SOCKET sock; // Get an (overlapped) DGRAM socket to test with sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return -1; DWORD bytes; status = WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, info, sizeof(info), &bytes, 0, 0); closesocket (sock); if (status == SOCKET_ERROR) return -1; n_interfaces = bytes / sizeof(INTERFACE_INFO); // SIO_GET_INTERFACE_LIST does not work for IPv6 // Instead recent versions of Winsock2 add the new opcode // SIO_ADDRESS_LIST_QUERY. // If this is not available forget about IPv6 local interfaces:-/ int n_v6_interfaces = 0; # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY) LPSOCKET_ADDRESS_LIST v6info; char *buffer; DWORD buflen = sizeof (SOCKET_ADDRESS_LIST) + (63 * sizeof (SOCKET_ADDRESS)); ACE_NEW_RETURN (buffer, char[buflen], -1); v6info = reinterpret_cast (buffer); // Get an (overlapped) DGRAM socket to test with. // If it fails only return IPv4 interfaces. sock = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (sock != INVALID_SOCKET) { status = WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, 0, 0, v6info, buflen, &bytes, 0, 0); closesocket (sock); if (status != SOCKET_ERROR) n_v6_interfaces = v6info->iAddressCount; } # endif /* ACE_HAS_IPV6 */ ACE_NEW_RETURN (addrs, ACE_INET_Addr[n_interfaces + n_v6_interfaces], -1); // Now go through the list and transfer the good ones to the list of // because they're down or don't have an IP address. for (count = 0, i = 0; i < n_interfaces; ++i) { LPINTERFACE_INFO lpii; struct sockaddr_in *addrp = 0; lpii = &info[i]; if (!(lpii->iiFlags & IFF_UP)) continue; // We assume IPv4 addresses here addrp = reinterpret_cast (&lpii->iiAddress.AddressIn); if (addrp->sin_addr.s_addr == INADDR_ANY) continue; // Set the address for the caller. addrs[count].set(addrp, sizeof(sockaddr_in)); ++count; } # if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY) // Now go through the list and transfer the good ones to the list of // because they're down or don't have an IP address. for (i = 0; i < n_v6_interfaces; i++) { struct sockaddr_in6 *addr6p; if (v6info->Address[i].lpSockaddr->sa_family != AF_INET6) continue; addr6p = reinterpret_cast (v6info->Address[i].lpSockaddr); if (IN6_IS_ADDR_UNSPECIFIED(&addr6p->sin6_addr)) // IN6ADDR_ANY? continue; // Set the address for the caller. addrs[count].set(reinterpret_cast (addr6p), sizeof(sockaddr_in6)); ++count; } delete [] buffer; // Clean up # endif /* ACE_HAS_IPV6 */ if (count == 0) { delete [] addrs; addrs = 0; } return 0; # endif /* ACE_HAS_WINCE */ } #elif defined (ACE_HAS_GETIFADDRS) static int get_ip_interfaces_getifaddrs (size_t &count, ACE_INET_Addr *&addrs) { // Take advantage of the BSD getifaddrs function that simplifies // access to connected interfaces. struct ifaddrs *ifap = 0; struct ifaddrs *p_if = 0; if (::getifaddrs (&ifap) != 0) return -1; // Count number of interfaces. size_t num_ifs = 0; for (p_if = ifap; p_if != 0; p_if = p_if->ifa_next) ++num_ifs; // Now create and initialize output array. ACE_NEW_RETURN (addrs, ACE_INET_Addr[num_ifs], -1); // caller must free // Pull the address out of each INET interface. Not every interface // is for IP, so be careful to count properly. When setting the // INET_Addr, note that the 3rd arg (0) says to leave the byte order // (already in net byte order from the interface structure) as is. count = 0; for (p_if = ifap; p_if != 0; p_if = p_if->ifa_next) { if (p_if->ifa_addr && p_if->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr = reinterpret_cast (p_if->ifa_addr); // Sometimes the kernel returns 0.0.0.0 as the interface // address, skip those... if (addr->sin_addr.s_addr != INADDR_ANY) { addrs[count].set ((u_short) 0, addr->sin_addr.s_addr, 0); ++count; } } # if defined (ACE_HAS_IPV6) else if (p_if->ifa_addr && p_if->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr = reinterpret_cast (p_if->ifa_addr); // Skip the ANY address if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) { addrs[count].set(reinterpret_cast (addr), sizeof(sockaddr_in6)); ++count; } } # endif /* ACE_HAS_IPV6 */ } ::freeifaddrs (ifap); return 0; } #elif defined (__hpux) static int get_ip_interfaces_hpux (size_t &count, ACE_INET_Addr *&addrs) { size_t num_ifs = 0; size_t num_ifs_found = 0; // Call specific routine as necessary. ACE_HANDLE handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0); ACE_HANDLE handle_ipv6 = ACE_INVALID_HANDLE; if (handle == ACE_INVALID_HANDLE) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces:open")), -1); int result = 0; int tmp_how_many = 0; result = ACE_OS::ioctl (handle, SIOCGIFNUM, (caddr_t) &tmp_how_many); if (result != -1) num_ifs = (size_t)tmp_how_many; # if defined (ACE_HAS_IPV6) tmp_how_many = 0; handle_ipv6 = ACE_OS::socket (PF_INET6, SOCK_DGRAM, 0); result = ACE_OS::ioctl (handle_ipv6, SIOCGLIFNUM, (caddr_t) &tmp_how_many); if (result != -1) num_ifs += (size_t)tmp_how_many; # endif if (num_ifs == 0) { ACE_OS::close (handle); ACE_OS::close (handle_ipv6); return -1; } // ioctl likes to have an extra IFREQ structure to mark the end of // what it returned, so increase the num_ifs by one. ++num_ifs; //HPUX requires two passes, First for IPv4, then for IPv6 struct ifreq *ifs = 0; ACE_NEW_RETURN (ifs, struct ifreq[num_ifs], -1); ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct ifreq)); ACE_Auto_Array_Ptr p_ifs (ifs); if (p_ifs.get() == 0) { ACE_OS::close (handle); ACE_OS::close (handle_ipv6); errno = ENOMEM; return -1; } struct ifconf ifcfg; ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf)); ifcfg.ifc_req = p_ifs.get (); ifcfg.ifc_len = num_ifs * sizeof (struct ifreq); if (ACE_OS::ioctl (handle, SIOCGIFCONF, (char *) &ifcfg) == -1) { ACE_OS::close (handle); ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces:") ACE_TEXT ("ioctl - SIOCGIFCONF failed")), -1); } ACE_OS::close (handle); // Now create and initialize output array. ACE_NEW_RETURN (addrs, ACE_INET_Addr[num_ifs], -1); // caller must free struct ifreq *pcur = p_ifs.get (); num_ifs_found = ifcfg.ifc_len / sizeof (struct ifreq); // get the number of returned ifs for (size_t i = 0; i < num_ifs_found; i++) { struct sockaddr_in *addr = reinterpret_cast (&pcur->ifr_addr); if (addr->sin_addr.s_addr != 0) { addrs[count].set ((u_short) 0, addr->sin_addr.s_addr, 0); ++count; } ++pcur; } # if defined (ACE_HAS_IPV6) if (handle_ipv6 != ACE_INVALID_HANDLE) { struct if_laddrreq *lifs = 0; ACE_NEW_RETURN (lifs, struct if_laddrreq[num_ifs], -1); ACE_OS::memset (lifs, 0, num_ifs * sizeof (struct if_laddrreq)); ACE_Auto_Array_Ptr p_lifs (lifs); if (p_lifs.get() == 0) { ACE_OS::close (handle); ACE_OS::close (handle_ipv6); errno = ENOMEM; return -1; } struct if_laddrconf lifcfg; ACE_OS::memset (&lifcfg, 0, sizeof (struct if_laddrconf)); lifcfg.iflc_req = p_lifs.get (); lifcfg.iflc_len = num_ifs * sizeof (struct if_laddrreq); if (ACE_OS::ioctl (handle_ipv6, SIOCGLIFCONF, (char *) &lifcfg) == -1) { ACE_OS::close (handle); ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces:") ACE_TEXT ("ioctl - SIOCGLIFCONF failed")), -1); } ACE_OS::close (handle_ipv6); struct if_laddrreq *plcur = p_lifs.get (); num_ifs_found = lifcfg.iflc_len / sizeof (struct if_laddrreq); for (size_t i = 0; i < num_ifs_found; i++) { struct sockaddr_in *addr = reinterpret_cast (&plcur->iflr_addr); if (!IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(addr)->sin6_addr)) { addrs[count].set(addr, sizeof(struct sockaddr_in6)); ++count; } ++plcur; } } # endif /* ACE_HAS_IPV6 */ return 0; } #elif defined (_AIX) static int get_ip_interfaces_aix (size_t &count, ACE_INET_Addr *&addrs) { ACE_HANDLE handle = ACE::get_handle(); size_t num_ifs = 0; struct ifconf ifc; if (handle == ACE_INVALID_HANDLE) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces_aix:")), -1); if (ACE_OS::ioctl (handle, SIOCGSIZIFCONF, (caddr_t)&ifc.ifc_len) == -1) { ACE_OS::close (handle); ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("get ifconf size")), -1); } ACE_NEW_RETURN (ifc.ifc_buf,char [ifc.ifc_len], -1); ACE_Auto_Array_Ptr safe_buf (ifc.ifc_buf); ACE_OS::memset (safe_buf.get(), 0, ifc.ifc_len); if (ACE_OS::ioctl(handle, SIOCGIFCONF, (caddr_t)&ifc) == -1) { ACE_OS::close (handle); ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("get ifconf")), -1); } ACE_OS::close (handle); char *buf_start = safe_buf.get(); char *buf_end = buf_start + ifc.ifc_len; num_ifs = 0; for (char *ptr = buf_start; ptr < buf_end; ) { struct ifreq *req = reinterpret_cast(ptr); ptr += IFNAMSIZ; ptr += req->ifr_addr.sa_len; if (req->ifr_addr.sa_family == AF_INET # if defined (ACE_HAS_IPV6) || req->ifr_addr.sa_family == AF_INET6 # endif ) ++num_ifs; } ACE_NEW_RETURN (addrs,ACE_INET_Addr[num_ifs], -1); for (char * ptr = buf_start; ptr < buf_end; ) { struct ifreq *req = reinterpret_cast(ptr); // skip the interface name ptr += IFNAMSIZ; if (req->ifr_addr.sa_family == AF_INET # if defined (ACE_HAS_IPV6) || req->ifr_addr.sa_family == AF_INET6 # endif ) { sockaddr_in *addr = (sockaddr_in*)&req->ifr_addr; addrs[count++].set(addr, addr->sin_len); } ptr += req->ifr_addr.sa_len; } return 0; } #elif defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600) && !defined (ACE_HAS_VXWORKS551_MEDUSA) int get_ip_interfaces_vxworks_lt600 (size_t &count, ACE_INET_Addr *&addrs) { count = 0; // Loop through each address structure # if defined (ACE_HAS_IPV6) && defined (TAILQ_ENTRY) # define ia_next ia_link.tqe_next # endif /* TAILQ_ENTRY */ for (struct in_ifaddr* ia = in_ifaddr; ia != 0; ia = ia->ia_next) { ++count; } // Now create and initialize output array. ACE_NEW_RETURN (addrs, ACE_INET_Addr[count], -1); // caller must free count = 0; for (struct in_ifaddr* ia = in_ifaddr; ia != 0; ia = ia->ia_next) { struct ifnet* ifp = ia->ia_ifa.ifa_ifp; if (ifp != 0) { // Get the current interface name char interface[64]; ACE_OS::sprintf(interface, "%s%d", ifp->if_name, ifp->if_unit); // Get the address for the current interface char address [INET_ADDR_LEN]; STATUS status = ifAddrGet(interface, address); if (status == OK) { // Concatenate a ':' at the end. This is because in // ACE_INET_Addr::string_to_addr, the ip_address is // obtained using ':' as the delimiter. Since, using // ifAddrGet(), we just get the IP address, I am adding // a ":" to get with the general case. ACE_OS::strcat (address, ":"); addrs[count].set (address); } else { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("ACE::get_ip_interface failed\n") ACE_TEXT ("Couldnt get the IP Address\n")), -1); } ++count; } } return 0; } #endif // ACE_WIN32 || ACE_HAS_GETIFADDRS || __hpux || _AIX || ACE_VXWORKS < 0x600 // return an array of all configured IP interfaces on this host, count // rc = 0 on success (count == number of interfaces else -1 caller is // responsible for calling delete [] on parray int ACE::get_ip_interfaces (size_t &count, ACE_INET_Addr *&addrs) { ACE_TRACE ("ACE::get_ip_interfaces"); count = 0; addrs = 0; #if defined (ACE_WIN32) return get_ip_interfaces_win32 (count, addrs); #elif defined (ACE_HAS_GETIFADDRS) return get_ip_interfaces_getifaddrs (count, addrs); #elif defined (__hpux) return get_ip_interfaces_hpux (count, addrs); #elif defined (_AIX) return get_ip_interfaces_aix (count, addrs); #elif defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600) && !defined (ACE_HAS_VXWORKS551_MEDUSA) return get_ip_interfaces_vxworks_lt600 (count, addrs); #elif (defined (__unix) || defined (__unix__) || defined (__Lynx__) || defined (ACE_OPENVMS) || (defined (ACE_VXWORKS) && (ACE_VXWORKS == 0x650)) || defined (ACE_HAS_RTEMS)) && !defined (ACE_LACKS_NETWORKING) // COMMON (SVR4 and BSD) UNIX CODE // Call specific routine as necessary. ACE_HANDLE handle = ACE::get_handle(); if (handle == ACE_INVALID_HANDLE) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces:open")), -1); size_t num_ifs, num_ifs_found; if (ACE::count_interfaces (handle, num_ifs)) { ACE_OS::close (handle); return -1; } // ioctl likes to have an extra ifreq structure to mark the end of // what it returned, so increase the num_ifs by one. ++num_ifs; struct IFREQ *ifs = 0; ACE_NEW_RETURN (ifs, struct IFREQ[num_ifs], -1); ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct IFREQ)); ACE_Auto_Array_Ptr p_ifs (ifs); if (p_ifs.get() == 0) { ACE_OS::close (handle); errno = ENOMEM; return -1; } struct IFCONF ifcfg; ACE_OS::memset (&ifcfg, 0, sizeof (struct IFCONF)); # ifdef SETFAMILY ifcfg.IFC_FAMILY = AF_UNSPEC; // request all families be returned ifcfg.IFC_FLAGS = 0; # endif ifcfg.IFC_REQ = p_ifs.get (); ifcfg.IFC_LEN = num_ifs * sizeof (struct IFREQ); if (ACE_OS::ioctl (handle, SIOCGIFCONF_CMD, (caddr_t) &ifcfg) == -1) { ACE_OS::close (handle); ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::get_ip_interfaces:") ACE_TEXT ("ioctl - SIOCGIFCONF failed")), -1); } ACE_OS::close (handle); // Now create and initialize output array. ACE_NEW_RETURN (addrs, ACE_INET_Addr[num_ifs], -1); // caller must free struct IFREQ *pcur = p_ifs.get (); num_ifs_found = ifcfg.IFC_LEN / sizeof (struct IFREQ); // get the number of returned ifs // Pull the address out of each INET interface. Not every interface // is for IP, so be careful to count properly. When setting the // INET_Addr, note that the 3rd arg (0) says to leave the byte order // (already in net byte order from the interface structure) as is. count = 0; for (size_t i = 0; i < num_ifs_found; i++) { if (pcur->IFR_ADDR.SA_FAMILY == AF_INET # if defined (ACE_HAS_IPV6) || pcur->IFR_ADDR.SA_FAMILY == AF_INET6 # endif ) { # if !defined(_UNICOS) struct sockaddr_in *addr = reinterpret_cast (&pcur->IFR_ADDR); // Sometimes the kernel returns 0.0.0.0 as an IPv4 interface // address; skip those... if (addr->sin_addr.s_addr != 0 # if defined (ACE_HAS_IPV6) || (addr->sin_family == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(addr)->sin6_addr)) # endif ) { int addrlen = static_cast (sizeof (struct sockaddr_in)); # if defined (ACE_HAS_IPV6) if (addr->sin_family == AF_INET6) addrlen = static_cast (sizeof (struct sockaddr_in6)); # endif addrs[count].set (addr, addrlen); ++count; } # else /* ! _UNICOS */ // need to explicitly copy on the Cray, since the bitfields kinda // screw things up here struct sockaddr_in inAddr; inAddr.sin_len = pcur->IFR_ADDR.sa_len; inAddr.sin_family = pcur->IFR_ADDR.sa_family; memcpy((void *)&(inAddr.sin_addr), (const void *)&(pcur->IFR_ADDR.sa_data[8]), sizeof(struct in_addr)); if (inAddr.sin_addr.s_addr != 0) { addrs[count].set(&inAddr, sizeof(struct sockaddr_in)); ++count; } # endif /* ! _UNICOS */ } #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) ++pcur; #else if (pcur->ifr_addr.sa_len <= sizeof (struct sockaddr)) { ++pcur; } else { pcur = (struct ifreq *) (pcur->ifr_addr.sa_len + (caddr_t) &pcur->ifr_addr); } #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) */ } # if defined (ACE_HAS_IPV6) // Retrieve IPv6 local interfaces by scanning /proc/net/if_inet6 if // it exists. If we cannot open it then ignore possible IPv6 // interfaces, we did our best;-) FILE* fp; char addr_p[8][5]; char s_ipaddr[64]; int scopeid; struct addrinfo hints, *res0; int error; ACE_OS::memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AF_INET6; if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0) { while (fscanf (fp, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*8s\n", addr_p[0], addr_p[1], addr_p[2], addr_p[3], addr_p[4], addr_p[5], addr_p[6], addr_p[7], &scopeid) != EOF) { // Format the address intoa proper IPv6 decimal address specification and // resolve the resulting text using getaddrinfo(). const char* ip_fmt = "%s:%s:%s:%s:%s:%s:%s:%s%%%d"; ACE_OS::sprintf (s_ipaddr, ip_fmt, addr_p[0], addr_p[1], addr_p[2], addr_p[3], addr_p[4], addr_p[5], addr_p[6], addr_p[7], scopeid); error = getaddrinfo (s_ipaddr, 0, &hints, &res0); if (error) continue; if (res0->ai_family == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED (&reinterpret_cast (res0->ai_addr)->sin6_addr)) { addrs[count].set(reinterpret_cast (res0->ai_addr), res0->ai_addrlen); ++count; } freeaddrinfo (res0); } ACE_OS::fclose (fp); } # endif /* ACE_HAS_IPV6 */ return 0; #else ACE_UNUSED_ARG (count); ACE_UNUSED_ARG (addrs); ACE_NOTSUP_RETURN (-1); // no implementation #endif /* ACE_WIN32 */ } // Helper routine for get_ip_interfaces, differs by UNIX platform so // put into own subroutine. perform some ioctls to retrieve ifconf // list of ifreq structs. int ACE::count_interfaces (ACE_HANDLE handle, size_t &how_many) { #if defined (ACE_WIN32) || defined (ACE_HAS_GETIFADDRS) || defined (__hpux) || defined (_AIX) || (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600)) // none of these platforms make use of count_interfaces ACE_UNUSED_ARG (handle); ACE_UNUSED_ARG (how_many); ACE_NOTSUP_RETURN (-1); // no implementation #elif defined (SIOCGIFNUM) # if defined (SIOCGLIFNUM) int cmd = SIOCGLIFNUM; struct lifnum if_num = {AF_UNSPEC,0,0}; # else int cmd = SIOCGIFNUM; int if_num = 0; # endif /* SIOCGLIFNUM */ if (ACE_OS::ioctl (handle, cmd, (caddr_t)&if_num) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::count_interfaces:") ACE_TEXT ("ioctl - SIOCGLIFNUM failed")), -1); # if defined (SIOCGLIFNUM) how_many = if_num.lifn_count; # else how_many = if_num; # endif /* SIOCGLIFNUM */ return 0; #elif (defined (__unix) || defined (__unix__) || defined (__Lynx__) || defined (ACE_OPENVMS) || defined (ACE_HAS_RTEMS)) && !defined (ACE_LACKS_NETWORKING) // Note: DEC CXX doesn't define "unix". BSD compatible OS: HP UX, // AIX, SunOS 4.x perform some ioctls to retrieve ifconf list of // ifreq structs no SIOCGIFNUM on SunOS 4.x, so use guess and scan // algorithm // Probably hard to put this many ifs in a unix box.. const int MAX_IF = 50; // HACK - set to an unreasonable number int num_ifs = MAX_IF; struct ifconf ifcfg; size_t ifreq_size = num_ifs * sizeof (struct ifreq); struct ifreq *p_ifs = (struct ifreq *) ACE_OS::malloc (ifreq_size); if (!p_ifs) { errno = ENOMEM; return -1; } ACE_OS::memset (p_ifs, 0, ifreq_size); ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf)); ifcfg.ifc_req = p_ifs; ifcfg.ifc_len = ifreq_size; if (ACE_OS::ioctl (handle, SIOCGIFCONF_CMD, (caddr_t) &ifcfg) == -1) { ACE_OS::free (ifcfg.ifc_req); ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE::count_interfaces:") ACE_TEXT ("ioctl - SIOCGIFCONF failed")), -1); } int if_count = 0, i; // get if address out of ifreq buffers. ioctl puts a blank-named // interface to mark the end of the returned interfaces. for (i = 0; i < num_ifs; i++) { /* In OpenBSD, the length of the list is returned. */ ifcfg.ifc_len -= sizeof (struct ifreq); if (ifcfg.ifc_len < 0) break; ++if_count; #if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) ++p_ifs; #else if (p_ifs->ifr_addr.sa_len <= sizeof (struct sockaddr)) { ++p_ifs; } else { p_ifs = (struct ifreq *) (p_ifs->ifr_addr.sa_len + (caddr_t) &p_ifs->ifr_addr); } #endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) */ } ACE_OS::free (ifcfg.ifc_req); # if defined (ACE_HAS_IPV6) FILE* fp = 0; if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0) { // Scan the lines according to the expected format but don't really read any input while (fscanf (fp, "%*32s %*02x %*02x %*02x %*02x %*8s\n") != EOF) { ++if_count; } ACE_OS::fclose (fp); } # endif /* ACE_HAS_IPV6 */ how_many = if_count; return 0; #else ACE_UNUSED_ARG (handle); ACE_UNUSED_ARG (how_many); ACE_NOTSUP_RETURN (-1); // no implementation #endif /* sparc && SIOCGIFNUM */ } // Routine to return a handle from which ioctl() requests can be made. ACE_HANDLE ACE::get_handle (void) { // Solaris 2.x ACE_HANDLE handle = ACE_INVALID_HANDLE; #if defined (sparc) handle = ACE_OS::open ("/dev/udp", O_RDONLY); #elif defined (__unix) || defined (__unix__) || defined (__Lynx__) || defined (_AIX) || defined (__hpux) || (defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600)) || defined (ACE_OPENVMS) || defined (ACE_HAS_RTEMS) // Note: DEC CXX doesn't define "unix" BSD compatible OS: HP UX, // AIX, SunOS 4.x handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0); #endif /* sparc */ return handle; } #if defined (ACE_HAS_IPV6) static int ip_check (int &ipvn_enabled, int pf) { // We only get to this point if ipvn_enabled was -1 in the caller. // Perform Double-Checked Locking Optimization. ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, *ACE_Static_Object_Lock::instance (), 0)); if (ipvn_enabled == -1) { // Determine if the kernel has IPv6 support by attempting to // create a PF_INET socket and see if it fails. ACE_HANDLE const s = ACE_OS::socket (pf, SOCK_DGRAM, 0); if (s == ACE_INVALID_HANDLE) { ipvn_enabled = 0; } else { ipvn_enabled = 1; ACE_OS::closesocket (s); } } return ipvn_enabled; } #endif /* ACE_HAS_IPV6 */ bool ACE::ipv4_enabled (void) { #if defined (ACE_HAS_IPV6) return static_cast (ace_ipv4_enabled == -1 ? ::ip_check (ace_ipv4_enabled, PF_INET) : ace_ipv4_enabled); #else // Assume it's always enabled since ACE requires some version of // TCP/IP to exist. return true; #endif /* ACE_HAS_IPV6*/ } int ACE::ipv6_enabled (void) { #if defined (ACE_HAS_IPV6) return ace_ipv6_enabled == -1 ? ::ip_check (ace_ipv6_enabled, PF_INET6) : ace_ipv6_enabled; #else /* ACE_HAS_IPV6 */ return 0; #endif /* !ACE_HAS_IPV6 */ } ACE_END_VERSIONED_NAMESPACE_DECL