5 // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
16 // Test that header file is self-contained.
17 #include <boost/asio/ip/multicast.hpp>
19 #include <boost/asio/io_context.hpp>
20 #include <boost/asio/ip/udp.hpp>
21 #include "../unit_test.hpp"
23 //------------------------------------------------------------------------------
25 // ip_multicast_compile test
26 // ~~~~~~~~~~~~~~~~~~~~~~~~~
27 // The following test checks that all nested classes, enums and constants in
28 // ip::multicast compile and link correctly. Runtime failures are ignored.
30 namespace ip_multicast_compile
{
34 using namespace boost::asio
;
35 namespace ip
= boost::asio::ip
;
40 ip::udp::socket
sock(ioc
);
41 const ip::address address
;
42 const ip::address_v4 address_v4
;
43 const ip::address_v6 address_v6
;
47 ip::multicast::join_group join_group1
;
48 ip::multicast::join_group
join_group2(address
);
49 ip::multicast::join_group
join_group3(address_v4
);
50 ip::multicast::join_group
join_group4(address_v4
, address_v4
);
51 ip::multicast::join_group
join_group5(address_v6
);
52 ip::multicast::join_group
join_group6(address_v6
, 1);
53 sock
.set_option(join_group6
);
57 ip::multicast::leave_group leave_group1
;
58 ip::multicast::leave_group
leave_group2(address
);
59 ip::multicast::leave_group
leave_group3(address_v4
);
60 ip::multicast::leave_group
leave_group4(address_v4
, address_v4
);
61 ip::multicast::leave_group
leave_group5(address_v6
);
62 ip::multicast::leave_group
leave_group6(address_v6
, 1);
63 sock
.set_option(leave_group6
);
65 // outbound_interface class.
67 ip::multicast::outbound_interface outbound_interface1
;
68 ip::multicast::outbound_interface
outbound_interface2(address_v4
);
69 ip::multicast::outbound_interface
outbound_interface3(1);
70 sock
.set_option(outbound_interface3
);
74 ip::multicast::hops
hops1(1024);
75 sock
.set_option(hops1
);
76 ip::multicast::hops hops2
;
77 sock
.get_option(hops2
);
79 (void)static_cast<int>(hops1
.value());
81 // enable_loopback class.
83 ip::multicast::enable_loopback
enable_loopback1(true);
84 sock
.set_option(enable_loopback1
);
85 ip::multicast::enable_loopback enable_loopback2
;
86 sock
.get_option(enable_loopback2
);
87 enable_loopback1
= true;
88 (void)static_cast<bool>(enable_loopback1
);
89 (void)static_cast<bool>(!enable_loopback1
);
90 (void)static_cast<bool>(enable_loopback1
.value());
92 catch (std::exception
&)
97 } // namespace ip_multicast_compile
99 //------------------------------------------------------------------------------
101 // ip_multicast_runtime test
102 // ~~~~~~~~~~~~~~~~~~~~~~~~~
103 // The following test checks the runtime operation of the socket options defined
104 // in the ip::multicast namespace.
106 namespace ip_multicast_runtime
{
109 // HP-UX doesn't declare this function extern "C", so it is declared again here
110 // to avoid a linker error about an undefined symbol.
111 extern "C" unsigned int if_nametoindex(const char*);
112 #endif // defined(__hpux)
116 using namespace boost::asio
;
117 namespace ip
= boost::asio::ip
;
120 boost::system::error_code ec
;
122 ip::udp::endpoint
ep_v4(ip::address_v4::loopback(), 0);
123 ip::udp::socket
sock_v4(ioc
);
124 sock_v4
.open(ep_v4
.protocol(), ec
);
125 sock_v4
.bind(ep_v4
, ec
);
128 ip::udp::endpoint
ep_v6(ip::address_v6::loopback(), 0);
129 ip::udp::socket
sock_v6(ioc
);
130 sock_v6
.open(ep_v6
.protocol(), ec
);
131 sock_v6
.bind(ep_v6
, ec
);
134 BOOST_ASIO_CHECK(have_v4
|| have_v6
);
136 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
137 // Windows CE seems to have problems with some multicast group addresses.
138 // The following address works on CE, but as it is not a private multicast
139 // address it will not be used on other platforms.
140 const ip::address multicast_address_v4
= ip::make_address("239.0.0.4", ec
);
141 #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
142 const ip::address multicast_address_v4
= ip::make_address("239.255.0.1", ec
);
143 #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
144 BOOST_ASIO_CHECK(!have_v4
|| !ec
);
146 #if (defined(__MACH__) && defined(__APPLE__)) \
147 || defined(__FreeBSD__) \
148 || defined(__NetBSD__) \
149 || defined(__OpenBSD__)
150 const ip::address multicast_address_v6
= ip::make_address("ff02::1%lo0", ec
);
151 #else // (defined(__MACH__) && defined(__APPLE__))
152 // || defined(__FreeBSD__)
153 // || defined(__NetBSD__)
154 // || defined(__OpenBSD__)
155 const ip::address multicast_address_v6
= ip::make_address("ff01::1", ec
);
156 #endif // (defined(__MACH__) && defined(__APPLE__))
157 // || defined(__FreeBSD__)
158 // || defined(__NetBSD__)
159 // || defined(__OpenBSD__)
160 BOOST_ASIO_CHECK(!have_v6
|| !ec
);
166 ip::multicast::join_group
join_group(multicast_address_v4
);
167 sock_v4
.set_option(join_group
, ec
);
168 BOOST_ASIO_CHECK_MESSAGE(!ec
|| ec
== error::no_such_device
,
169 ec
.value() << ", " << ec
.message());
173 // leave_group class.
175 ip::multicast::leave_group
leave_group(multicast_address_v4
);
176 sock_v4
.set_option(leave_group
, ec
);
177 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
183 ip::multicast::join_group
join_group(multicast_address_v6
);
184 sock_v6
.set_option(join_group
, ec
);
185 BOOST_ASIO_CHECK_MESSAGE(!ec
|| ec
== error::no_such_device
,
186 ec
.value() << ", " << ec
.message());
190 // leave_group class.
192 ip::multicast::leave_group
leave_group(multicast_address_v6
);
193 sock_v6
.set_option(leave_group
, ec
);
194 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
198 // outbound_interface class.
202 ip::multicast::outbound_interface
outbound_interface(
203 ip::address_v4::loopback());
204 sock_v4
.set_option(outbound_interface
, ec
);
205 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
211 ip::multicast::outbound_interface
outbound_interface(if_nametoindex("lo0"));
213 ip::multicast::outbound_interface
outbound_interface(1);
215 sock_v6
.set_option(outbound_interface
, ec
);
216 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
223 ip::multicast::hops
hops1(1);
224 BOOST_ASIO_CHECK(hops1
.value() == 1);
225 sock_v4
.set_option(hops1
, ec
);
226 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
228 ip::multicast::hops hops2
;
229 sock_v4
.get_option(hops2
, ec
);
230 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
231 BOOST_ASIO_CHECK(hops2
.value() == 1);
233 ip::multicast::hops
hops3(0);
234 BOOST_ASIO_CHECK(hops3
.value() == 0);
235 sock_v4
.set_option(hops3
, ec
);
236 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
238 ip::multicast::hops hops4
;
239 sock_v4
.get_option(hops4
, ec
);
240 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
241 BOOST_ASIO_CHECK(hops4
.value() == 0);
246 ip::multicast::hops
hops1(1);
247 BOOST_ASIO_CHECK(hops1
.value() == 1);
248 sock_v6
.set_option(hops1
, ec
);
249 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
251 ip::multicast::hops hops2
;
252 sock_v6
.get_option(hops2
, ec
);
253 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
254 BOOST_ASIO_CHECK(hops2
.value() == 1);
256 ip::multicast::hops
hops3(0);
257 BOOST_ASIO_CHECK(hops3
.value() == 0);
258 sock_v6
.set_option(hops3
, ec
);
259 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
261 ip::multicast::hops hops4
;
262 sock_v6
.get_option(hops4
, ec
);
263 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
264 BOOST_ASIO_CHECK(hops4
.value() == 0);
267 // enable_loopback class.
271 ip::multicast::enable_loopback
enable_loopback1(true);
272 BOOST_ASIO_CHECK(enable_loopback1
.value());
273 BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1
));
274 BOOST_ASIO_CHECK(!!enable_loopback1
);
275 sock_v4
.set_option(enable_loopback1
, ec
);
276 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
277 // Option is not supported under Windows CE.
278 BOOST_ASIO_CHECK_MESSAGE(ec
== boost::asio::error::no_protocol_option
,
279 ec
.value() << ", " << ec
.message());
280 #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
281 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
282 #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
284 ip::multicast::enable_loopback enable_loopback2
;
285 sock_v4
.get_option(enable_loopback2
, ec
);
286 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
287 // Not supported under Windows CE but can get value.
288 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
289 #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
290 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
291 BOOST_ASIO_CHECK(enable_loopback2
.value());
292 BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2
));
293 BOOST_ASIO_CHECK(!!enable_loopback2
);
294 #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
296 ip::multicast::enable_loopback
enable_loopback3(false);
297 BOOST_ASIO_CHECK(!enable_loopback3
.value());
298 BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3
));
299 BOOST_ASIO_CHECK(!enable_loopback3
);
300 sock_v4
.set_option(enable_loopback3
, ec
);
301 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
302 // Option is not supported under Windows CE.
303 BOOST_ASIO_CHECK_MESSAGE(ec
== boost::asio::error::no_protocol_option
,
304 ec
.value() << ", " << ec
.message());
305 #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
306 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
307 #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
309 ip::multicast::enable_loopback enable_loopback4
;
310 sock_v4
.get_option(enable_loopback4
, ec
);
311 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
312 // Not supported under Windows CE but can get value.
313 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
314 #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
315 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
316 BOOST_ASIO_CHECK(!enable_loopback4
.value());
317 BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4
));
318 BOOST_ASIO_CHECK(!enable_loopback4
);
319 #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
324 ip::multicast::enable_loopback
enable_loopback1(true);
325 BOOST_ASIO_CHECK(enable_loopback1
.value());
326 BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1
));
327 BOOST_ASIO_CHECK(!!enable_loopback1
);
328 sock_v6
.set_option(enable_loopback1
, ec
);
329 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
331 ip::multicast::enable_loopback enable_loopback2
;
332 sock_v6
.get_option(enable_loopback2
, ec
);
333 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
334 BOOST_ASIO_CHECK(enable_loopback2
.value());
335 BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2
));
336 BOOST_ASIO_CHECK(!!enable_loopback2
);
338 ip::multicast::enable_loopback
enable_loopback3(false);
339 BOOST_ASIO_CHECK(!enable_loopback3
.value());
340 BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3
));
341 BOOST_ASIO_CHECK(!enable_loopback3
);
342 sock_v6
.set_option(enable_loopback3
, ec
);
343 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
345 ip::multicast::enable_loopback enable_loopback4
;
346 sock_v6
.get_option(enable_loopback4
, ec
);
347 BOOST_ASIO_CHECK_MESSAGE(!ec
, ec
.value() << ", " << ec
.message());
348 BOOST_ASIO_CHECK(!enable_loopback4
.value());
349 BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4
));
350 BOOST_ASIO_CHECK(!enable_loopback4
);
354 } // namespace ip_multicast_runtime
356 //------------------------------------------------------------------------------
358 BOOST_ASIO_TEST_SUITE
361 BOOST_ASIO_TEST_CASE(ip_multicast_compile::test
)
362 BOOST_ASIO_TEST_CASE(ip_multicast_runtime::test
)