socket_option.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //
  2. // socket_option.hpp
  3. // ~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 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. #ifndef BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP
  11. #define BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <cstddef>
  18. #include <cstring>
  19. #include <boost/config.hpp>
  20. #include <boost/throw_exception.hpp>
  21. #include <boost/asio/detail/pop_options.hpp>
  22. #include <boost/asio/ip/address.hpp>
  23. #include <boost/asio/detail/socket_ops.hpp>
  24. #include <boost/asio/detail/socket_types.hpp>
  25. namespace boost {
  26. namespace asio {
  27. namespace ip {
  28. namespace detail {
  29. namespace socket_option {
  30. // Helper template for implementing multicast enable loopback options.
  31. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
  32. class multicast_enable_loopback
  33. {
  34. public:
  35. #if defined(__sun) || defined(__osf__)
  36. typedef unsigned char ipv4_value_type;
  37. typedef unsigned char ipv6_value_type;
  38. #elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__)
  39. typedef unsigned char ipv4_value_type;
  40. typedef unsigned int ipv6_value_type;
  41. #else
  42. typedef int ipv4_value_type;
  43. typedef int ipv6_value_type;
  44. #endif
  45. // Default constructor.
  46. multicast_enable_loopback()
  47. : ipv4_value_(0),
  48. ipv6_value_(0)
  49. {
  50. }
  51. // Construct with a specific option value.
  52. explicit multicast_enable_loopback(bool v)
  53. : ipv4_value_(v ? 1 : 0),
  54. ipv6_value_(v ? 1 : 0)
  55. {
  56. }
  57. // Set the value of the boolean.
  58. multicast_enable_loopback& operator=(bool v)
  59. {
  60. ipv4_value_ = v ? 1 : 0;
  61. ipv6_value_ = v ? 1 : 0;
  62. return *this;
  63. }
  64. // Get the current value of the boolean.
  65. bool value() const
  66. {
  67. return !!ipv4_value_;
  68. }
  69. // Convert to bool.
  70. operator bool() const
  71. {
  72. return !!ipv4_value_;
  73. }
  74. // Test for false.
  75. bool operator!() const
  76. {
  77. return !ipv4_value_;
  78. }
  79. // Get the level of the socket option.
  80. template <typename Protocol>
  81. int level(const Protocol& protocol) const
  82. {
  83. if (protocol.family() == PF_INET6)
  84. return IPv6_Level;
  85. return IPv4_Level;
  86. }
  87. // Get the name of the socket option.
  88. template <typename Protocol>
  89. int name(const Protocol& protocol) const
  90. {
  91. if (protocol.family() == PF_INET6)
  92. return IPv6_Name;
  93. return IPv4_Name;
  94. }
  95. // Get the address of the boolean data.
  96. template <typename Protocol>
  97. void* data(const Protocol& protocol)
  98. {
  99. if (protocol.family() == PF_INET6)
  100. return &ipv6_value_;
  101. return &ipv4_value_;
  102. }
  103. // Get the address of the boolean data.
  104. template <typename Protocol>
  105. const void* data(const Protocol& protocol) const
  106. {
  107. if (protocol.family() == PF_INET6)
  108. return &ipv6_value_;
  109. return &ipv4_value_;
  110. }
  111. // Get the size of the boolean data.
  112. template <typename Protocol>
  113. std::size_t size(const Protocol& protocol) const
  114. {
  115. if (protocol.family() == PF_INET6)
  116. return sizeof(ipv6_value_);
  117. return sizeof(ipv4_value_);
  118. }
  119. // Set the size of the boolean data.
  120. template <typename Protocol>
  121. void resize(const Protocol& protocol, std::size_t s)
  122. {
  123. if (protocol.family() == PF_INET6)
  124. {
  125. if (s != sizeof(ipv6_value_))
  126. {
  127. std::length_error ex("multicast_enable_loopback socket option resize");
  128. boost::throw_exception(ex);
  129. }
  130. ipv4_value_ = ipv6_value_ ? 1 : 0;
  131. }
  132. else
  133. {
  134. if (s != sizeof(ipv4_value_))
  135. {
  136. std::length_error ex("multicast_enable_loopback socket option resize");
  137. boost::throw_exception(ex);
  138. }
  139. ipv6_value_ = ipv4_value_ ? 1 : 0;
  140. }
  141. }
  142. private:
  143. ipv4_value_type ipv4_value_;
  144. ipv6_value_type ipv6_value_;
  145. };
  146. // Helper template for implementing unicast hops options.
  147. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
  148. class unicast_hops
  149. {
  150. public:
  151. // Default constructor.
  152. unicast_hops()
  153. : value_(0)
  154. {
  155. }
  156. // Construct with a specific option value.
  157. explicit unicast_hops(int v)
  158. : value_(v)
  159. {
  160. }
  161. // Set the value of the option.
  162. unicast_hops& operator=(int v)
  163. {
  164. value_ = v;
  165. return *this;
  166. }
  167. // Get the current value of the option.
  168. int value() const
  169. {
  170. return value_;
  171. }
  172. // Get the level of the socket option.
  173. template <typename Protocol>
  174. int level(const Protocol& protocol) const
  175. {
  176. if (protocol.family() == PF_INET6)
  177. return IPv6_Level;
  178. return IPv4_Level;
  179. }
  180. // Get the name of the socket option.
  181. template <typename Protocol>
  182. int name(const Protocol& protocol) const
  183. {
  184. if (protocol.family() == PF_INET6)
  185. return IPv6_Name;
  186. return IPv4_Name;
  187. }
  188. // Get the address of the data.
  189. template <typename Protocol>
  190. int* data(const Protocol&)
  191. {
  192. return &value_;
  193. }
  194. // Get the address of the data.
  195. template <typename Protocol>
  196. const int* data(const Protocol&) const
  197. {
  198. return &value_;
  199. }
  200. // Get the size of the data.
  201. template <typename Protocol>
  202. std::size_t size(const Protocol&) const
  203. {
  204. return sizeof(value_);
  205. }
  206. // Set the size of the data.
  207. template <typename Protocol>
  208. void resize(const Protocol&, std::size_t s)
  209. {
  210. if (s != sizeof(value_))
  211. {
  212. std::length_error ex("unicast hops socket option resize");
  213. boost::throw_exception(ex);
  214. }
  215. #if defined(__hpux)
  216. if (value_ < 0)
  217. value_ = value_ & 0xFF;
  218. #endif
  219. }
  220. private:
  221. int value_;
  222. };
  223. // Helper template for implementing multicast hops options.
  224. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
  225. class multicast_hops
  226. {
  227. public:
  228. #if defined(BOOST_WINDOWS) && defined(UNDER_CE)
  229. typedef int ipv4_value_type;
  230. #else
  231. typedef unsigned char ipv4_value_type;
  232. #endif
  233. typedef int ipv6_value_type;
  234. // Default constructor.
  235. multicast_hops()
  236. : ipv4_value_(0),
  237. ipv6_value_(0)
  238. {
  239. }
  240. // Construct with a specific option value.
  241. explicit multicast_hops(int v)
  242. {
  243. if (v < 0 || v > 255)
  244. {
  245. std::out_of_range ex("multicast hops value out of range");
  246. boost::throw_exception(ex);
  247. }
  248. ipv4_value_ = (ipv4_value_type)v;
  249. ipv6_value_ = v;
  250. }
  251. // Set the value of the option.
  252. multicast_hops& operator=(int v)
  253. {
  254. if (v < 0 || v > 255)
  255. {
  256. std::out_of_range ex("multicast hops value out of range");
  257. boost::throw_exception(ex);
  258. }
  259. ipv4_value_ = (ipv4_value_type)v;
  260. ipv6_value_ = v;
  261. return *this;
  262. }
  263. // Get the current value of the option.
  264. int value() const
  265. {
  266. return ipv6_value_;
  267. }
  268. // Get the level of the socket option.
  269. template <typename Protocol>
  270. int level(const Protocol& protocol) const
  271. {
  272. if (protocol.family() == PF_INET6)
  273. return IPv6_Level;
  274. return IPv4_Level;
  275. }
  276. // Get the name of the socket option.
  277. template <typename Protocol>
  278. int name(const Protocol& protocol) const
  279. {
  280. if (protocol.family() == PF_INET6)
  281. return IPv6_Name;
  282. return IPv4_Name;
  283. }
  284. // Get the address of the data.
  285. template <typename Protocol>
  286. void* data(const Protocol& protocol)
  287. {
  288. if (protocol.family() == PF_INET6)
  289. return &ipv6_value_;
  290. return &ipv4_value_;
  291. }
  292. // Get the address of the data.
  293. template <typename Protocol>
  294. const void* data(const Protocol& protocol) const
  295. {
  296. if (protocol.family() == PF_INET6)
  297. return &ipv6_value_;
  298. return &ipv4_value_;
  299. }
  300. // Get the size of the data.
  301. template <typename Protocol>
  302. std::size_t size(const Protocol& protocol) const
  303. {
  304. if (protocol.family() == PF_INET6)
  305. return sizeof(ipv6_value_);
  306. return sizeof(ipv4_value_);
  307. }
  308. // Set the size of the data.
  309. template <typename Protocol>
  310. void resize(const Protocol& protocol, std::size_t s)
  311. {
  312. if (protocol.family() == PF_INET6)
  313. {
  314. if (s != sizeof(ipv6_value_))
  315. {
  316. std::length_error ex("multicast hops socket option resize");
  317. boost::throw_exception(ex);
  318. }
  319. if (ipv6_value_ < 0)
  320. ipv4_value_ = 0;
  321. else if (ipv6_value_ > 255)
  322. ipv4_value_ = 255;
  323. else
  324. ipv4_value_ = (ipv4_value_type)ipv6_value_;
  325. }
  326. else
  327. {
  328. if (s != sizeof(ipv4_value_))
  329. {
  330. std::length_error ex("multicast hops socket option resize");
  331. boost::throw_exception(ex);
  332. }
  333. ipv6_value_ = ipv4_value_;
  334. }
  335. }
  336. private:
  337. ipv4_value_type ipv4_value_;
  338. ipv6_value_type ipv6_value_;
  339. };
  340. // Helper template for implementing ip_mreq-based options.
  341. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
  342. class multicast_request
  343. {
  344. public:
  345. // Default constructor.
  346. multicast_request()
  347. {
  348. ipv4_value_.imr_multiaddr.s_addr =
  349. boost::asio::detail::socket_ops::host_to_network_long(
  350. boost::asio::ip::address_v4::any().to_ulong());
  351. ipv4_value_.imr_interface.s_addr =
  352. boost::asio::detail::socket_ops::host_to_network_long(
  353. boost::asio::ip::address_v4::any().to_ulong());
  354. boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
  355. ipv6_value_.ipv6mr_multiaddr = tmp_addr;
  356. ipv6_value_.ipv6mr_interface = 0;
  357. }
  358. // Construct with multicast address only.
  359. explicit multicast_request(const boost::asio::ip::address& multicast_address)
  360. {
  361. if (multicast_address.is_v6())
  362. {
  363. ipv4_value_.imr_multiaddr.s_addr =
  364. boost::asio::detail::socket_ops::host_to_network_long(
  365. boost::asio::ip::address_v4::any().to_ulong());
  366. ipv4_value_.imr_interface.s_addr =
  367. boost::asio::detail::socket_ops::host_to_network_long(
  368. boost::asio::ip::address_v4::any().to_ulong());
  369. using namespace std; // For memcpy.
  370. boost::asio::ip::address_v6 ipv6_address = multicast_address.to_v6();
  371. boost::asio::ip::address_v6::bytes_type bytes = ipv6_address.to_bytes();
  372. memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16);
  373. ipv6_value_.ipv6mr_interface = 0;
  374. }
  375. else
  376. {
  377. ipv4_value_.imr_multiaddr.s_addr =
  378. boost::asio::detail::socket_ops::host_to_network_long(
  379. multicast_address.to_v4().to_ulong());
  380. ipv4_value_.imr_interface.s_addr =
  381. boost::asio::detail::socket_ops::host_to_network_long(
  382. boost::asio::ip::address_v4::any().to_ulong());
  383. boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
  384. ipv6_value_.ipv6mr_multiaddr = tmp_addr;
  385. ipv6_value_.ipv6mr_interface = 0;
  386. }
  387. }
  388. // Construct with multicast address and IPv4 address specifying an interface.
  389. explicit multicast_request(
  390. const boost::asio::ip::address_v4& multicast_address,
  391. const boost::asio::ip::address_v4& network_interface
  392. = boost::asio::ip::address_v4::any())
  393. {
  394. ipv4_value_.imr_multiaddr.s_addr =
  395. boost::asio::detail::socket_ops::host_to_network_long(
  396. multicast_address.to_ulong());
  397. ipv4_value_.imr_interface.s_addr =
  398. boost::asio::detail::socket_ops::host_to_network_long(
  399. network_interface.to_ulong());
  400. boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
  401. ipv6_value_.ipv6mr_multiaddr = tmp_addr;
  402. ipv6_value_.ipv6mr_interface = 0;
  403. }
  404. // Construct with multicast address and IPv6 network interface index.
  405. explicit multicast_request(
  406. const boost::asio::ip::address_v6& multicast_address,
  407. unsigned long network_interface = 0)
  408. {
  409. ipv4_value_.imr_multiaddr.s_addr =
  410. boost::asio::detail::socket_ops::host_to_network_long(
  411. boost::asio::ip::address_v4::any().to_ulong());
  412. ipv4_value_.imr_interface.s_addr =
  413. boost::asio::detail::socket_ops::host_to_network_long(
  414. boost::asio::ip::address_v4::any().to_ulong());
  415. using namespace std; // For memcpy.
  416. boost::asio::ip::address_v6::bytes_type bytes =
  417. multicast_address.to_bytes();
  418. memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16);
  419. ipv6_value_.ipv6mr_interface = network_interface;
  420. }
  421. // Get the level of the socket option.
  422. template <typename Protocol>
  423. int level(const Protocol& protocol) const
  424. {
  425. if (protocol.family() == PF_INET6)
  426. return IPv6_Level;
  427. return IPv4_Level;
  428. }
  429. // Get the name of the socket option.
  430. template <typename Protocol>
  431. int name(const Protocol& protocol) const
  432. {
  433. if (protocol.family() == PF_INET6)
  434. return IPv6_Name;
  435. return IPv4_Name;
  436. }
  437. // Get the address of the option data.
  438. template <typename Protocol>
  439. const void* data(const Protocol& protocol) const
  440. {
  441. if (protocol.family() == PF_INET6)
  442. return &ipv6_value_;
  443. return &ipv4_value_;
  444. }
  445. // Get the size of the option data.
  446. template <typename Protocol>
  447. std::size_t size(const Protocol& protocol) const
  448. {
  449. if (protocol.family() == PF_INET6)
  450. return sizeof(ipv6_value_);
  451. return sizeof(ipv4_value_);
  452. }
  453. private:
  454. boost::asio::detail::in4_mreq_type ipv4_value_;
  455. boost::asio::detail::in6_mreq_type ipv6_value_;
  456. };
  457. // Helper template for implementing options that specify a network interface.
  458. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
  459. class network_interface
  460. {
  461. public:
  462. // Default constructor.
  463. network_interface()
  464. {
  465. ipv4_value_.s_addr =
  466. boost::asio::detail::socket_ops::host_to_network_long(
  467. boost::asio::ip::address_v4::any().to_ulong());
  468. ipv6_value_ = 0;
  469. }
  470. // Construct with IPv4 interface.
  471. explicit network_interface(const boost::asio::ip::address_v4& ipv4_interface)
  472. {
  473. ipv4_value_.s_addr =
  474. boost::asio::detail::socket_ops::host_to_network_long(
  475. ipv4_interface.to_ulong());
  476. ipv6_value_ = 0;
  477. }
  478. // Construct with IPv6 interface.
  479. explicit network_interface(unsigned int ipv6_interface)
  480. {
  481. ipv4_value_.s_addr =
  482. boost::asio::detail::socket_ops::host_to_network_long(
  483. boost::asio::ip::address_v4::any().to_ulong());
  484. ipv6_value_ = ipv6_interface;
  485. }
  486. // Get the level of the socket option.
  487. template <typename Protocol>
  488. int level(const Protocol& protocol) const
  489. {
  490. if (protocol.family() == PF_INET6)
  491. return IPv6_Level;
  492. return IPv4_Level;
  493. }
  494. // Get the name of the socket option.
  495. template <typename Protocol>
  496. int name(const Protocol& protocol) const
  497. {
  498. if (protocol.family() == PF_INET6)
  499. return IPv6_Name;
  500. return IPv4_Name;
  501. }
  502. // Get the address of the option data.
  503. template <typename Protocol>
  504. const void* data(const Protocol& protocol) const
  505. {
  506. if (protocol.family() == PF_INET6)
  507. return &ipv6_value_;
  508. return &ipv4_value_;
  509. }
  510. // Get the size of the option data.
  511. template <typename Protocol>
  512. std::size_t size(const Protocol& protocol) const
  513. {
  514. if (protocol.family() == PF_INET6)
  515. return sizeof(ipv6_value_);
  516. return sizeof(ipv4_value_);
  517. }
  518. private:
  519. boost::asio::detail::in4_addr_type ipv4_value_;
  520. unsigned int ipv6_value_;
  521. };
  522. } // namespace socket_option
  523. } // namespace detail
  524. } // namespace ip
  525. } // namespace asio
  526. } // namespace boost
  527. #include <boost/asio/detail/pop_options.hpp>
  528. #endif // BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP