multicast.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // multicast.cpp
  3. // ~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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. // Disable autolinking for unit tests.
  11. #if !defined(BOOST_ALL_NO_LIB)
  12. #define BOOST_ALL_NO_LIB 1
  13. #endif // !defined(BOOST_ALL_NO_LIB)
  14. // Test that header file is self-contained.
  15. #include <boost/asio/ip/multicast.hpp>
  16. #include <boost/asio/io_context.hpp>
  17. #include <boost/asio/ip/udp.hpp>
  18. #include "../unit_test.hpp"
  19. //------------------------------------------------------------------------------
  20. // ip_multicast_compile test
  21. // ~~~~~~~~~~~~~~~~~~~~~~~~~
  22. // The following test checks that all nested classes, enums and constants in
  23. // ip::multicast compile and link correctly. Runtime failures are ignored.
  24. namespace ip_multicast_compile {
  25. void test()
  26. {
  27. using namespace boost::asio;
  28. namespace ip = boost::asio::ip;
  29. try
  30. {
  31. io_context ioc;
  32. ip::udp::socket sock(ioc);
  33. const ip::address address;
  34. const ip::address_v4 address_v4;
  35. const ip::address_v6 address_v6;
  36. // join_group class.
  37. ip::multicast::join_group join_group1;
  38. ip::multicast::join_group join_group2(address);
  39. ip::multicast::join_group join_group3(address_v4);
  40. ip::multicast::join_group join_group4(address_v4, address_v4);
  41. ip::multicast::join_group join_group5(address_v6);
  42. ip::multicast::join_group join_group6(address_v6, 1);
  43. sock.set_option(join_group6);
  44. // leave_group class.
  45. ip::multicast::leave_group leave_group1;
  46. ip::multicast::leave_group leave_group2(address);
  47. ip::multicast::leave_group leave_group3(address_v4);
  48. ip::multicast::leave_group leave_group4(address_v4, address_v4);
  49. ip::multicast::leave_group leave_group5(address_v6);
  50. ip::multicast::leave_group leave_group6(address_v6, 1);
  51. sock.set_option(leave_group6);
  52. // outbound_interface class.
  53. ip::multicast::outbound_interface outbound_interface1;
  54. ip::multicast::outbound_interface outbound_interface2(address_v4);
  55. ip::multicast::outbound_interface outbound_interface3(1);
  56. sock.set_option(outbound_interface3);
  57. // hops class.
  58. ip::multicast::hops hops1(1024);
  59. sock.set_option(hops1);
  60. ip::multicast::hops hops2;
  61. sock.get_option(hops2);
  62. hops1 = 1;
  63. (void)static_cast<int>(hops1.value());
  64. // enable_loopback class.
  65. ip::multicast::enable_loopback enable_loopback1(true);
  66. sock.set_option(enable_loopback1);
  67. ip::multicast::enable_loopback enable_loopback2;
  68. sock.get_option(enable_loopback2);
  69. enable_loopback1 = true;
  70. (void)static_cast<bool>(enable_loopback1);
  71. (void)static_cast<bool>(!enable_loopback1);
  72. (void)static_cast<bool>(enable_loopback1.value());
  73. }
  74. catch (std::exception&)
  75. {
  76. }
  77. }
  78. } // namespace ip_multicast_compile
  79. //------------------------------------------------------------------------------
  80. // ip_multicast_runtime test
  81. // ~~~~~~~~~~~~~~~~~~~~~~~~~
  82. // The following test checks the runtime operation of the socket options defined
  83. // in the ip::multicast namespace.
  84. namespace ip_multicast_runtime {
  85. #if defined(__hpux)
  86. // HP-UX doesn't declare this function extern "C", so it is declared again here
  87. // to avoid a linker error about an undefined symbol.
  88. extern "C" unsigned int if_nametoindex(const char*);
  89. #endif // defined(__hpux)
  90. void test()
  91. {
  92. using namespace boost::asio;
  93. namespace ip = boost::asio::ip;
  94. io_context ioc;
  95. boost::system::error_code ec;
  96. ip::udp::endpoint ep_v4(ip::address_v4::loopback(), 0);
  97. ip::udp::socket sock_v4(ioc);
  98. sock_v4.open(ep_v4.protocol(), ec);
  99. sock_v4.bind(ep_v4, ec);
  100. bool have_v4 = !ec;
  101. ip::udp::endpoint ep_v6(ip::address_v6::loopback(), 0);
  102. ip::udp::socket sock_v6(ioc);
  103. sock_v6.open(ep_v6.protocol(), ec);
  104. sock_v6.bind(ep_v6, ec);
  105. bool have_v6 = !ec;
  106. BOOST_ASIO_CHECK(have_v4 || have_v6);
  107. #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  108. // Windows CE seems to have problems with some multicast group addresses.
  109. // The following address works on CE, but as it is not a private multicast
  110. // address it will not be used on other platforms.
  111. const ip::address multicast_address_v4 = ip::make_address("239.0.0.4", ec);
  112. #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  113. const ip::address multicast_address_v4 = ip::make_address("239.255.0.1", ec);
  114. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  115. BOOST_ASIO_CHECK(!have_v4 || !ec);
  116. #if (defined(__MACH__) && defined(__APPLE__)) \
  117. || defined(__FreeBSD__) \
  118. || defined(__NetBSD__) \
  119. || defined(__OpenBSD__)
  120. const ip::address multicast_address_v6 = ip::make_address("ff02::1%lo0", ec);
  121. #else // (defined(__MACH__) && defined(__APPLE__))
  122. // || defined(__FreeBSD__)
  123. // || defined(__NetBSD__)
  124. // || defined(__OpenBSD__)
  125. const ip::address multicast_address_v6 = ip::make_address("ff01::1", ec);
  126. #endif // (defined(__MACH__) && defined(__APPLE__))
  127. // || defined(__FreeBSD__)
  128. // || defined(__NetBSD__)
  129. // || defined(__OpenBSD__)
  130. BOOST_ASIO_CHECK(!have_v6 || !ec);
  131. // join_group class.
  132. if (have_v4)
  133. {
  134. ip::multicast::join_group join_group(multicast_address_v4);
  135. sock_v4.set_option(join_group, ec);
  136. BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device,
  137. ec.value() << ", " << ec.message());
  138. if (!ec)
  139. {
  140. // leave_group class.
  141. ip::multicast::leave_group leave_group(multicast_address_v4);
  142. sock_v4.set_option(leave_group, ec);
  143. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  144. }
  145. }
  146. if (have_v6)
  147. {
  148. ip::multicast::join_group join_group(multicast_address_v6);
  149. sock_v6.set_option(join_group, ec);
  150. BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device,
  151. ec.value() << ", " << ec.message());
  152. if (!ec)
  153. {
  154. // leave_group class.
  155. ip::multicast::leave_group leave_group(multicast_address_v6);
  156. sock_v6.set_option(leave_group, ec);
  157. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  158. }
  159. }
  160. // outbound_interface class.
  161. if (have_v4)
  162. {
  163. ip::multicast::outbound_interface outbound_interface(
  164. ip::address_v4::loopback());
  165. sock_v4.set_option(outbound_interface, ec);
  166. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  167. }
  168. if (have_v6)
  169. {
  170. #if defined(__hpux)
  171. ip::multicast::outbound_interface outbound_interface(if_nametoindex("lo0"));
  172. #else
  173. ip::multicast::outbound_interface outbound_interface(1);
  174. #endif
  175. sock_v6.set_option(outbound_interface, ec);
  176. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  177. }
  178. // hops class.
  179. if (have_v4)
  180. {
  181. ip::multicast::hops hops1(1);
  182. BOOST_ASIO_CHECK(hops1.value() == 1);
  183. sock_v4.set_option(hops1, ec);
  184. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  185. ip::multicast::hops hops2;
  186. sock_v4.get_option(hops2, ec);
  187. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  188. BOOST_ASIO_CHECK(hops2.value() == 1);
  189. ip::multicast::hops hops3(0);
  190. BOOST_ASIO_CHECK(hops3.value() == 0);
  191. sock_v4.set_option(hops3, ec);
  192. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  193. ip::multicast::hops hops4;
  194. sock_v4.get_option(hops4, ec);
  195. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  196. BOOST_ASIO_CHECK(hops4.value() == 0);
  197. }
  198. if (have_v6)
  199. {
  200. ip::multicast::hops hops1(1);
  201. BOOST_ASIO_CHECK(hops1.value() == 1);
  202. sock_v6.set_option(hops1, ec);
  203. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  204. ip::multicast::hops hops2;
  205. sock_v6.get_option(hops2, ec);
  206. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  207. BOOST_ASIO_CHECK(hops2.value() == 1);
  208. ip::multicast::hops hops3(0);
  209. BOOST_ASIO_CHECK(hops3.value() == 0);
  210. sock_v6.set_option(hops3, ec);
  211. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  212. ip::multicast::hops hops4;
  213. sock_v6.get_option(hops4, ec);
  214. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  215. BOOST_ASIO_CHECK(hops4.value() == 0);
  216. }
  217. // enable_loopback class.
  218. if (have_v4)
  219. {
  220. ip::multicast::enable_loopback enable_loopback1(true);
  221. BOOST_ASIO_CHECK(enable_loopback1.value());
  222. BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1));
  223. BOOST_ASIO_CHECK(!!enable_loopback1);
  224. sock_v4.set_option(enable_loopback1, ec);
  225. #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  226. // Option is not supported under Windows CE.
  227. BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option,
  228. ec.value() << ", " << ec.message());
  229. #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  230. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  231. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  232. ip::multicast::enable_loopback enable_loopback2;
  233. sock_v4.get_option(enable_loopback2, ec);
  234. #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  235. // Not supported under Windows CE but can get value.
  236. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  237. #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  238. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  239. BOOST_ASIO_CHECK(enable_loopback2.value());
  240. BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2));
  241. BOOST_ASIO_CHECK(!!enable_loopback2);
  242. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  243. ip::multicast::enable_loopback enable_loopback3(false);
  244. BOOST_ASIO_CHECK(!enable_loopback3.value());
  245. BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3));
  246. BOOST_ASIO_CHECK(!enable_loopback3);
  247. sock_v4.set_option(enable_loopback3, ec);
  248. #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  249. // Option is not supported under Windows CE.
  250. BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option,
  251. ec.value() << ", " << ec.message());
  252. #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  253. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  254. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  255. ip::multicast::enable_loopback enable_loopback4;
  256. sock_v4.get_option(enable_loopback4, ec);
  257. #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  258. // Not supported under Windows CE but can get value.
  259. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  260. #else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  261. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  262. BOOST_ASIO_CHECK(!enable_loopback4.value());
  263. BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4));
  264. BOOST_ASIO_CHECK(!enable_loopback4);
  265. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  266. }
  267. if (have_v6)
  268. {
  269. ip::multicast::enable_loopback enable_loopback1(true);
  270. BOOST_ASIO_CHECK(enable_loopback1.value());
  271. BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1));
  272. BOOST_ASIO_CHECK(!!enable_loopback1);
  273. sock_v6.set_option(enable_loopback1, ec);
  274. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  275. ip::multicast::enable_loopback enable_loopback2;
  276. sock_v6.get_option(enable_loopback2, ec);
  277. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  278. BOOST_ASIO_CHECK(enable_loopback2.value());
  279. BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2));
  280. BOOST_ASIO_CHECK(!!enable_loopback2);
  281. ip::multicast::enable_loopback enable_loopback3(false);
  282. BOOST_ASIO_CHECK(!enable_loopback3.value());
  283. BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3));
  284. BOOST_ASIO_CHECK(!enable_loopback3);
  285. sock_v6.set_option(enable_loopback3, ec);
  286. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  287. ip::multicast::enable_loopback enable_loopback4;
  288. sock_v6.get_option(enable_loopback4, ec);
  289. BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message());
  290. BOOST_ASIO_CHECK(!enable_loopback4.value());
  291. BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4));
  292. BOOST_ASIO_CHECK(!enable_loopback4);
  293. }
  294. }
  295. } // namespace ip_multicast_runtime
  296. //------------------------------------------------------------------------------
  297. BOOST_ASIO_TEST_SUITE
  298. (
  299. "ip/multicast",
  300. BOOST_ASIO_TEST_CASE(ip_multicast_compile::test)
  301. BOOST_ASIO_TEST_CASE(ip_multicast_runtime::test)
  302. )