Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / asio / ip / detail / socket_option.hpp
1 //
2 // detail/socket_option.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2014 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 boost::asio::ip::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       boost::asio::ip::address_v6 ipv6_address = multicast_address.to_v6();
403       boost::asio::ip::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_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     }
416   }
417
418   // Construct with multicast address and IPv4 address specifying an interface.
419   explicit multicast_request(
420       const boost::asio::ip::address_v4& multicast_address,
421       const boost::asio::ip::address_v4& network_interface
422         = boost::asio::ip::address_v4::any())
423     : ipv6_value_() // Zero-initialisation gives the "any" address.
424   {
425     ipv4_value_.imr_multiaddr.s_addr =
426       boost::asio::detail::socket_ops::host_to_network_long(
427           multicast_address.to_ulong());
428     ipv4_value_.imr_interface.s_addr =
429       boost::asio::detail::socket_ops::host_to_network_long(
430           network_interface.to_ulong());
431   }
432
433   // Construct with multicast address and IPv6 network interface index.
434   explicit multicast_request(
435       const boost::asio::ip::address_v6& multicast_address,
436       unsigned long network_interface = 0)
437     : ipv4_value_() // Zero-initialisation gives the "any" address.
438   {
439     using namespace std; // For memcpy.
440     boost::asio::ip::address_v6::bytes_type bytes =
441       multicast_address.to_bytes();
442     memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);
443     if (network_interface)
444       ipv6_value_.ipv6mr_interface = network_interface;
445     else
446       ipv6_value_.ipv6mr_interface = multicast_address.scope_id();
447   }
448
449   // Get the level of the socket option.
450   template <typename Protocol>
451   int level(const Protocol& protocol) const
452   {
453     if (protocol.family() == PF_INET6)
454       return IPv6_Level;
455     return IPv4_Level;
456   }
457
458   // Get the name of the socket option.
459   template <typename Protocol>
460   int name(const Protocol& protocol) const
461   {
462     if (protocol.family() == PF_INET6)
463       return IPv6_Name;
464     return IPv4_Name;
465   }
466
467   // Get the address of the option data.
468   template <typename Protocol>
469   const void* data(const Protocol& protocol) const
470   {
471     if (protocol.family() == PF_INET6)
472       return &ipv6_value_;
473     return &ipv4_value_;
474   }
475
476   // Get the size of the option data.
477   template <typename Protocol>
478   std::size_t size(const Protocol& protocol) const
479   {
480     if (protocol.family() == PF_INET6)
481       return sizeof(ipv6_value_);
482     return sizeof(ipv4_value_);
483   }
484
485 private:
486   boost::asio::detail::in4_mreq_type ipv4_value_;
487   boost::asio::detail::in6_mreq_type ipv6_value_;
488 };
489
490 // Helper template for implementing options that specify a network interface.
491 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
492 class network_interface
493 {
494 public:
495   // Default constructor.
496   network_interface()
497   {
498     ipv4_value_.s_addr =
499       boost::asio::detail::socket_ops::host_to_network_long(
500           boost::asio::ip::address_v4::any().to_ulong());
501     ipv6_value_ = 0;
502   }
503
504   // Construct with IPv4 interface.
505   explicit network_interface(const boost::asio::ip::address_v4& ipv4_interface)
506   {
507     ipv4_value_.s_addr =
508       boost::asio::detail::socket_ops::host_to_network_long(
509           ipv4_interface.to_ulong());
510     ipv6_value_ = 0;
511   }
512
513   // Construct with IPv6 interface.
514   explicit network_interface(unsigned int ipv6_interface)
515   {
516     ipv4_value_.s_addr =
517       boost::asio::detail::socket_ops::host_to_network_long(
518           boost::asio::ip::address_v4::any().to_ulong());
519     ipv6_value_ = ipv6_interface;
520   }
521
522   // Get the level of the socket option.
523   template <typename Protocol>
524   int level(const Protocol& protocol) const
525   {
526     if (protocol.family() == PF_INET6)
527       return IPv6_Level;
528     return IPv4_Level;
529   }
530
531   // Get the name of the socket option.
532   template <typename Protocol>
533   int name(const Protocol& protocol) const
534   {
535     if (protocol.family() == PF_INET6)
536       return IPv6_Name;
537     return IPv4_Name;
538   }
539
540   // Get the address of the option data.
541   template <typename Protocol>
542   const void* data(const Protocol& protocol) const
543   {
544     if (protocol.family() == PF_INET6)
545       return &ipv6_value_;
546     return &ipv4_value_;
547   }
548
549   // Get the size of the option data.
550   template <typename Protocol>
551   std::size_t size(const Protocol& protocol) const
552   {
553     if (protocol.family() == PF_INET6)
554       return sizeof(ipv6_value_);
555     return sizeof(ipv4_value_);
556   }
557
558 private:
559   boost::asio::detail::in4_addr_type ipv4_value_;
560   unsigned int ipv6_value_;
561 };
562
563 } // namespace socket_option
564 } // namespace detail
565 } // namespace ip
566 } // namespace asio
567 } // namespace boost
568
569 #include <boost/asio/detail/pop_options.hpp>
570
571 #endif // BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP