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
30namespace ip_multicast_compile {
31
32void 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(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
106namespace 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.
111extern "C" unsigned int if_nametoindex(const char*);
112#endif // defined(__hpux)
113
114void 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(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);
129 ip::udp::socket sock_v6(ios);
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.
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("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("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(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(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(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(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(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(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(hops1, ec);
230 BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
231
232 ip::multicast::hops hops2;
233 sock_v4.get_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(hops3, ec);
240 BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
241
242 ip::multicast::hops hops4;
243 sock_v4.get_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(hops1, ec);
253 BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
254
255 ip::multicast::hops hops2;
256 sock_v6.get_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(hops3, ec);
263 BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
264
265 ip::multicast::hops hops4;
266 sock_v6.get_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(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(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(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(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(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(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(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(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
362BOOST_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