3 //=============================================================================
5 * @file Multicast_Interfaces_Test.cpp
7 * This is a sanity-check test of ACE_SOCK_Dgram_Mcast::join by
8 * interface name on platforms that support it.
9 * It retrieves the valid local interface names and attempts to
10 * perform a multicast join on all interfaces and then on each
11 * individual interface separately. If IPv6 is enabled, it will
12 * attempt to join on an IPv6 multicast address as well.
14 * @author Timothy Simpson <simpsont@objectcomputing.com>
16 //=============================================================================
18 #include "test_config.h"
20 #include "ace/OS_Memory.h"
21 #include "ace/OS_NS_sys_utsname.h"
22 #include "ace/SOCK_Dgram_Mcast.h"
23 #include "ace/SString.h"
25 #if defined (ACE_HAS_GETIFADDRS)
26 # include "ace/os_include/os_ifaddrs.h"
27 #endif /* ACE_HAS_GETIFADDRS */
31 using nameset
= std::set
<ACE_TString
>;
33 #if defined (ACE_WIN32)
35 get_valid_ipv4_interface_names_win32 (nameset
&names
)
39 // Initial call to determine actual memory size needed
40 IP_ADAPTER_ADDRESSES tmp_addrs
;
42 if (GetAdaptersAddresses (AF_INET
, 0, 0, &tmp_addrs
, &bufLen
) != ERROR_BUFFER_OVERFLOW
)
47 // Get required output buffer and retrieve info for real.
49 ACE_NEW (buf
, char[bufLen
]);
50 PIP_ADAPTER_ADDRESSES pAddrs
= reinterpret_cast<PIP_ADAPTER_ADDRESSES
> (buf
);
51 if (::GetAdaptersAddresses (AF_INET
, 0, 0, pAddrs
, &bufLen
) != NO_ERROR
)
59 if (pAddrs
->OperStatus
== IfOperStatusUp
&& !(pAddrs
->Flags
& IP_ADAPTER_NO_MULTICAST
))
61 PIP_ADAPTER_UNICAST_ADDRESS pUnicast
= pAddrs
->FirstUnicastAddress
;
62 LPSOCKADDR sa
= pUnicast
->Address
.lpSockaddr
;
63 if (sa
->sa_family
== AF_INET
)
65 names
.insert (ACE_TEXT_WCHAR_TO_TCHAR (pAddrs
->FriendlyName
));
68 pAddrs
= pAddrs
->Next
;
73 #elif defined (ACE_HAS_GETIFADDRS)
75 get_valid_ipv4_interface_names_getifaddrs (nameset
&names
)
80 if (::getifaddrs (&ifap
) != 0)
83 for (p_if
= ifap
; p_if
!= 0; p_if
= p_if
->ifa_next
)
85 if (p_if
->ifa_flags
& IFF_MULTICAST
&&
86 p_if
->ifa_addr
->sa_family
== AF_INET
)
88 sockaddr_in
*addr
= reinterpret_cast<sockaddr_in
*> (p_if
->ifa_addr
);
90 if (addr
->sin_addr
.s_addr
!= INADDR_ANY
)
92 names
.insert (ACE_TEXT_CHAR_TO_TCHAR (p_if
->ifa_name
));
99 #endif /* ACE_WIN32 */
102 get_valid_ipv4_interface_names (nameset
&names
)
104 #if defined (ACE_WIN32)
105 get_valid_ipv4_interface_names_win32 (names
);
106 #elif defined (ACE_HAS_GETIFADDRS)
107 get_valid_ipv4_interface_names_getifaddrs (names
);
108 #endif /* ACE_WIN32 */
111 #if defined (ACE_HAS_IPV6)
112 #if defined (ACE_WIN32)
114 get_valid_ipv6_interface_names_win32 (nameset
&names
)
118 // Initial call to determine actual memory size needed
119 IP_ADAPTER_ADDRESSES tmp_addrs
;
121 if (GetAdaptersAddresses (AF_INET
, 0, 0, &tmp_addrs
, &bufLen
) != ERROR_BUFFER_OVERFLOW
)
126 // Get required output buffer and retrieve info for real.
128 ACE_NEW (buf
, char[bufLen
]);
129 PIP_ADAPTER_ADDRESSES pAddrs
= reinterpret_cast<PIP_ADAPTER_ADDRESSES
> (buf
);
130 if (::GetAdaptersAddresses (AF_INET6
, 0, 0, pAddrs
, &bufLen
) != NO_ERROR
)
138 if (pAddrs
->OperStatus
== IfOperStatusUp
&& !(pAddrs
->Flags
& IP_ADAPTER_NO_MULTICAST
))
140 PIP_ADAPTER_UNICAST_ADDRESS pUnicast
= pAddrs
->FirstUnicastAddress
;
141 LPSOCKADDR sa
= pUnicast
->Address
.lpSockaddr
;
142 if (sa
->sa_family
== AF_INET6
)
144 names
.insert (ACE_TEXT_WCHAR_TO_TCHAR (pAddrs
->FriendlyName
));
147 pAddrs
= pAddrs
->Next
;
152 #elif defined (ACE_HAS_GETIFADDRS)
154 get_valid_ipv6_interface_names_getifaddrs (nameset
&names
)
159 if (::getifaddrs (&ifap
) != 0)
162 for (p_if
= ifap
; p_if
!= 0; p_if
= p_if
->ifa_next
)
164 if (p_if
->ifa_flags
& IFF_MULTICAST
&&
165 p_if
->ifa_addr
->sa_family
== AF_INET6
)
167 sockaddr_in6
*addr
= reinterpret_cast<sockaddr_in6
*> (p_if
->ifa_addr
);
169 if (!IN6_IS_ADDR_UNSPECIFIED (&addr
->sin6_addr
))
171 names
.insert (ACE_TEXT_CHAR_TO_TCHAR (p_if
->ifa_name
));
176 ::freeifaddrs (ifap
);
178 #endif /*ACE_WIN32 */
181 get_valid_ipv6_interface_names (nameset
&names
)
183 #if defined (ACE_WIN32)
184 get_valid_ipv6_interface_names_win32 (names
);
185 #elif defined (ACE_HAS_GETIFADDRS)
186 get_valid_ipv6_interface_names_getifaddrs (names
);
187 #endif /* ACE_WIN32 */
189 #endif /* ACE_HAS_IPV6 */
192 create_socket_and_join_multicast (const ACE_INET_Addr
&mc_addr
, const ACE_TString
&if_name
)
195 ACE_SOCK_Dgram_Mcast sock
;
196 sock
.opts (ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_NO
| ACE_SOCK_Dgram_Mcast::DEFOPT_NULLIFACE
);
197 result
= sock
.join (mc_addr
, 1, if_name
.empty () ? 0 : if_name
.c_str ());
198 result
|= sock
.close ();
203 run_main (int, ACE_TCHAR
*[])
205 ACE_START_TEST (ACE_TEXT ("Multicast_Interfaces_Test"));
210 ACE_OS::uname (&uname
);
211 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("Machine: %C running on %C\n"),
212 uname
.nodename
, uname
.machine
));
213 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("Platform: %C, %C, %C\n"),
214 uname
.sysname
, uname
.release
, uname
.version
));
218 get_valid_ipv4_interface_names (names
);
219 ACE_INET_Addr
ipv4_mc_addr ("239.255.0.7:1234", AF_INET
);
220 result
|= create_socket_and_join_multicast (ipv4_mc_addr
, ACE_TString ());
221 for (nameset::const_iterator it
= names
.begin (); result
== 0 && it
!= names
.end (); ++it
)
223 result
|= create_socket_and_join_multicast (ipv4_mc_addr
, *it
);
226 #if defined (ACE_HAS_IPV6)
228 get_valid_ipv6_interface_names (names
);
229 ACE_INET_Addr
ipv6_mc_addr ("ff03::7:4321", AF_INET6
);
230 result
|= create_socket_and_join_multicast (ipv6_mc_addr
, ACE_TString ());
231 for (nameset::const_iterator it
= names
.begin (); result
== 0 && it
!= names
.end (); ++it
)
233 result
|= create_socket_and_join_multicast (ipv6_mc_addr
, *it
);
235 #endif /* ACE_HAS_IPV6 */