$search
00001 // 00002 // socket_option.hpp 00003 // ~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #ifndef ASIO_IP_DETAIL_SOCKET_OPTION_HPP 00012 #define ASIO_IP_DETAIL_SOCKET_OPTION_HPP 00013 00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00015 # pragma once 00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00017 00018 #include "asio/detail/push_options.hpp" 00019 00020 #include "asio/detail/push_options.hpp" 00021 #include <cstddef> 00022 #include <cstring> 00023 #include <boost/config.hpp> 00024 #include "asio/detail/pop_options.hpp" 00025 00026 #include "asio/ip/address.hpp" 00027 #include "asio/detail/socket_ops.hpp" 00028 #include "asio/detail/socket_types.hpp" 00029 00030 namespace asio { 00031 namespace ip { 00032 namespace detail { 00033 namespace socket_option { 00034 00035 // Helper template for implementing multicast enable loopback options. 00036 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 00037 class multicast_enable_loopback 00038 { 00039 public: 00040 #if defined(__sun) || defined(__osf__) 00041 typedef unsigned char ipv4_value_type; 00042 typedef unsigned char ipv6_value_type; 00043 #elif defined(_AIX) || defined(__hpux) 00044 typedef unsigned char ipv4_value_type; 00045 typedef unsigned int ipv6_value_type; 00046 #else 00047 typedef int ipv4_value_type; 00048 typedef int ipv6_value_type; 00049 #endif 00050 00051 // Default constructor. 00052 multicast_enable_loopback() 00053 : ipv4_value_(0), 00054 ipv6_value_(0) 00055 { 00056 } 00057 00058 // Construct with a specific option value. 00059 explicit multicast_enable_loopback(bool v) 00060 : ipv4_value_(v ? 1 : 0), 00061 ipv6_value_(v ? 1 : 0) 00062 { 00063 } 00064 00065 // Set the value of the boolean. 00066 multicast_enable_loopback& operator=(bool v) 00067 { 00068 ipv4_value_ = v ? 1 : 0; 00069 ipv6_value_ = v ? 1 : 0; 00070 return *this; 00071 } 00072 00073 // Get the current value of the boolean. 00074 bool value() const 00075 { 00076 return !!ipv4_value_; 00077 } 00078 00079 // Convert to bool. 00080 operator bool() const 00081 { 00082 return !!ipv4_value_; 00083 } 00084 00085 // Test for false. 00086 bool operator!() const 00087 { 00088 return !ipv4_value_; 00089 } 00090 00091 // Get the level of the socket option. 00092 template <typename Protocol> 00093 int level(const Protocol& protocol) const 00094 { 00095 if (protocol.family() == PF_INET6) 00096 return IPv6_Level; 00097 return IPv4_Level; 00098 } 00099 00100 // Get the name of the socket option. 00101 template <typename Protocol> 00102 int name(const Protocol& protocol) const 00103 { 00104 if (protocol.family() == PF_INET6) 00105 return IPv6_Name; 00106 return IPv4_Name; 00107 } 00108 00109 // Get the address of the boolean data. 00110 template <typename Protocol> 00111 void* data(const Protocol& protocol) 00112 { 00113 if (protocol.family() == PF_INET6) 00114 return &ipv6_value_; 00115 return &ipv4_value_; 00116 } 00117 00118 // Get the address of the boolean data. 00119 template <typename Protocol> 00120 const void* data(const Protocol& protocol) const 00121 { 00122 if (protocol.family() == PF_INET6) 00123 return &ipv6_value_; 00124 return &ipv4_value_; 00125 } 00126 00127 // Get the size of the boolean data. 00128 template <typename Protocol> 00129 std::size_t size(const Protocol& protocol) const 00130 { 00131 if (protocol.family() == PF_INET6) 00132 return sizeof(ipv6_value_); 00133 return sizeof(ipv4_value_); 00134 } 00135 00136 // Set the size of the boolean data. 00137 template <typename Protocol> 00138 void resize(const Protocol& protocol, std::size_t s) 00139 { 00140 if (protocol.family() == PF_INET6) 00141 { 00142 if (s != sizeof(ipv6_value_)) 00143 { 00144 throw std::length_error( 00145 "multicast_enable_loopback socket option resize"); 00146 } 00147 ipv4_value_ = ipv6_value_ ? 1 : 0; 00148 } 00149 else 00150 { 00151 if (s != sizeof(ipv4_value_)) 00152 { 00153 throw std::length_error( 00154 "multicast_enable_loopback socket option resize"); 00155 } 00156 ipv6_value_ = ipv4_value_ ? 1 : 0; 00157 } 00158 } 00159 00160 private: 00161 ipv4_value_type ipv4_value_; 00162 ipv6_value_type ipv6_value_; 00163 }; 00164 00165 // Helper template for implementing unicast hops options. 00166 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 00167 class unicast_hops 00168 { 00169 public: 00170 // Default constructor. 00171 unicast_hops() 00172 : value_(0) 00173 { 00174 } 00175 00176 // Construct with a specific option value. 00177 explicit unicast_hops(int v) 00178 : value_(v) 00179 { 00180 } 00181 00182 // Set the value of the option. 00183 unicast_hops& operator=(int v) 00184 { 00185 value_ = v; 00186 return *this; 00187 } 00188 00189 // Get the current value of the option. 00190 int value() const 00191 { 00192 return value_; 00193 } 00194 00195 // Get the level of the socket option. 00196 template <typename Protocol> 00197 int level(const Protocol& protocol) const 00198 { 00199 if (protocol.family() == PF_INET6) 00200 return IPv6_Level; 00201 return IPv4_Level; 00202 } 00203 00204 // Get the name of the socket option. 00205 template <typename Protocol> 00206 int name(const Protocol& protocol) const 00207 { 00208 if (protocol.family() == PF_INET6) 00209 return IPv6_Name; 00210 return IPv4_Name; 00211 } 00212 00213 // Get the address of the data. 00214 template <typename Protocol> 00215 int* data(const Protocol&) 00216 { 00217 return &value_; 00218 } 00219 00220 // Get the address of the data. 00221 template <typename Protocol> 00222 const int* data(const Protocol&) const 00223 { 00224 return &value_; 00225 } 00226 00227 // Get the size of the data. 00228 template <typename Protocol> 00229 std::size_t size(const Protocol&) const 00230 { 00231 return sizeof(value_); 00232 } 00233 00234 // Set the size of the data. 00235 template <typename Protocol> 00236 void resize(const Protocol&, std::size_t s) 00237 { 00238 if (s != sizeof(value_)) 00239 throw std::length_error("unicast hops socket option resize"); 00240 #if defined(__hpux) 00241 if (value_ < 0) 00242 value_ = value_ & 0xFF; 00243 #endif 00244 } 00245 00246 private: 00247 int value_; 00248 }; 00249 00250 // Helper template for implementing multicast hops options. 00251 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 00252 class multicast_hops 00253 { 00254 public: 00255 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00256 typedef int ipv4_value_type; 00257 #else 00258 typedef unsigned char ipv4_value_type; 00259 #endif 00260 typedef int ipv6_value_type; 00261 00262 // Default constructor. 00263 multicast_hops() 00264 : ipv4_value_(0), 00265 ipv6_value_(0) 00266 { 00267 } 00268 00269 // Construct with a specific option value. 00270 explicit multicast_hops(int v) 00271 { 00272 if (v < 0 || v > 255) 00273 throw std::out_of_range("multicast hops value out of range"); 00274 ipv4_value_ = (ipv4_value_type)v; 00275 ipv6_value_ = v; 00276 } 00277 00278 // Set the value of the option. 00279 multicast_hops& operator=(int v) 00280 { 00281 if (v < 0 || v > 255) 00282 throw std::out_of_range("multicast hops value out of range"); 00283 ipv4_value_ = (ipv4_value_type)v; 00284 ipv6_value_ = v; 00285 return *this; 00286 } 00287 00288 // Get the current value of the option. 00289 int value() const 00290 { 00291 return ipv6_value_; 00292 } 00293 00294 // Get the level of the socket option. 00295 template <typename Protocol> 00296 int level(const Protocol& protocol) const 00297 { 00298 if (protocol.family() == PF_INET6) 00299 return IPv6_Level; 00300 return IPv4_Level; 00301 } 00302 00303 // Get the name of the socket option. 00304 template <typename Protocol> 00305 int name(const Protocol& protocol) const 00306 { 00307 if (protocol.family() == PF_INET6) 00308 return IPv6_Name; 00309 return IPv4_Name; 00310 } 00311 00312 // Get the address of the data. 00313 template <typename Protocol> 00314 void* data(const Protocol& protocol) 00315 { 00316 if (protocol.family() == PF_INET6) 00317 return &ipv6_value_; 00318 return &ipv4_value_; 00319 } 00320 00321 // Get the address of the data. 00322 template <typename Protocol> 00323 const void* data(const Protocol& protocol) const 00324 { 00325 if (protocol.family() == PF_INET6) 00326 return &ipv6_value_; 00327 return &ipv4_value_; 00328 } 00329 00330 // Get the size of the data. 00331 template <typename Protocol> 00332 std::size_t size(const Protocol& protocol) const 00333 { 00334 if (protocol.family() == PF_INET6) 00335 return sizeof(ipv6_value_); 00336 return sizeof(ipv4_value_); 00337 } 00338 00339 // Set the size of the data. 00340 template <typename Protocol> 00341 void resize(const Protocol& protocol, std::size_t s) 00342 { 00343 if (protocol.family() == PF_INET6) 00344 { 00345 if (s != sizeof(ipv6_value_)) 00346 throw std::length_error("multicast hops socket option resize"); 00347 if (ipv6_value_ < 0) 00348 ipv4_value_ = 0; 00349 else if (ipv6_value_ > 255) 00350 ipv4_value_ = 255; 00351 else 00352 ipv4_value_ = (ipv4_value_type)ipv6_value_; 00353 } 00354 else 00355 { 00356 if (s != sizeof(ipv4_value_)) 00357 throw std::length_error("multicast hops socket option resize"); 00358 ipv6_value_ = ipv4_value_; 00359 } 00360 } 00361 00362 private: 00363 ipv4_value_type ipv4_value_; 00364 ipv6_value_type ipv6_value_; 00365 }; 00366 00367 // Helper template for implementing ip_mreq-based options. 00368 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 00369 class multicast_request 00370 { 00371 public: 00372 // Default constructor. 00373 multicast_request() 00374 { 00375 ipv4_value_.imr_multiaddr.s_addr = 00376 asio::detail::socket_ops::host_to_network_long( 00377 asio::ip::address_v4::any().to_ulong()); 00378 ipv4_value_.imr_interface.s_addr = 00379 asio::detail::socket_ops::host_to_network_long( 00380 asio::ip::address_v4::any().to_ulong()); 00381 00382 asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; 00383 ipv6_value_.ipv6mr_multiaddr = tmp_addr; 00384 ipv6_value_.ipv6mr_interface = 0; 00385 } 00386 00387 // Construct with multicast address only. 00388 explicit multicast_request(const asio::ip::address& multicast_address) 00389 { 00390 if (multicast_address.is_v6()) 00391 { 00392 ipv4_value_.imr_multiaddr.s_addr = 00393 asio::detail::socket_ops::host_to_network_long( 00394 asio::ip::address_v4::any().to_ulong()); 00395 ipv4_value_.imr_interface.s_addr = 00396 asio::detail::socket_ops::host_to_network_long( 00397 asio::ip::address_v4::any().to_ulong()); 00398 00399 using namespace std; // For memcpy. 00400 asio::ip::address_v6 ipv6_address = multicast_address.to_v6(); 00401 asio::ip::address_v6::bytes_type bytes = ipv6_address.to_bytes(); 00402 memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16); 00403 ipv6_value_.ipv6mr_interface = 0; 00404 } 00405 else 00406 { 00407 ipv4_value_.imr_multiaddr.s_addr = 00408 asio::detail::socket_ops::host_to_network_long( 00409 multicast_address.to_v4().to_ulong()); 00410 ipv4_value_.imr_interface.s_addr = 00411 asio::detail::socket_ops::host_to_network_long( 00412 asio::ip::address_v4::any().to_ulong()); 00413 00414 asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; 00415 ipv6_value_.ipv6mr_multiaddr = tmp_addr; 00416 ipv6_value_.ipv6mr_interface = 0; 00417 } 00418 } 00419 00420 // Construct with multicast address and IPv4 address specifying an interface. 00421 explicit multicast_request( 00422 const asio::ip::address_v4& multicast_address, 00423 const asio::ip::address_v4& network_interface 00424 = asio::ip::address_v4::any()) 00425 { 00426 ipv4_value_.imr_multiaddr.s_addr = 00427 asio::detail::socket_ops::host_to_network_long( 00428 multicast_address.to_ulong()); 00429 ipv4_value_.imr_interface.s_addr = 00430 asio::detail::socket_ops::host_to_network_long( 00431 network_interface.to_ulong()); 00432 00433 asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; 00434 ipv6_value_.ipv6mr_multiaddr = tmp_addr; 00435 ipv6_value_.ipv6mr_interface = 0; 00436 } 00437 00438 // Construct with multicast address and IPv6 network interface index. 00439 explicit multicast_request( 00440 const asio::ip::address_v6& multicast_address, 00441 unsigned long network_interface = 0) 00442 { 00443 ipv4_value_.imr_multiaddr.s_addr = 00444 asio::detail::socket_ops::host_to_network_long( 00445 asio::ip::address_v4::any().to_ulong()); 00446 ipv4_value_.imr_interface.s_addr = 00447 asio::detail::socket_ops::host_to_network_long( 00448 asio::ip::address_v4::any().to_ulong()); 00449 00450 using namespace std; // For memcpy. 00451 asio::ip::address_v6::bytes_type bytes = 00452 multicast_address.to_bytes(); 00453 memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16); 00454 ipv6_value_.ipv6mr_interface = network_interface; 00455 } 00456 00457 // Get the level of the socket option. 00458 template <typename Protocol> 00459 int level(const Protocol& protocol) const 00460 { 00461 if (protocol.family() == PF_INET6) 00462 return IPv6_Level; 00463 return IPv4_Level; 00464 } 00465 00466 // Get the name of the socket option. 00467 template <typename Protocol> 00468 int name(const Protocol& protocol) const 00469 { 00470 if (protocol.family() == PF_INET6) 00471 return IPv6_Name; 00472 return IPv4_Name; 00473 } 00474 00475 // Get the address of the option data. 00476 template <typename Protocol> 00477 const void* data(const Protocol& protocol) const 00478 { 00479 if (protocol.family() == PF_INET6) 00480 return &ipv6_value_; 00481 return &ipv4_value_; 00482 } 00483 00484 // Get the size of the option data. 00485 template <typename Protocol> 00486 std::size_t size(const Protocol& protocol) const 00487 { 00488 if (protocol.family() == PF_INET6) 00489 return sizeof(ipv6_value_); 00490 return sizeof(ipv4_value_); 00491 } 00492 00493 private: 00494 asio::detail::in4_mreq_type ipv4_value_; 00495 asio::detail::in6_mreq_type ipv6_value_; 00496 }; 00497 00498 // Helper template for implementing options that specify a network interface. 00499 template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 00500 class network_interface 00501 { 00502 public: 00503 // Default constructor. 00504 network_interface() 00505 { 00506 ipv4_value_.s_addr = 00507 asio::detail::socket_ops::host_to_network_long( 00508 asio::ip::address_v4::any().to_ulong()); 00509 ipv6_value_ = 0; 00510 } 00511 00512 // Construct with IPv4 interface. 00513 explicit network_interface(const asio::ip::address_v4& ipv4_interface) 00514 { 00515 ipv4_value_.s_addr = 00516 asio::detail::socket_ops::host_to_network_long( 00517 ipv4_interface.to_ulong()); 00518 ipv6_value_ = 0; 00519 } 00520 00521 // Construct with IPv6 interface. 00522 explicit network_interface(unsigned int ipv6_interface) 00523 { 00524 ipv4_value_.s_addr = 00525 asio::detail::socket_ops::host_to_network_long( 00526 asio::ip::address_v4::any().to_ulong()); 00527 ipv6_value_ = ipv6_interface; 00528 } 00529 00530 // Get the level of the socket option. 00531 template <typename Protocol> 00532 int level(const Protocol& protocol) const 00533 { 00534 if (protocol.family() == PF_INET6) 00535 return IPv6_Level; 00536 return IPv4_Level; 00537 } 00538 00539 // Get the name of the socket option. 00540 template <typename Protocol> 00541 int name(const Protocol& protocol) const 00542 { 00543 if (protocol.family() == PF_INET6) 00544 return IPv6_Name; 00545 return IPv4_Name; 00546 } 00547 00548 // Get the address of the option data. 00549 template <typename Protocol> 00550 const void* data(const Protocol& protocol) const 00551 { 00552 if (protocol.family() == PF_INET6) 00553 return &ipv6_value_; 00554 return &ipv4_value_; 00555 } 00556 00557 // Get the size of the option data. 00558 template <typename Protocol> 00559 std::size_t size(const Protocol& protocol) const 00560 { 00561 if (protocol.family() == PF_INET6) 00562 return sizeof(ipv6_value_); 00563 return sizeof(ipv4_value_); 00564 } 00565 00566 private: 00567 asio::detail::in4_addr_type ipv4_value_; 00568 unsigned int ipv6_value_; 00569 }; 00570 00571 } // namespace socket_option 00572 } // namespace detail 00573 } // namespace ip 00574 } // namespace asio 00575 00576 #include "asio/detail/pop_options.hpp" 00577 00578 #endif // ASIO_IP_DETAIL_SOCKET_OPTION_HPP