1 | // |
2 | // multicast.cpp |
3 | // ~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
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 | |
19 | #include <boost/asio/io_service.hpp> |
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 | { |
39 | io_service ios; |
40 | ip::udp::socket sock(ios); |
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(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(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 | |
119 | io_service ios; |
120 | boost::system::error_code ec; |
121 | |
122 | ip::udp::endpoint ep_v4(ip::address_v4::loopback(), 0); |
123 | ip::udp::socket sock_v4(ios); |
124 | sock_v4.open(protocol: ep_v4.protocol(), ec); |
125 | sock_v4.bind(endpoint: ep_v4, ec); |
126 | bool have_v4 = !ec; |
127 | |
128 | ip::udp::endpoint ep_v6(ip::address_v6::loopback(), 0); |
129 | ip::udp::socket sock_v6(ios); |
130 | sock_v6.open(protocol: ep_v6.protocol(), ec); |
131 | sock_v6.bind(endpoint: 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. |
140 | const ip::address multicast_address_v4 = |
141 | ip::address::from_string("239.0.0.4" , ec); |
142 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
143 | const ip::address multicast_address_v4 = |
144 | ip::address::from_string(str: "239.255.0.1" , ec); |
145 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
146 | BOOST_ASIO_CHECK(!have_v4 || !ec); |
147 | |
148 | #if (defined(__MACH__) && defined(__APPLE__)) \ |
149 | || defined(__FreeBSD__) \ |
150 | || defined(__NetBSD__) \ |
151 | || defined(__OpenBSD__) |
152 | const ip::address multicast_address_v6 = |
153 | ip::address::from_string("ff02::1%lo0" , ec); |
154 | #else // (defined(__MACH__) && defined(__APPLE__)) |
155 | // || defined(__FreeBSD__) |
156 | // || defined(__NetBSD__) |
157 | // || defined(__OpenBSD__) |
158 | const ip::address multicast_address_v6 = |
159 | ip::address::from_string(str: "ff01::1" , ec); |
160 | #endif // (defined(__MACH__) && defined(__APPLE__)) |
161 | // || defined(__FreeBSD__) |
162 | // || defined(__NetBSD__) |
163 | // || defined(__OpenBSD__) |
164 | BOOST_ASIO_CHECK(!have_v6 || !ec); |
165 | |
166 | // join_group class. |
167 | |
168 | if (have_v4) |
169 | { |
170 | ip::multicast::join_group join_group(multicast_address_v4); |
171 | sock_v4.set_option(option: join_group, ec); |
172 | BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device, |
173 | ec.value() << ", " << ec.message()); |
174 | |
175 | if (!ec) |
176 | { |
177 | // leave_group class. |
178 | |
179 | ip::multicast::leave_group leave_group(multicast_address_v4); |
180 | sock_v4.set_option(option: leave_group, ec); |
181 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
182 | } |
183 | } |
184 | |
185 | if (have_v6) |
186 | { |
187 | ip::multicast::join_group join_group(multicast_address_v6); |
188 | sock_v6.set_option(option: join_group, ec); |
189 | BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device, |
190 | ec.value() << ", " << ec.message()); |
191 | |
192 | if (!ec) |
193 | { |
194 | // leave_group class. |
195 | |
196 | ip::multicast::leave_group leave_group(multicast_address_v6); |
197 | sock_v6.set_option(option: leave_group, ec); |
198 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
199 | } |
200 | } |
201 | |
202 | // outbound_interface class. |
203 | |
204 | if (have_v4) |
205 | { |
206 | ip::multicast::outbound_interface outbound_interface( |
207 | ip::address_v4::loopback()); |
208 | sock_v4.set_option(option: outbound_interface, ec); |
209 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
210 | } |
211 | |
212 | if (have_v6) |
213 | { |
214 | #if defined(__hpux) |
215 | ip::multicast::outbound_interface outbound_interface(if_nametoindex("lo0" )); |
216 | #else |
217 | ip::multicast::outbound_interface outbound_interface(1); |
218 | #endif |
219 | sock_v6.set_option(option: outbound_interface, ec); |
220 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
221 | } |
222 | |
223 | // hops class. |
224 | |
225 | if (have_v4) |
226 | { |
227 | ip::multicast::hops hops1(1); |
228 | BOOST_ASIO_CHECK(hops1.value() == 1); |
229 | sock_v4.set_option(option: hops1, ec); |
230 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
231 | |
232 | ip::multicast::hops hops2; |
233 | sock_v4.get_option(option&: hops2, ec); |
234 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
235 | BOOST_ASIO_CHECK(hops2.value() == 1); |
236 | |
237 | ip::multicast::hops hops3(0); |
238 | BOOST_ASIO_CHECK(hops3.value() == 0); |
239 | sock_v4.set_option(option: hops3, ec); |
240 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
241 | |
242 | ip::multicast::hops hops4; |
243 | sock_v4.get_option(option&: hops4, ec); |
244 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
245 | BOOST_ASIO_CHECK(hops4.value() == 0); |
246 | } |
247 | |
248 | if (have_v6) |
249 | { |
250 | ip::multicast::hops hops1(1); |
251 | BOOST_ASIO_CHECK(hops1.value() == 1); |
252 | sock_v6.set_option(option: hops1, ec); |
253 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
254 | |
255 | ip::multicast::hops hops2; |
256 | sock_v6.get_option(option&: hops2, ec); |
257 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
258 | BOOST_ASIO_CHECK(hops2.value() == 1); |
259 | |
260 | ip::multicast::hops hops3(0); |
261 | BOOST_ASIO_CHECK(hops3.value() == 0); |
262 | sock_v6.set_option(option: hops3, ec); |
263 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
264 | |
265 | ip::multicast::hops hops4; |
266 | sock_v6.get_option(option&: hops4, ec); |
267 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
268 | BOOST_ASIO_CHECK(hops4.value() == 0); |
269 | } |
270 | |
271 | // enable_loopback class. |
272 | |
273 | if (have_v4) |
274 | { |
275 | ip::multicast::enable_loopback enable_loopback1(true); |
276 | BOOST_ASIO_CHECK(enable_loopback1.value()); |
277 | BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1)); |
278 | BOOST_ASIO_CHECK(!!enable_loopback1); |
279 | sock_v4.set_option(option: enable_loopback1, ec); |
280 | #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
281 | // Option is not supported under Windows CE. |
282 | BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, |
283 | ec.value() << ", " << ec.message()); |
284 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
285 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
286 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
287 | |
288 | ip::multicast::enable_loopback enable_loopback2; |
289 | sock_v4.get_option(option&: enable_loopback2, ec); |
290 | #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
291 | // Not supported under Windows CE but can get value. |
292 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
293 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
294 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
295 | BOOST_ASIO_CHECK(enable_loopback2.value()); |
296 | BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2)); |
297 | BOOST_ASIO_CHECK(!!enable_loopback2); |
298 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
299 | |
300 | ip::multicast::enable_loopback enable_loopback3(false); |
301 | BOOST_ASIO_CHECK(!enable_loopback3.value()); |
302 | BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3)); |
303 | BOOST_ASIO_CHECK(!enable_loopback3); |
304 | sock_v4.set_option(option: enable_loopback3, ec); |
305 | #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
306 | // Option is not supported under Windows CE. |
307 | BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, |
308 | ec.value() << ", " << ec.message()); |
309 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
310 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
311 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
312 | |
313 | ip::multicast::enable_loopback enable_loopback4; |
314 | sock_v4.get_option(option&: enable_loopback4, ec); |
315 | #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
316 | // Not supported under Windows CE but can get value. |
317 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
318 | #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
319 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
320 | BOOST_ASIO_CHECK(!enable_loopback4.value()); |
321 | BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4)); |
322 | BOOST_ASIO_CHECK(!enable_loopback4); |
323 | #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) |
324 | } |
325 | |
326 | if (have_v6) |
327 | { |
328 | ip::multicast::enable_loopback enable_loopback1(true); |
329 | BOOST_ASIO_CHECK(enable_loopback1.value()); |
330 | BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1)); |
331 | BOOST_ASIO_CHECK(!!enable_loopback1); |
332 | sock_v6.set_option(option: enable_loopback1, ec); |
333 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
334 | |
335 | ip::multicast::enable_loopback enable_loopback2; |
336 | sock_v6.get_option(option&: enable_loopback2, ec); |
337 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
338 | BOOST_ASIO_CHECK(enable_loopback2.value()); |
339 | BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2)); |
340 | BOOST_ASIO_CHECK(!!enable_loopback2); |
341 | |
342 | ip::multicast::enable_loopback enable_loopback3(false); |
343 | BOOST_ASIO_CHECK(!enable_loopback3.value()); |
344 | BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3)); |
345 | BOOST_ASIO_CHECK(!enable_loopback3); |
346 | sock_v6.set_option(option: enable_loopback3, ec); |
347 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
348 | |
349 | ip::multicast::enable_loopback enable_loopback4; |
350 | sock_v6.get_option(option&: enable_loopback4, ec); |
351 | BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); |
352 | BOOST_ASIO_CHECK(!enable_loopback4.value()); |
353 | BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4)); |
354 | BOOST_ASIO_CHECK(!enable_loopback4); |
355 | } |
356 | } |
357 | |
358 | } // namespace ip_multicast_runtime |
359 | |
360 | //------------------------------------------------------------------------------ |
361 | |
362 | BOOST_ASIO_TEST_SUITE |
363 | ( |
364 | "ip/multicast" , |
365 | BOOST_ASIO_TEST_CASE(ip_multicast_compile::test) |
366 | BOOST_ASIO_TEST_CASE(ip_multicast_runtime::test) |
367 | ) |
368 | |