From 647a2e5a4444a8486e3e6214208bf29ecfa81d7c Mon Sep 17 00:00:00 2001 From: Steve Huston Date: Tue, 17 Apr 2012 22:22:08 +0000 Subject: Merge in multicast changes from trunk ACE 6.1.1 release 3/21/2012 to 4/3/2012 --- ChangeLog | 59 +++++++ ace/SOCK_Dgram_Mcast.cpp | 235 +++++++++++++------------- ace/SOCK_Dgram_Mcast.h | 169 ++++++++++-------- ace/Sock_Connect.cpp | 13 +- bin/MakeProjectCreator/config/acedefaults.mpb | 4 + bin/MakeProjectCreator/config/ipv6.mpb | 4 - tests/Multicast_Test.cpp | 30 ++-- 7 files changed, 304 insertions(+), 210 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9249e14d710..b33fd579b99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,62 @@ +Tue Apr 3 22:49:11 UTC 2012 Steve Huston + + * ace/SOCK_Dgram_Mcast.cpp (subscribe_ifs): Set the error code when + a Windows API call fails. Also, when calling GetAdaptersAddresses() + to both check size and get the info, supply GAA_FLAG_SKIP_MULTICAST + as the flag value. This avoids obtaining info for joined multicast + addresses, not multicastable interfaces. Without the flag, and if + some other process does a join between the size-check call and the + info-gathering call, the size will be wrong. + +Wed Mar 28 21:44:20 UTC 2012 Steve Huston + + * tests/Multicast_Test.cpp: Removed the forced set_nic to "lo" for + Linux. It's not needed with the changes from: + Wed Mar 21 21:57:40 UTC 2012 Steve Huston + +Sat Mar 24 21:53:13 UTC 2012 Steve Huston + + * ace/SOCK_Dgram_Mcast.cpp (subscribe_ifs): For Windows, handle IPv6 + and IPv4 differently. The make_multicast_ifaddr() call that will end + up being made for IPv4 wants the interface's IP address, not name. + + * bin/MakeProjectCreator/config/acedefaults.mpb: + * bin/MakeProjectCreator/config/ipv6.mpb: Moved the lit_lib for iphlpapi + on Windows from the IPv6 base to acedefaults. SOCK_Dgram_Mcast.cpp + uses it for both IPv4 and IPv6 now. + +Thu Mar 22 16:23:14 UTC 2012 Steve Huston + + * ace/SOCK_Dgram_Mcast.h: Corrected the description of conditions + under which using OPT_NULLIFACE_ALL works and neatened things up. + + * tests/Multicast_Test.cpp: Turn on IP_MULTICAST_LOOP all the time. + This test requires it and it's not universally the default. + +Wed Mar 21 21:57:40 UTC 2012 Steve Huston + + * ace/SOCK_Dgram_Mcast.cpp (subscribe_ifs): Expanded the use of + code to scan interfaces to be always, not just for IPv6, when + subscribing with OPT_NULLIFACE_ALL and no specific interface. + Also replaced use of ACE_OS::if_nameindex with getifaddr() when + it's available (which was only on Linux anyway) so checks + for interface up and multicastable can be made before joining. + The code now works for systems with ACE_HAS_GETIFDADDR (incl. + Linux, which was my main issue driving this) and Win32. The others + end up in the old get_ip_interfaces code which will never work + anywhere as far as I can tell because it tries to subscribe to an + interface named with the IP address in string form. + + * tests/Multicast_Test.cpp: Removed hack force of interface "lo0" + on join(). No need for that with the fix above. For background, this + was added at: + Thu Jan 21 15:25:30 UTC 2010 Martin Corino + + * ace/Sock_Connect.cpp (get_ip_interfaces_getifaddr): Will no longer + return an interface marked 'down'. Partially fixes Bugzilla #1990 + but other platform-specific changes are needed to resolve it + completely. + Wed Mar 07 09:04:40 CET 2012 Johnny Willemsen * ACE version 6.1.0 released. 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 /**/ #endif +#if defined (ACE_HAS_GETIFADDRS) +# if defined (ACE_VXWORKS) +# include /**/ +# else +# include /**/ +# 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 (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 (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 (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 (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; diff --git a/ace/SOCK_Dgram_Mcast.h b/ace/SOCK_Dgram_Mcast.h index 6f3c3bc5b62..a2e54969d39 100644 --- a/ace/SOCK_Dgram_Mcast.h +++ b/ace/SOCK_Dgram_Mcast.h @@ -46,50 +46,56 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL * * Supports multiple simultaneous subscriptions, unsubscription from one or * all subscriptions, and independent send/recv address and interface - * specifications. Template parameters and/or ctor arguments determine - * per-instance optional functionality. + * specifications. Constructor arguments determine per-instance optional + * functionality. * - * Note that multicast semantics and implementation details are _very_ + * Note that multicast semantics and implementation details are @i very * environment-specific; this class is just a wrapper around the underlying * implementation and does not try to normalize the concept of multicast * communications. * * Usage Notes: - * - Send and Recv addresses and network interfaces, but not port#, are - * independent. While this instance is open, 1 send interface (and a default - * send address) is in effect and 0, 1, or multiple recv addresses/interfaces - * are in effect. + * - Send and receive addresses and network interfaces, but not port number, + * are independent. While this instance is open, one send interface (and a + * default send address) is in effect and 0, 1, or multiple receive + * addresses/interfaces are in effect. * - The first open()/subscribe() invocation defines the network interface * and default address used for all sends by this instance, defines the - * port# and optionally the multicast address bound to the underlying - * socket, and defines the (one) port# that is used for all subscribes - * (subsequent subscribes must pass the same port# or '0'). + * port number and optionally the multicast address bound to the underlying + * socket, and defines the (one) port number that is used for all subscribes + * (subsequent subscribes must pass the same port number or 0). * - The default loopback state is not explicitly set; the environment will - * determine the default state. Note that some environments (e.g. some Win32) - * do not allow the default to be changed, and that the semantics of - * loopback control are environment dependent (e.g. sender vs receiver - * control). + * determine the default state. Note that some environments (e.g. some + * Windows versions) do not allow the default to be changed, and that the + * semantics of loopback control are environment dependent (e.g. sender vs. + * receiver control). * - In general, due to multicast design and implementation quirks/bugs, it is * difficult to tell which address a received message was sent to or which * interface it was received on (even if only one subscription is active). - * However; there are filtering options that can be applied, to narrow it + * However, there are filtering options that can be applied, to narrow it * down considerably. * * Interface specification notes (for subscribe() and unsubscribe()): - * - If net_if == 0, the null_iface_opt option determines whether only the - * system "default" interface or all interfaces is affected. Specifying - * "all" interfaces is supported only for environments for which - * ACE_Sock_Connect::get_ip_interfaces() is properly implemented. + * - If @a net_if == 0, the @c OPT_NULLIFACE_ALL and @c OPT_NULLIFACE_ONE + * options determine whether only the system default interface + * (if @c OPT_NULLIFACE_ONE is set) or all interfaces (if + * @c OPT_NULLIFACE_ALL is set) is affected. Specifying all interfaces + * functions correctly only on: + * + Windows + * + Platforms with the ACE_HAS_GETIFADDRS config setting (includes Linux) + * + Platforms which accept the IP address as an interface + * name/specification + * + Systems with only one non-loopback interface. + * Other platforms require additional supporting code. * - Multiple subscriptions for the same address but different interfaces is * normally supported, but re-subscription to an address/interface that is * already subscribed is normally not allowed. - * - The interface specification syntax is environment-specific. + * - The @a net_if interface specification syntax is environment-specific. * UNIX systems will normally use device specifications such as "le0" or * "elxl1", while other systems will use the IP address of the interface. * Some platforms, such as pSoS, support only cardinal numbers as network * interface specifications; for these platforms, just give these numbers in - * alphanumeric form and will convert them into numbers via - * ACE_OS::atoi(). + * string form and join() will convert them into numbers. */ class ACE_Export ACE_SOCK_Dgram_Mcast : public ACE_SOCK_Dgram { @@ -99,28 +105,30 @@ public: * @brief Option parameters. * * These control per-instance optional functionality. They are set via - * optional constructor arguments. + * an optional constructor argument. + * * @note Certain option values are not valid for all environments (see * comments in source file for environment-specific restrictions). Default * values are always valid values for the compilation environment. */ enum options { - // Define whether a specific (multicast) address (in addition to the port#) - // is bound to the socket. - // Notes: - // - Effect of doing this is stack/environment dependent, but in most - // environments can be used to filter out unwanted unicast, broadcast, and - // (other) multicast messages sent to the same port#. - // - Some IP stacks (e.g. some Win32) do not support binding multicast - // addresses. Using this option will always cause an error. - // - It's not strictly possible for user code to do this level of filtering - // w/out the bind; some environments support ways to determine which address - // a message was sent _to_, but this class interface does not support access - // to that info. - // - The address (and port#) passed to (or the first , if - // is not explicitly invoked) is the one that is bound. - // + /* Define whether a specific multicast address (in addition to the port + * number) is bound to the socket. + * @note: + * - Effect of doing this is stack/environment dependent, but in most + * environments can be used to filter out unwanted unicast, broadcast, + * and (other) multicast messages sent to the same port number. + * - Some IP stacks (e.g. some Windows) do not support binding multicast + * addresses. Using this option will always cause an open() error. + * - It's not strictly possible for user code to do this level of filtering + * without the bind; some environments support ways to determine which + * address a message was sent to, but this class interface does not + * support access to that information. + * - The address (and port number) passed to open() (or the first + * join(), if open() is not explicitly invoked) is the one that is bound. + */ + /// Disable address bind. (Bind only port.) /// @note This might seem odd, but we need a way to distinguish between /// default behavior, which might or might not be to bind, and explicitly @@ -142,20 +150,28 @@ public: DEFOPT_BINDADDR = OPT_BINDADDR_NO, #endif /* ACE_LACKS_PERFECT_MULTICAST_FILTERING = 1) */ - /// Define the interpretation of 'NULL' as a recv interface specification. - /// If the interface part of a multicast address specification is NULL, it - /// will be interpreted to mean either "the default interface" or "all - /// interfaces", depending on the setting of this option. - /// Notes: - /// - The 'nulliface_all' option can not be used in environments which do - /// not fully support the ACE_Sock_Connect::get_ip_interfaces() method - /// (e.g. non-Windows). - /// If it is, using NULL for iface will _always_ fail. - /// - The default behavior in most IP stacks is to use the 'default' interface, - /// where 'default' has rather ad-hoc semantics. - /// - This applies only to receives, not sends (which always use only one - /// interface; NULL means use the "system default" interface). - /// Supported values: + /* + * Define the interpretation of NULL as a join interface specification. + * If the interface part of a multicast address specification is NULL, it + * will be interpreted to mean either "the default interface" or "all + * interfaces", depending on the setting of this option. + * @note + * - The @c OPT_NULLIFACE_ALL option can be used only in the following + * environments: + * + Windows + * + Platforms with the ACE_HAS_GETIFADDRS config setting (includes + * Linux) + * + Platforms which accept the IP address as an interface + * name/specification and for which + * ACE_Sock_Connect::get_ip_interfaces() is fully implemented + * + Systems with only one non-loopback interface. + * Other platforms require additional supporting code. + * - The default behavior in most IP stacks is to use the default + * interface where "default" has rather ad-hoc semantics. + * - This applies only to receives, not sends (which always use only one + * interface; NULL means use the "system default" interface). + */ + /// Supported values: /// If (net_if==NULL), use default interface. /// @note This might seem odd, but we need a way to distinguish between /// default behavior, which might or might not be to bind, and explicitly @@ -179,15 +195,15 @@ public: // = Initialization routines. - /// Ctor - Create an unitialized instance and define per-instance optional + /// Create an unitialized instance and define per-instance optional /// functionality. /** - * You must invoke open() or subscribe(), to create/bind a socket and define + * You must invoke open() or join(), to create/bind a socket and define * operational parameters, before performing any I/O with this instance. */ ACE_SOCK_Dgram_Mcast (options opts = DEFOPTS); - /// Dtor - Release all resources and implicitly or explicitly unsubscribe + /// Release all resources and implicitly or explicitly unsubscribe /// from all currently subscribed groups. /** * The OPT_DTORUNSUB_YES_ option defines whether an explicit unsubscribe() is @@ -196,31 +212,36 @@ public: */ ~ACE_SOCK_Dgram_Mcast (void); - /// Explicitly open/bind the socket and define the network interface - /// and default multicast address used for sending messages. /** + * Explicitly open/bind the socket and define the network interface + * and default multicast address used for sending messages. + * * This method is optional; if not explicitly invoked, it is invoked by - * the first subscribe(), using the subscribed address/port# and network + * the first join(), using the subscribed address/port number and network * interface parameters. - * The @a mcast_addr parameter defines the default send address/port# and - * also the port# and, if the OPT_BINDADDR_YES option is used, - * the multicast address that is bound to this socket. - * If the @a net_if parameter != 0, it defines the network interface - * used for all sends by this instance, otherwise the system "default" - * interface is used. (The @a net_if parameter is ignored if this - * feature is not supported by the environment.) - * The port# in @a mcast_addr may be 0, in which case a system-assigned - * (ephemeral) port# is used for sending and receiving. - * If @a reuse_addr != 0, the SO_REUSEADDR option and, if it is supported, - * the SO_REUSEPORT option are enabled. * - * Returns: -1 if the call fails. Failure can occur due to problems with - * the address, port#, and/or interface parameters or during system open() + * @param mcast_addr Defines the default send address/port number and, + * if the @c OPT_BINDADDR_YES option is used, the multicast address + * that is bound to this socket. The port number in @a mcast_addr + * may be 0, in which case a system-assigned (ephemeral) port number + * is used for sending and receiving. + * + * @param net_if If @a net_if is not 0, it defines the network interface + * used for all sends by this instance, otherwise the system default + * interface is used. (The @a net_if parameter is ignored if this + * feature is not supported by the environment.) + * + * @param reuse_addr If @a reuse_addr is not 0, the @c SO_REUSEADDR option + * and, if it is supported, the SO_REUSEPORT option are enabled. + * + * @retval 0 on success + * @retval -1 if the call fails. Failure can occur due to problems with + * the address, port, and/or interface parameters or during system open() * or socket option processing. */ - int open (const ACE_INET_Addr &mcast_addr, // Bound & sendto address. - const ACE_TCHAR *net_if = 0, // Net interface for sends. - int reuse_addr = 1); // Reuse addr/port sock opt. + int open (const ACE_INET_Addr &mcast_addr, + const ACE_TCHAR *net_if = 0, + int reuse_addr = 1); // = Multicast group subscribe/unsubscribe routines. diff --git a/ace/Sock_Connect.cpp b/ace/Sock_Connect.cpp index 332b21bb69e..8973534b202 100644 --- a/ace/Sock_Connect.cpp +++ b/ace/Sock_Connect.cpp @@ -777,8 +777,14 @@ get_ip_interfaces_getifaddrs (size_t &count, p_if != 0; p_if = p_if->ifa_next) { - if (p_if->ifa_addr && - p_if->ifa_addr->sa_family == AF_INET) + if (p_if->ifa_addr == 0) + continue; + + // Check to see if it's up. + if ((p_if->ifa_flags & IFF_UP) != IFF_UP) + continue; + + if (p_if->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr = reinterpret_cast (p_if->ifa_addr); @@ -794,8 +800,7 @@ get_ip_interfaces_getifaddrs (size_t &count, } } # if defined (ACE_HAS_IPV6) - else if (p_if->ifa_addr && - p_if->ifa_addr->sa_family == AF_INET6) + else if (p_if->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr = reinterpret_cast (p_if->ifa_addr); diff --git a/bin/MakeProjectCreator/config/acedefaults.mpb b/bin/MakeProjectCreator/config/acedefaults.mpb index 7c7cff5c75c..6798ba1ea52 100644 --- a/bin/MakeProjectCreator/config/acedefaults.mpb +++ b/bin/MakeProjectCreator/config/acedefaults.mpb @@ -17,6 +17,10 @@ project: ipv6, vc_warnings, build_files, test_files, svc_conf_files, ace_unicode macro_for_lib_modifier=1 } + specific(prop:windows) { + lit_libs += iphlpapi + } + specific(cdt6) { win32::platform_libs += ws2_32 mswsock netapi32 release::macros += ACE_NDEBUG ACE_USE_RCSID=0 diff --git a/bin/MakeProjectCreator/config/ipv6.mpb b/bin/MakeProjectCreator/config/ipv6.mpb index 92473ad7113..b76821b80d1 100644 --- a/bin/MakeProjectCreator/config/ipv6.mpb +++ b/bin/MakeProjectCreator/config/ipv6.mpb @@ -2,9 +2,5 @@ // $Id$ feature(ipv6) { - specific(prop:windows) { - lit_libs += iphlpapi - } - macros += ACE_HAS_IPV6 } diff --git a/tests/Multicast_Test.cpp b/tests/Multicast_Test.cpp index 5d1d8109f12..a053676b1c2 100644 --- a/tests/Multicast_Test.cpp +++ b/tests/Multicast_Test.cpp @@ -448,19 +448,11 @@ public: = ACE_SOCK_Dgram_Mcast::DEFOPTS); virtual ~MCT_Event_Handler (void); -#if defined (ACE_LINUX) - int join (const ACE_INET_Addr &mcast_addr, - int reuse_addr = 1, - const ACE_TCHAR *net_if = ACE_TEXT ("lo")); - int leave (const ACE_INET_Addr &mcast_addr, - const ACE_TCHAR *net_if = ACE_TEXT ("lo")); -#else int join (const ACE_INET_Addr &mcast_addr, int reuse_addr = 1, const ACE_TCHAR *net_if = 0); int leave (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if = 0); -#endif // = Event Handler hooks. virtual int handle_input (ACE_HANDLE handle); @@ -468,6 +460,9 @@ public: virtual ACE_HANDLE get_handle (void) const; + // Turn loopback on/off. Must be called after at least 1 join() is performed. + int loopback (bool on_off); + protected: ACE_SOCK_Dgram_Mcast *mcast (void); int find (const char *buf); @@ -641,6 +636,14 @@ MCT_Event_Handler::get_handle (void) const return this->mcast_.get_handle (); } +// Turn loopback on/off +int +MCT_Event_Handler::loopback (bool on_off) +{ + char loopback_on = on_off ? 1 : 0; + return this->mcast_.set_option (IP_MULTICAST_LOOP, loopback_on); +} + /******************************************************************************/ /* @@ -721,6 +724,13 @@ MCT_Task::open (void *) advance_addr (addr); + // This test needs loopback because we're both sending and receiving. + // Loopback is usually the default, but be sure. + if (-1 == handler->loopback (true)) + ACE_ERROR ((LM_WARNING, + ACE_TEXT ("%p\n"), + ACE_TEXT ("MCT_Task::open - enable loopback"))); + if (this->reactor ()->register_handler (handler, READ_MASK) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("MCT_Task::open - cannot register ") @@ -787,9 +797,7 @@ int producer (MCT_Config &config) ACE_DEBUG ((LM_INFO, ACE_TEXT ("Starting producer...\n"))); ACE_SOCK_Dgram socket (ACE_sap_any_cast (ACE_INET_Addr &), PF_INET); //FUZZ: enable check_for_lack_ACE_OS -#if defined (ACE_LINUX) - socket.set_nic (ACE_TEXT("lo")); -#endif + // Note that is is IPv4 specific and needs to be changed once // if (config.ttl () > 1) -- cgit v1.2.1