Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

567 lines
14KB

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