]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // multicast.cpp | |
3 | // ~~~~~~~~~~~~~ | |
4 | // | |
b32b8144 | 5 | // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
6 | // |
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) | |
9 | // | |
10 | ||
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) | |
15 | ||
16 | // Test that header file is self-contained. | |
17 | #include <boost/asio/ip/multicast.hpp> | |
18 | ||
b32b8144 | 19 | #include <boost/asio/io_context.hpp> |
7c673cae FG |
20 | #include <boost/asio/ip/udp.hpp> |
21 | #include "../unit_test.hpp" | |
22 | ||
23 | //------------------------------------------------------------------------------ | |
24 | ||
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. | |
29 | ||
30 | namespace ip_multicast_compile { | |
31 | ||
32 | void test() | |
33 | { | |
34 | using namespace boost::asio; | |
35 | namespace ip = boost::asio::ip; | |
36 | ||
37 | try | |
38 | { | |
b32b8144 FG |
39 | io_context ioc; |
40 | ip::udp::socket sock(ioc); | |
7c673cae FG |
41 | const ip::address address; |
42 | const ip::address_v4 address_v4; | |
43 | const ip::address_v6 address_v6; | |
44 | ||
45 | // join_group class. | |
46 | ||
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); | |
54 | ||
55 | // leave_group class. | |
56 | ||
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); | |
64 | ||
65 | // outbound_interface class. | |
66 | ||
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); | |
71 | ||
72 | // hops class. | |
73 | ||
74 | ip::multicast::hops hops1(1024); | |
75 | sock.set_option(hops1); | |
76 | ip::multicast::hops hops2; | |
77 | sock.get_option(hops2); | |
78 | hops1 = 1; | |
79 | (void)static_cast<int>(hops1.value()); | |
80 | ||
81 | // enable_loopback class. | |
82 | ||
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()); | |
91 | } | |
92 | catch (std::exception&) | |
93 | { | |
94 | } | |
95 | } | |
96 | ||
97 | } // namespace ip_multicast_compile | |
98 | ||
99 | //------------------------------------------------------------------------------ | |
100 | ||
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. | |
105 | ||
106 | namespace ip_multicast_runtime { | |
107 | ||
108 | #if defined(__hpux) | |
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) | |
113 | ||
114 | void test() | |
115 | { | |
116 | using namespace boost::asio; | |
117 | namespace ip = boost::asio::ip; | |
118 | ||
b32b8144 | 119 | io_context ioc; |
7c673cae FG |
120 | boost::system::error_code ec; |
121 | ||
122 | ip::udp::endpoint ep_v4(ip::address_v4::loopback(), 0); | |
b32b8144 | 123 | ip::udp::socket sock_v4(ioc); |
7c673cae FG |
124 | sock_v4.open(ep_v4.protocol(), ec); |
125 | sock_v4.bind(ep_v4, ec); | |
126 | bool have_v4 = !ec; | |
127 | ||
128 | ip::udp::endpoint ep_v6(ip::address_v6::loopback(), 0); | |
b32b8144 | 129 | ip::udp::socket sock_v6(ioc); |
7c673cae FG |
130 | sock_v6.open(ep_v6.protocol(), ec); |
131 | sock_v6.bind(ep_v6, ec); | |
132 | bool have_v6 = !ec; | |
133 | ||
134 | BOOST_ASIO_CHECK(have_v4 || have_v6); | |
135 | ||
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. | |
b32b8144 | 140 | const ip::address multicast_address_v4 = ip::make_address("239.0.0.4", ec); |
7c673cae | 141 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
b32b8144 | 142 | const ip::address multicast_address_v4 = ip::make_address("239.255.0.1", ec); |
7c673cae FG |
143 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
144 | BOOST_ASIO_CHECK(!have_v4 || !ec); | |
145 | ||
146 | #if (defined(__MACH__) && defined(__APPLE__)) \ | |
147 | || defined(__FreeBSD__) \ | |
148 | || defined(__NetBSD__) \ | |
149 | || defined(__OpenBSD__) | |
b32b8144 | 150 | const ip::address multicast_address_v6 = ip::make_address("ff02::1%lo0", ec); |
7c673cae FG |
151 | #else // (defined(__MACH__) && defined(__APPLE__)) |
152 | // || defined(__FreeBSD__) | |
153 | // || defined(__NetBSD__) | |
154 | // || defined(__OpenBSD__) | |
b32b8144 | 155 | const ip::address multicast_address_v6 = ip::make_address("ff01::1", ec); |
7c673cae FG |
156 | #endif // (defined(__MACH__) && defined(__APPLE__)) |
157 | // || defined(__FreeBSD__) | |
158 | // || defined(__NetBSD__) | |
159 | // || defined(__OpenBSD__) | |
160 | BOOST_ASIO_CHECK(!have_v6 || !ec); | |
161 | ||
162 | // join_group class. | |
163 | ||
164 | if (have_v4) | |
165 | { | |
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()); | |
170 | ||
171 | if (!ec) | |
172 | { | |
173 | // leave_group class. | |
174 | ||
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()); | |
178 | } | |
179 | } | |
180 | ||
181 | if (have_v6) | |
182 | { | |
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()); | |
187 | ||
188 | if (!ec) | |
189 | { | |
190 | // leave_group class. | |
191 | ||
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()); | |
195 | } | |
196 | } | |
197 | ||
198 | // outbound_interface class. | |
199 | ||
200 | if (have_v4) | |
201 | { | |
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()); | |
206 | } | |
207 | ||
208 | if (have_v6) | |
209 | { | |
210 | #if defined(__hpux) | |
211 | ip::multicast::outbound_interface outbound_interface(if_nametoindex("lo0")); | |
212 | #else | |
213 | ip::multicast::outbound_interface outbound_interface(1); | |
214 | #endif | |
215 | sock_v6.set_option(outbound_interface, ec); | |
216 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); | |
217 | } | |
218 | ||
219 | // hops class. | |
220 | ||
221 | if (have_v4) | |
222 | { | |
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()); | |
227 | ||
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); | |
232 | ||
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()); | |
237 | ||
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); | |
242 | } | |
243 | ||
244 | if (have_v6) | |
245 | { | |
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()); | |
250 | ||
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); | |
255 | ||
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()); | |
260 | ||
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); | |
265 | } | |
266 | ||
267 | // enable_loopback class. | |
268 | ||
269 | if (have_v4) | |
270 | { | |
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) | |
283 | ||
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) | |
295 | ||
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) | |
308 | ||
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) | |
320 | } | |
321 | ||
322 | if (have_v6) | |
323 | { | |
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()); | |
330 | ||
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); | |
337 | ||
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()); | |
344 | ||
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); | |
351 | } | |
352 | } | |
353 | ||
354 | } // namespace ip_multicast_runtime | |
355 | ||
356 | //------------------------------------------------------------------------------ | |
357 | ||
358 | BOOST_ASIO_TEST_SUITE | |
359 | ( | |
360 | "ip/multicast", | |
361 | BOOST_ASIO_TEST_CASE(ip_multicast_compile::test) | |
362 | BOOST_ASIO_TEST_CASE(ip_multicast_runtime::test) | |
363 | ) |