diff options
Diffstat (limited to 'ace/SOCK_Dgram_Mcast.cpp')
-rw-r--r-- | ace/SOCK_Dgram_Mcast.cpp | 235 |
1 files changed, 118 insertions, 117 deletions
diff --git a/ace/SOCK_Dgram_Mcast.cpp b/ace/SOCK_Dgram_Mcast.cpp index abac401f790..a5d5e5e0c16 100644 --- a/ace/SOCK_Dgram_Mcast.cpp +++ b/ace/SOCK_Dgram_Mcast.cpp @@ -12,10 +12,18 @@ #include "ace/OS_NS_sys_socket.h" #endif -#if defined (ACE_HAS_IPV6) && defined (ACE_WIN32) +#if defined (ACE_WIN32) #include /**/ <iphlpapi.h> #endif +#if defined (ACE_HAS_GETIFADDRS) +# if defined (ACE_VXWORKS) +# include /**/ <net/ifaddrs.h> +# else +# include /**/ <ifaddrs.h> +# endif /*ACE_VXWORKS */ +#endif /* ACE_HAS_GETIFADDRS */ + #if !defined (__ACE_INLINE__) #include "ace/SOCK_Dgram_Mcast.inl" #endif /* __ACE_INLINE__ */ @@ -253,135 +261,135 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) && net_if == 0) { -#if defined (ACE_HAS_IPV6) - if (mcast_addr.get_type () == AF_INET6) - { - size_t nr_subscribed = 0; -# if defined(ACE_LINUX) - struct if_nameindex *intf = 0; - - intf = ACE_OS::if_nameindex (); - - if (intf == 0) - return -1; - - int index = 0; - while (intf[index].if_index != 0 || intf[index].if_name != 0) - { - if (this->join (mcast_addr, reuse_addr, - ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0) - ++nr_subscribed; - - ++index; - } + int family = mcast_addr.get_type (); + size_t nr_subscribed = 0; - ACE_OS::if_freenameindex (intf); +#if defined (ACE_HAS_GETIFADDRS) -# elif defined (ACE_WIN32) + // Take advantage of the BSD getifaddrs function that simplifies + // access to connected interfaces. + struct ifaddrs *ifap = 0; + struct ifaddrs *p_if = 0; - IP_ADAPTER_ADDRESSES tmp_addrs; - // Initial call to determine actual memory size needed - DWORD dwRetVal; - ULONG bufLen = 0; - if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6, - 0, - 0, - &tmp_addrs, - &bufLen)) != ERROR_BUFFER_OVERFLOW) - return -1; // With output bufferlength 0 this can't be right. + if (::getifaddrs (&ifap) != 0) + return -1; - // Get required output buffer and retrieve info for real. - PIP_ADAPTER_ADDRESSES pAddrs; - char *buf; - ACE_NEW_RETURN (buf, - char[bufLen], - -1); - pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf); - if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6, - 0, - 0, - pAddrs, - &bufLen)) != NO_ERROR) + // Not every interface is for IP, and not all are up and multicast. + for (p_if = ifap; + p_if != 0; + p_if = p_if->ifa_next) + { + // Some OSes can return interfaces with no ifa_addr if the + // interface has no assigned address. + // If there is an address but it's not the family we want, ignore it. + if (p_if->ifa_addr == 0 || p_if->ifa_addr->sa_family != family) + continue; + + // Check to see if it's up and supports multicast. + unsigned int wanted = IFF_UP | IFF_MULTICAST; + if ((p_if->ifa_flags & wanted) != wanted) + continue; + + // Sometimes the kernel returns 0.0.0.0 as the interface + // address, skip those... + if (p_if->ifa_addr->sa_family == PF_INET) { - delete[] buf; // clean up - return -1; - } + struct sockaddr_in *addr = + reinterpret_cast<sockaddr_in *> (p_if->ifa_addr); - while (pAddrs) + if (addr->sin_addr.s_addr == INADDR_ANY) + continue; + } +# if defined (ACE_HAS_IPV6) + else if (p_if->ifa_addr->sa_family == AF_INET6) { - if (this->join (mcast_addr, reuse_addr, - ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0) - ++nr_subscribed; + struct sockaddr_in6 *addr = + reinterpret_cast<sockaddr_in6 *> (p_if->ifa_addr); - pAddrs = pAddrs->Next; + // Skip the ANY address + if (IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) + continue; } +# endif /* ACE_HAS_IPV6 */ - delete[] buf; // clean up + // Ok, now join on this interface. + if (this->join (mcast_addr, + reuse_addr, + ACE_TEXT_CHAR_TO_TCHAR(p_if->ifa_name)) == 0) + ++nr_subscribed; + } -# endif /* ACE_WIN32 */ + ::freeifaddrs (ifap); - if (nr_subscribed == 0) - { - errno = ENODEV; - return -1; - } +# elif defined (ACE_WIN32) - return 1; - } - else + IP_ADAPTER_ADDRESSES tmp_addrs; + // Initial call to determine actual memory size needed + DWORD dwRetVal; + ULONG bufLen = 0; + // Note... GetAdaptersAddresses returns different bufLen values depending + // on how many multicast joins there are on the system. To avoid this, + // specify that we don't want to know about multicast addresses. This + // does not avoid multicastable interfaces and makes the size-check + // more reliable across varying conditions. + DWORD flags = GAA_FLAG_SKIP_MULTICAST; + if ((dwRetVal = ::GetAdaptersAddresses (family, + flags, + 0, + &tmp_addrs, + &bufLen)) != ERROR_BUFFER_OVERFLOW) { - // Subscribe on all local multicast-capable network interfaces, by - // doing recursive calls with specific interfaces. - - ACE_INET_Addr *if_addrs = 0; - size_t if_cnt; + errno = dwRetVal; + return -1; // With output bufferlength 0 this can't be right. + } - if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0) - return -1; + // Get required output buffer and retrieve info for real. + PIP_ADAPTER_ADDRESSES pAddrs; + char *buf; + ACE_NEW_RETURN (buf, + char[bufLen], + -1); + pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf); + if ((dwRetVal = ::GetAdaptersAddresses (family, + flags, + 0, + pAddrs, + &bufLen)) != NO_ERROR) + { + delete[] buf; // clean up + errno = dwRetVal; + return -1; + } - size_t nr_subscribed = 0; + for (; pAddrs; pAddrs = pAddrs->Next) + { + if (pAddrs->OperStatus != IfOperStatusUp) + continue; - if (if_cnt < 2) + // The ACE_SOCK_Dgram::make_multicast_ifaddr (IPv4), called by join(), + // can only deal with a dotted-decimal address, not an interface name. + if (family == AF_INET) { - if (this->join (mcast_addr, - reuse_addr, - ACE_TEXT ("0.0.0.0")) == 0) + ACE_INET_Addr intf_addr ((sockaddr_in*)(pAddrs->FirstUnicastAddress->Address.lpSockaddr), + pAddrs->FirstUnicastAddress->Address.iSockaddrLength); + char intf_addr_str[INET_ADDRSTRLEN]; + intf_addr.get_host_addr (intf_addr_str, sizeof (intf_addr_str)); + if (this->join (mcast_addr, reuse_addr, + ACE_TEXT_CHAR_TO_TCHAR(intf_addr_str)) == 0) ++nr_subscribed; } else { - // Iterate through all the interfaces, figure out which ones - // offer multicast service, and subscribe to them. - while (if_cnt > 0) - { - --if_cnt; - - // Convert to 0-based for indexing, next loop check. - if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ()) - continue; - char addr_buf[INET6_ADDRSTRLEN]; - if (this->join (mcast_addr, - reuse_addr, - ACE_TEXT_CHAR_TO_TCHAR - (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0) - ++nr_subscribed; - } + if (this->join (mcast_addr, reuse_addr, + ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0) + ++nr_subscribed; } + } - delete [] if_addrs; + delete[] buf; // clean up - if (nr_subscribed == 0) - { - errno = ENODEV; - return -1; - } +# else - // 1 indicates a "short-circuit" return. This handles the - // recursive behavior of checking all the interfaces. - return 1; - - } -#else // Subscribe on all local multicast-capable network interfaces, by // doing recursive calls with specific interfaces. @@ -391,8 +399,6 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0) return -1; - size_t nr_subscribed = 0; - if (if_cnt < 2) { if (this->join (mcast_addr, @@ -409,7 +415,7 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, --if_cnt; // Convert to 0-based for indexing, next loop check. - if (if_addrs[if_cnt].is_loopback ()) + if (if_addrs[if_cnt].get_type () != family || if_addrs[if_cnt].is_loopback ()) continue; char addr_buf[INET6_ADDRSTRLEN]; if (this->join (mcast_addr, @@ -422,18 +428,19 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, delete [] if_addrs; +# endif /* ACE_WIN32 */ + if (nr_subscribed == 0) { errno = ENODEV; return -1; } - // 1 indicates a "short-circuit" return. This handles the - // recursive behavior of checking all the interfaces. return 1; -#endif /* ACE_HAS_IPV6 */ } + // Subscribe on a specific interface, or on the default interface. + #if defined (ACE_HAS_IPV6) if (mcast_addr.get_type () == AF_INET6) { @@ -441,6 +448,7 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, return -1; } else +#endif /* ACE_HAS_IPV6 - Fall into IPv4-only case */ { // Validate passed multicast addr and iface specifications. if (this->make_multicast_ifaddr (0, @@ -448,13 +456,6 @@ ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr, net_if) == -1) return -1; } -#else - // Validate passed multicast addr and iface specifications. - if (this->make_multicast_ifaddr (0, - mcast_addr, - net_if) == -1) - return -1; -#endif /* ACE_HAS_IPV6 */ return 0; |