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