| 1 | // |
| 2 | // detail/socket_option.hpp |
| 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ |
| 4 | // |
| 5 | // Copyright (c) 2003-2024 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_DETAIL_SOCKET_OPTION_HPP |
| 12 | #define BOOST_ASIO_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 <stdexcept> |
| 21 | #include <boost/asio/detail/socket_types.hpp> |
| 22 | #include <boost/asio/detail/throw_exception.hpp> |
| 23 | |
| 24 | #include <boost/asio/detail/push_options.hpp> |
| 25 | |
| 26 | namespace boost { |
| 27 | namespace asio { |
| 28 | namespace detail { |
| 29 | namespace socket_option { |
| 30 | |
| 31 | // Helper template for implementing boolean-based options. |
| 32 | template <int Level, int Name> |
| 33 | class boolean |
| 34 | { |
| 35 | public: |
| 36 | // Default constructor. |
| 37 | boolean() |
| 38 | : value_(0) |
| 39 | { |
| 40 | } |
| 41 | |
| 42 | // Construct with a specific option value. |
| 43 | explicit boolean(bool v) |
| 44 | : value_(v ? 1 : 0) |
| 45 | { |
| 46 | } |
| 47 | |
| 48 | // Set the current value of the boolean. |
| 49 | boolean& operator=(bool v) |
| 50 | { |
| 51 | value_ = v ? 1 : 0; |
| 52 | return *this; |
| 53 | } |
| 54 | |
| 55 | // Get the current value of the boolean. |
| 56 | bool value() const |
| 57 | { |
| 58 | return !!value_; |
| 59 | } |
| 60 | |
| 61 | // Convert to bool. |
| 62 | operator bool() const |
| 63 | { |
| 64 | return !!value_; |
| 65 | } |
| 66 | |
| 67 | // Test for false. |
| 68 | bool operator!() const |
| 69 | { |
| 70 | return !value_; |
| 71 | } |
| 72 | |
| 73 | // Get the level of the socket option. |
| 74 | template <typename Protocol> |
| 75 | int level(const Protocol&) const |
| 76 | { |
| 77 | return Level; |
| 78 | } |
| 79 | |
| 80 | // Get the name of the socket option. |
| 81 | template <typename Protocol> |
| 82 | int name(const Protocol&) const |
| 83 | { |
| 84 | return Name; |
| 85 | } |
| 86 | |
| 87 | // Get the address of the boolean data. |
| 88 | template <typename Protocol> |
| 89 | int* data(const Protocol&) |
| 90 | { |
| 91 | return &value_; |
| 92 | } |
| 93 | |
| 94 | // Get the address of the boolean data. |
| 95 | template <typename Protocol> |
| 96 | const int* data(const Protocol&) const |
| 97 | { |
| 98 | return &value_; |
| 99 | } |
| 100 | |
| 101 | // Get the size of the boolean data. |
| 102 | template <typename Protocol> |
| 103 | std::size_t size(const Protocol&) const |
| 104 | { |
| 105 | return sizeof(value_); |
| 106 | } |
| 107 | |
| 108 | // Set the size of the boolean data. |
| 109 | template <typename Protocol> |
| 110 | void resize(const Protocol&, std::size_t s) |
| 111 | { |
| 112 | // On some platforms (e.g. Windows Vista), the getsockopt function will |
| 113 | // return the size of a boolean socket option as one byte, even though a |
| 114 | // four byte integer was passed in. |
| 115 | switch (s) |
| 116 | { |
| 117 | case sizeof(char): |
| 118 | value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0; |
| 119 | break; |
| 120 | case sizeof(value_): |
| 121 | break; |
| 122 | default: |
| 123 | { |
| 124 | std::length_error ex("boolean socket option resize" ); |
| 125 | boost::asio::detail::throw_exception(e: ex); |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | private: |
| 131 | int value_; |
| 132 | }; |
| 133 | |
| 134 | // Helper template for implementing integer options. |
| 135 | template <int Level, int Name> |
| 136 | class integer |
| 137 | { |
| 138 | public: |
| 139 | // Default constructor. |
| 140 | integer() |
| 141 | : value_(0) |
| 142 | { |
| 143 | } |
| 144 | |
| 145 | // Construct with a specific option value. |
| 146 | explicit integer(int v) |
| 147 | : value_(v) |
| 148 | { |
| 149 | } |
| 150 | |
| 151 | // Set the value of the int option. |
| 152 | integer& operator=(int v) |
| 153 | { |
| 154 | value_ = v; |
| 155 | return *this; |
| 156 | } |
| 157 | |
| 158 | // Get the current value of the int option. |
| 159 | int value() const |
| 160 | { |
| 161 | return value_; |
| 162 | } |
| 163 | |
| 164 | // Get the level of the socket option. |
| 165 | template <typename Protocol> |
| 166 | int level(const Protocol&) const |
| 167 | { |
| 168 | return Level; |
| 169 | } |
| 170 | |
| 171 | // Get the name of the socket option. |
| 172 | template <typename Protocol> |
| 173 | int name(const Protocol&) const |
| 174 | { |
| 175 | return Name; |
| 176 | } |
| 177 | |
| 178 | // Get the address of the int data. |
| 179 | template <typename Protocol> |
| 180 | int* data(const Protocol&) |
| 181 | { |
| 182 | return &value_; |
| 183 | } |
| 184 | |
| 185 | // Get the address of the int data. |
| 186 | template <typename Protocol> |
| 187 | const int* data(const Protocol&) const |
| 188 | { |
| 189 | return &value_; |
| 190 | } |
| 191 | |
| 192 | // Get the size of the int data. |
| 193 | template <typename Protocol> |
| 194 | std::size_t size(const Protocol&) const |
| 195 | { |
| 196 | return sizeof(value_); |
| 197 | } |
| 198 | |
| 199 | // Set the size of the int data. |
| 200 | template <typename Protocol> |
| 201 | void resize(const Protocol&, std::size_t s) |
| 202 | { |
| 203 | if (s != sizeof(value_)) |
| 204 | { |
| 205 | std::length_error ex("integer socket option resize" ); |
| 206 | boost::asio::detail::throw_exception(e: ex); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | private: |
| 211 | int value_; |
| 212 | }; |
| 213 | |
| 214 | // Helper template for implementing linger options. |
| 215 | template <int Level, int Name> |
| 216 | class linger |
| 217 | { |
| 218 | public: |
| 219 | // Default constructor. |
| 220 | linger() |
| 221 | { |
| 222 | value_.l_onoff = 0; |
| 223 | value_.l_linger = 0; |
| 224 | } |
| 225 | |
| 226 | // Construct with specific option values. |
| 227 | linger(bool e, int t) |
| 228 | { |
| 229 | enabled(e); |
| 230 | timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION(t); |
| 231 | } |
| 232 | |
| 233 | // Set the value for whether linger is enabled. |
| 234 | void enabled(bool value) |
| 235 | { |
| 236 | value_.l_onoff = value ? 1 : 0; |
| 237 | } |
| 238 | |
| 239 | // Get the value for whether linger is enabled. |
| 240 | bool enabled() const |
| 241 | { |
| 242 | return value_.l_onoff != 0; |
| 243 | } |
| 244 | |
| 245 | // Set the value for the linger timeout. |
| 246 | void timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION(int value) |
| 247 | { |
| 248 | #if defined(WIN32) |
| 249 | value_.l_linger = static_cast<u_short>(value); |
| 250 | #else |
| 251 | value_.l_linger = value; |
| 252 | #endif |
| 253 | } |
| 254 | |
| 255 | // Get the value for the linger timeout. |
| 256 | int timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION() const |
| 257 | { |
| 258 | return static_cast<int>(value_.l_linger); |
| 259 | } |
| 260 | |
| 261 | // Get the level of the socket option. |
| 262 | template <typename Protocol> |
| 263 | int level(const Protocol&) const |
| 264 | { |
| 265 | return Level; |
| 266 | } |
| 267 | |
| 268 | // Get the name of the socket option. |
| 269 | template <typename Protocol> |
| 270 | int name(const Protocol&) const |
| 271 | { |
| 272 | return Name; |
| 273 | } |
| 274 | |
| 275 | // Get the address of the linger data. |
| 276 | template <typename Protocol> |
| 277 | detail::linger_type* data(const Protocol&) |
| 278 | { |
| 279 | return &value_; |
| 280 | } |
| 281 | |
| 282 | // Get the address of the linger data. |
| 283 | template <typename Protocol> |
| 284 | const detail::linger_type* data(const Protocol&) const |
| 285 | { |
| 286 | return &value_; |
| 287 | } |
| 288 | |
| 289 | // Get the size of the linger data. |
| 290 | template <typename Protocol> |
| 291 | std::size_t size(const Protocol&) const |
| 292 | { |
| 293 | return sizeof(value_); |
| 294 | } |
| 295 | |
| 296 | // Set the size of the int data. |
| 297 | template <typename Protocol> |
| 298 | void resize(const Protocol&, std::size_t s) |
| 299 | { |
| 300 | if (s != sizeof(value_)) |
| 301 | { |
| 302 | std::length_error ex("linger socket option resize" ); |
| 303 | boost::asio::detail::throw_exception(e: ex); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | private: |
| 308 | detail::linger_type value_; |
| 309 | }; |
| 310 | |
| 311 | } // namespace socket_option |
| 312 | } // namespace detail |
| 313 | } // namespace asio |
| 314 | } // namespace boost |
| 315 | |
| 316 | #include <boost/asio/detail/pop_options.hpp> |
| 317 | |
| 318 | #endif // BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP |
| 319 | |