Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:59

0001 //
0002 // detail/socket_option.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP
0012 #define BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <cstring>
0021 #include <stdexcept>
0022 #include <boost/asio/detail/socket_ops.hpp>
0023 #include <boost/asio/detail/socket_types.hpp>
0024 #include <boost/asio/detail/throw_exception.hpp>
0025 #include <boost/asio/ip/address.hpp>
0026 
0027 #include <boost/asio/detail/push_options.hpp>
0028 
0029 namespace boost {
0030 namespace asio {
0031 namespace ip {
0032 namespace detail {
0033 namespace socket_option {
0034 
0035 // Helper template for implementing multicast enable loopback options.
0036 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
0037 class multicast_enable_loopback
0038 {
0039 public:
0040 #if defined(__sun) || defined(__osf__)
0041   typedef unsigned char ipv4_value_type;
0042   typedef unsigned char ipv6_value_type;
0043 #elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) 
0044   typedef unsigned char ipv4_value_type;
0045   typedef unsigned int ipv6_value_type;
0046 #else
0047   typedef int ipv4_value_type;
0048   typedef int ipv6_value_type;
0049 #endif
0050 
0051   // Default constructor.
0052   multicast_enable_loopback()
0053     : ipv4_value_(0),
0054       ipv6_value_(0)
0055   {
0056   }
0057 
0058   // Construct with a specific option value.
0059   explicit multicast_enable_loopback(bool v)
0060     : ipv4_value_(v ? 1 : 0),
0061       ipv6_value_(v ? 1 : 0)
0062   {
0063   }
0064 
0065   // Set the value of the boolean.
0066   multicast_enable_loopback& operator=(bool v)
0067   {
0068     ipv4_value_ = v ? 1 : 0;
0069     ipv6_value_ = v ? 1 : 0;
0070     return *this;
0071   }
0072 
0073   // Get the current value of the boolean.
0074   bool value() const
0075   {
0076     return !!ipv4_value_;
0077   }
0078 
0079   // Convert to bool.
0080   operator bool() const
0081   {
0082     return !!ipv4_value_;
0083   }
0084 
0085   // Test for false.
0086   bool operator!() const
0087   {
0088     return !ipv4_value_;
0089   }
0090 
0091   // Get the level of the socket option.
0092   template <typename Protocol>
0093   int level(const Protocol& protocol) const
0094   {
0095     if (protocol.family() == PF_INET6)
0096       return IPv6_Level;
0097     return IPv4_Level;
0098   }
0099 
0100   // Get the name of the socket option.
0101   template <typename Protocol>
0102   int name(const Protocol& protocol) const
0103   {
0104     if (protocol.family() == PF_INET6)
0105       return IPv6_Name;
0106     return IPv4_Name;
0107   }
0108 
0109   // Get the address of the boolean data.
0110   template <typename Protocol>
0111   void* data(const Protocol& protocol)
0112   {
0113     if (protocol.family() == PF_INET6)
0114       return &ipv6_value_;
0115     return &ipv4_value_;
0116   }
0117 
0118   // Get the address of the boolean data.
0119   template <typename Protocol>
0120   const void* data(const Protocol& protocol) const
0121   {
0122     if (protocol.family() == PF_INET6)
0123       return &ipv6_value_;
0124     return &ipv4_value_;
0125   }
0126 
0127   // Get the size of the boolean data.
0128   template <typename Protocol>
0129   std::size_t size(const Protocol& protocol) const
0130   {
0131     if (protocol.family() == PF_INET6)
0132       return sizeof(ipv6_value_);
0133     return sizeof(ipv4_value_);
0134   }
0135 
0136   // Set the size of the boolean data.
0137   template <typename Protocol>
0138   void resize(const Protocol& protocol, std::size_t s)
0139   {
0140     if (protocol.family() == PF_INET6)
0141     {
0142       if (s != sizeof(ipv6_value_))
0143       {
0144         std::length_error ex("multicast_enable_loopback socket option resize");
0145         boost::asio::detail::throw_exception(ex);
0146       }
0147       ipv4_value_ = ipv6_value_ ? 1 : 0;
0148     }
0149     else
0150     {
0151       if (s != sizeof(ipv4_value_))
0152       {
0153         std::length_error ex("multicast_enable_loopback socket option resize");
0154         boost::asio::detail::throw_exception(ex);
0155       }
0156       ipv6_value_ = ipv4_value_ ? 1 : 0;
0157     }
0158   }
0159 
0160 private:
0161   ipv4_value_type ipv4_value_;
0162   ipv6_value_type ipv6_value_;
0163 };
0164 
0165 // Helper template for implementing unicast hops options.
0166 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
0167 class unicast_hops
0168 {
0169 public:
0170   // Default constructor.
0171   unicast_hops()
0172     : value_(0)
0173   {
0174   }
0175 
0176   // Construct with a specific option value.
0177   explicit unicast_hops(int v)
0178     : value_(v)
0179   {
0180   }
0181 
0182   // Set the value of the option.
0183   unicast_hops& operator=(int v)
0184   {
0185     value_ = v;
0186     return *this;
0187   }
0188 
0189   // Get the current value of the option.
0190   int value() const
0191   {
0192     return value_;
0193   }
0194 
0195   // Get the level of the socket option.
0196   template <typename Protocol>
0197   int level(const Protocol& protocol) const
0198   {
0199     if (protocol.family() == PF_INET6)
0200       return IPv6_Level;
0201     return IPv4_Level;
0202   }
0203 
0204   // Get the name of the socket option.
0205   template <typename Protocol>
0206   int name(const Protocol& protocol) const
0207   {
0208     if (protocol.family() == PF_INET6)
0209       return IPv6_Name;
0210     return IPv4_Name;
0211   }
0212 
0213   // Get the address of the data.
0214   template <typename Protocol>
0215   int* data(const Protocol&)
0216   {
0217     return &value_;
0218   }
0219 
0220   // Get the address of the data.
0221   template <typename Protocol>
0222   const int* data(const Protocol&) const
0223   {
0224     return &value_;
0225   }
0226 
0227   // Get the size of the data.
0228   template <typename Protocol>
0229   std::size_t size(const Protocol&) const
0230   {
0231     return sizeof(value_);
0232   }
0233 
0234   // Set the size of the data.
0235   template <typename Protocol>
0236   void resize(const Protocol&, std::size_t s)
0237   {
0238     if (s != sizeof(value_))
0239     {
0240       std::length_error ex("unicast hops socket option resize");
0241       boost::asio::detail::throw_exception(ex);
0242     }
0243 #if defined(__hpux)
0244     if (value_ < 0)
0245       value_ = value_ & 0xFF;
0246 #endif
0247   }
0248 
0249 private:
0250   int value_;
0251 };
0252 
0253 // Helper template for implementing multicast hops options.
0254 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
0255 class multicast_hops
0256 {
0257 public:
0258 #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
0259   typedef int ipv4_value_type;
0260 #else
0261   typedef unsigned char ipv4_value_type;
0262 #endif
0263   typedef int ipv6_value_type;
0264 
0265   // Default constructor.
0266   multicast_hops()
0267     : ipv4_value_(0),
0268       ipv6_value_(0)
0269   {
0270   }
0271 
0272   // Construct with a specific option value.
0273   explicit multicast_hops(int v)
0274   {
0275     if (v < 0 || v > 255)
0276     {
0277       std::out_of_range ex("multicast hops value out of range");
0278       boost::asio::detail::throw_exception(ex);
0279     }
0280     ipv4_value_ = (ipv4_value_type)v;
0281     ipv6_value_ = v;
0282   }
0283 
0284   // Set the value of the option.
0285   multicast_hops& operator=(int v)
0286   {
0287     if (v < 0 || v > 255)
0288     {
0289       std::out_of_range ex("multicast hops value out of range");
0290       boost::asio::detail::throw_exception(ex);
0291     }
0292     ipv4_value_ = (ipv4_value_type)v;
0293     ipv6_value_ = v;
0294     return *this;
0295   }
0296 
0297   // Get the current value of the option.
0298   int value() const
0299   {
0300     return ipv6_value_;
0301   }
0302 
0303   // Get the level of the socket option.
0304   template <typename Protocol>
0305   int level(const Protocol& protocol) const
0306   {
0307     if (protocol.family() == PF_INET6)
0308       return IPv6_Level;
0309     return IPv4_Level;
0310   }
0311 
0312   // Get the name of the socket option.
0313   template <typename Protocol>
0314   int name(const Protocol& protocol) const
0315   {
0316     if (protocol.family() == PF_INET6)
0317       return IPv6_Name;
0318     return IPv4_Name;
0319   }
0320 
0321   // Get the address of the data.
0322   template <typename Protocol>
0323   void* data(const Protocol& protocol)
0324   {
0325     if (protocol.family() == PF_INET6)
0326       return &ipv6_value_;
0327     return &ipv4_value_;
0328   }
0329 
0330   // Get the address of the data.
0331   template <typename Protocol>
0332   const void* data(const Protocol& protocol) const
0333   {
0334     if (protocol.family() == PF_INET6)
0335       return &ipv6_value_;
0336     return &ipv4_value_;
0337   }
0338 
0339   // Get the size of the data.
0340   template <typename Protocol>
0341   std::size_t size(const Protocol& protocol) const
0342   {
0343     if (protocol.family() == PF_INET6)
0344       return sizeof(ipv6_value_);
0345     return sizeof(ipv4_value_);
0346   }
0347 
0348   // Set the size of the data.
0349   template <typename Protocol>
0350   void resize(const Protocol& protocol, std::size_t s)
0351   {
0352     if (protocol.family() == PF_INET6)
0353     {
0354       if (s != sizeof(ipv6_value_))
0355       {
0356         std::length_error ex("multicast hops socket option resize");
0357         boost::asio::detail::throw_exception(ex);
0358       }
0359       if (ipv6_value_ < 0)
0360         ipv4_value_ = 0;
0361       else if (ipv6_value_ > 255)
0362         ipv4_value_ = 255;
0363       else
0364         ipv4_value_ = (ipv4_value_type)ipv6_value_;
0365     }
0366     else
0367     {
0368       if (s != sizeof(ipv4_value_))
0369       {
0370         std::length_error ex("multicast hops socket option resize");
0371         boost::asio::detail::throw_exception(ex);
0372       }
0373       ipv6_value_ = ipv4_value_;
0374     }
0375   }
0376 
0377 private:
0378   ipv4_value_type ipv4_value_;
0379   ipv6_value_type ipv6_value_;
0380 };
0381 
0382 // Helper template for implementing ip_mreq-based options.
0383 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
0384 class multicast_request
0385 {
0386 public:
0387   // Default constructor.
0388   multicast_request()
0389     : ipv4_value_(), // Zero-initialisation gives the "any" address.
0390       ipv6_value_() // Zero-initialisation gives the "any" address.
0391   {
0392   }
0393 
0394   // Construct with multicast address only.
0395   explicit multicast_request(const address& multicast_address)
0396     : ipv4_value_(), // Zero-initialisation gives the "any" address.
0397       ipv6_value_() // Zero-initialisation gives the "any" address.
0398   {
0399     if (multicast_address.is_v6())
0400     {
0401       using namespace std; // For memcpy.
0402       address_v6 ipv6_address = multicast_address.to_v6();
0403       address_v6::bytes_type bytes = ipv6_address.to_bytes();
0404       memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);
0405       ipv6_value_.ipv6mr_interface = ipv6_address.scope_id();
0406     }
0407     else
0408     {
0409       ipv4_value_.imr_multiaddr.s_addr =
0410         boost::asio::detail::socket_ops::host_to_network_long(
0411             multicast_address.to_v4().to_uint());
0412       ipv4_value_.imr_interface.s_addr =
0413         boost::asio::detail::socket_ops::host_to_network_long(
0414             address_v4::any().to_uint());
0415     }
0416   }
0417 
0418   // Construct with multicast address and IPv4 address specifying an interface.
0419   explicit multicast_request(const address_v4& multicast_address,
0420       const address_v4& network_interface = address_v4::any())
0421     : ipv6_value_() // Zero-initialisation gives the "any" address.
0422   {
0423     ipv4_value_.imr_multiaddr.s_addr =
0424       boost::asio::detail::socket_ops::host_to_network_long(
0425           multicast_address.to_uint());
0426     ipv4_value_.imr_interface.s_addr =
0427       boost::asio::detail::socket_ops::host_to_network_long(
0428           network_interface.to_uint());
0429   }
0430 
0431   // Construct with multicast address and IPv6 network interface index.
0432   explicit multicast_request(
0433       const address_v6& multicast_address,
0434       unsigned long network_interface = 0)
0435     : ipv4_value_() // Zero-initialisation gives the "any" address.
0436   {
0437     using namespace std; // For memcpy.
0438     address_v6::bytes_type bytes = multicast_address.to_bytes();
0439     memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);
0440     if (network_interface)
0441       ipv6_value_.ipv6mr_interface = network_interface;
0442     else
0443       ipv6_value_.ipv6mr_interface = multicast_address.scope_id();
0444   }
0445 
0446   // Get the level of the socket option.
0447   template <typename Protocol>
0448   int level(const Protocol& protocol) const
0449   {
0450     if (protocol.family() == PF_INET6)
0451       return IPv6_Level;
0452     return IPv4_Level;
0453   }
0454 
0455   // Get the name of the socket option.
0456   template <typename Protocol>
0457   int name(const Protocol& protocol) const
0458   {
0459     if (protocol.family() == PF_INET6)
0460       return IPv6_Name;
0461     return IPv4_Name;
0462   }
0463 
0464   // Get the address of the option data.
0465   template <typename Protocol>
0466   const void* data(const Protocol& protocol) const
0467   {
0468     if (protocol.family() == PF_INET6)
0469       return &ipv6_value_;
0470     return &ipv4_value_;
0471   }
0472 
0473   // Get the size of the option data.
0474   template <typename Protocol>
0475   std::size_t size(const Protocol& protocol) const
0476   {
0477     if (protocol.family() == PF_INET6)
0478       return sizeof(ipv6_value_);
0479     return sizeof(ipv4_value_);
0480   }
0481 
0482 private:
0483   boost::asio::detail::in4_mreq_type ipv4_value_;
0484   boost::asio::detail::in6_mreq_type ipv6_value_;
0485 };
0486 
0487 // Helper template for implementing options that specify a network interface.
0488 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
0489 class network_interface
0490 {
0491 public:
0492   // Default constructor.
0493   network_interface()
0494   {
0495     ipv4_value_.s_addr =
0496       boost::asio::detail::socket_ops::host_to_network_long(
0497           address_v4::any().to_uint());
0498     ipv6_value_ = 0;
0499   }
0500 
0501   // Construct with IPv4 interface.
0502   explicit network_interface(const address_v4& ipv4_interface)
0503   {
0504     ipv4_value_.s_addr =
0505       boost::asio::detail::socket_ops::host_to_network_long(
0506           ipv4_interface.to_uint());
0507     ipv6_value_ = 0;
0508   }
0509 
0510   // Construct with IPv6 interface.
0511   explicit network_interface(unsigned int ipv6_interface)
0512   {
0513     ipv4_value_.s_addr =
0514       boost::asio::detail::socket_ops::host_to_network_long(
0515           address_v4::any().to_uint());
0516     ipv6_value_ = ipv6_interface;
0517   }
0518 
0519   // Get the level of the socket option.
0520   template <typename Protocol>
0521   int level(const Protocol& protocol) const
0522   {
0523     if (protocol.family() == PF_INET6)
0524       return IPv6_Level;
0525     return IPv4_Level;
0526   }
0527 
0528   // Get the name of the socket option.
0529   template <typename Protocol>
0530   int name(const Protocol& protocol) const
0531   {
0532     if (protocol.family() == PF_INET6)
0533       return IPv6_Name;
0534     return IPv4_Name;
0535   }
0536 
0537   // Get the address of the option data.
0538   template <typename Protocol>
0539   const void* data(const Protocol& protocol) const
0540   {
0541     if (protocol.family() == PF_INET6)
0542       return &ipv6_value_;
0543     return &ipv4_value_;
0544   }
0545 
0546   // Get the size of the option data.
0547   template <typename Protocol>
0548   std::size_t size(const Protocol& protocol) const
0549   {
0550     if (protocol.family() == PF_INET6)
0551       return sizeof(ipv6_value_);
0552     return sizeof(ipv4_value_);
0553   }
0554 
0555 private:
0556   boost::asio::detail::in4_addr_type ipv4_value_;
0557   unsigned int ipv6_value_;
0558 };
0559 
0560 } // namespace socket_option
0561 } // namespace detail
0562 } // namespace ip
0563 } // namespace asio
0564 } // namespace boost
0565 
0566 #include <boost/asio/detail/pop_options.hpp>
0567 
0568 #endif // BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP