1  
//
1  
//
2  
// Copyright (c) 2026 Steve Gerbino
2  
// Copyright (c) 2026 Steve Gerbino
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/corosio
7  
// Official repository: https://github.com/cppalliance/corosio
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_COROSIO_SOCKET_OPTION_HPP
10  
#ifndef BOOST_COROSIO_SOCKET_OPTION_HPP
11  
#define BOOST_COROSIO_SOCKET_OPTION_HPP
11  
#define BOOST_COROSIO_SOCKET_OPTION_HPP
12  

12  

13  
#include <boost/corosio/detail/config.hpp>
13  
#include <boost/corosio/detail/config.hpp>
14  

14  

15  
#include <cstddef>
15  
#include <cstddef>
16  

16  

17  
/** @file socket_option.hpp
17  
/** @file socket_option.hpp
18  

18  

19  
    Type-erased socket option types that avoid platform-specific
19  
    Type-erased socket option types that avoid platform-specific
20  
    headers. The protocol level and option name for each type are
20  
    headers. The protocol level and option name for each type are
21  
    resolved at link time via the compiled library.
21  
    resolved at link time via the compiled library.
22  

22  

23  
    For an inline (zero-overhead) alternative that includes platform
23  
    For an inline (zero-overhead) alternative that includes platform
24  
    headers, use `<boost/corosio/native/native_socket_option.hpp>`
24  
    headers, use `<boost/corosio/native/native_socket_option.hpp>`
25  
    (`boost::corosio::native_socket_option`).
25  
    (`boost::corosio::native_socket_option`).
26  

26  

27  
    Both variants satisfy the same option-type interface and work
27  
    Both variants satisfy the same option-type interface and work
28  
    interchangeably with `tcp_socket::set_option` /
28  
    interchangeably with `tcp_socket::set_option` /
29  
    `tcp_socket::get_option` and the corresponding acceptor methods.
29  
    `tcp_socket::get_option` and the corresponding acceptor methods.
30  

30  

31  
    @see native_socket_option
31  
    @see native_socket_option
32  
*/
32  
*/
33  

33  

34  
namespace boost::corosio::socket_option {
34  
namespace boost::corosio::socket_option {
35  

35  

36  
/** Base class for concrete boolean socket options.
36  
/** Base class for concrete boolean socket options.
37  

37  

38  
    Stores a boolean as an `int` suitable for `setsockopt`/`getsockopt`.
38  
    Stores a boolean as an `int` suitable for `setsockopt`/`getsockopt`.
39  
    Derived types provide `level()` and `name()` for the specific option.
39  
    Derived types provide `level()` and `name()` for the specific option.
40  
*/
40  
*/
41  
class boolean_option
41  
class boolean_option
42  
{
42  
{
43  
    int value_ = 0;
43  
    int value_ = 0;
44  

44  

45  
public:
45  
public:
46  
    /// Construct with default value (disabled).
46  
    /// Construct with default value (disabled).
47  
    boolean_option() = default;
47  
    boolean_option() = default;
48  

48  

49  
    /** Construct with an explicit value.
49  
    /** Construct with an explicit value.
50  

50  

51  
        @param v `true` to enable the option, `false` to disable.
51  
        @param v `true` to enable the option, `false` to disable.
52  
    */
52  
    */
53  
    explicit boolean_option(bool v) noexcept : value_(v ? 1 : 0) {}
53  
    explicit boolean_option(bool v) noexcept : value_(v ? 1 : 0) {}
54  

54  

55  
    /// Assign a new value.
55  
    /// Assign a new value.
56  
    boolean_option& operator=(bool v) noexcept
56  
    boolean_option& operator=(bool v) noexcept
57  
    {
57  
    {
58  
        value_ = v ? 1 : 0;
58  
        value_ = v ? 1 : 0;
59  
        return *this;
59  
        return *this;
60  
    }
60  
    }
61  

61  

62  
    /// Return the option value.
62  
    /// Return the option value.
63  
    bool value() const noexcept
63  
    bool value() const noexcept
64  
    {
64  
    {
65  
        return value_ != 0;
65  
        return value_ != 0;
66  
    }
66  
    }
67  

67  

68  
    /// Return the option value.
68  
    /// Return the option value.
69  
    explicit operator bool() const noexcept
69  
    explicit operator bool() const noexcept
70  
    {
70  
    {
71  
        return value_ != 0;
71  
        return value_ != 0;
72  
    }
72  
    }
73  

73  

74  
    /// Return the negated option value.
74  
    /// Return the negated option value.
75  
    bool operator!() const noexcept
75  
    bool operator!() const noexcept
76  
    {
76  
    {
77  
        return value_ == 0;
77  
        return value_ == 0;
78  
    }
78  
    }
79  

79  

80  
    /// Return a pointer to the underlying storage.
80  
    /// Return a pointer to the underlying storage.
81  
    void* data() noexcept
81  
    void* data() noexcept
82  
    {
82  
    {
83  
        return &value_;
83  
        return &value_;
84  
    }
84  
    }
85  

85  

86  
    /// Return a pointer to the underlying storage.
86  
    /// Return a pointer to the underlying storage.
87  
    void const* data() const noexcept
87  
    void const* data() const noexcept
88  
    {
88  
    {
89  
        return &value_;
89  
        return &value_;
90  
    }
90  
    }
91  

91  

92  
    /// Return the size of the underlying storage.
92  
    /// Return the size of the underlying storage.
93  
    std::size_t size() const noexcept
93  
    std::size_t size() const noexcept
94  
    {
94  
    {
95  
        return sizeof(value_);
95  
        return sizeof(value_);
96  
    }
96  
    }
97  

97  

98  
    /** Normalize after `getsockopt` returns fewer bytes than expected.
98  
    /** Normalize after `getsockopt` returns fewer bytes than expected.
99  

99  

100  
        Windows Vista+ may write only 1 byte for boolean options.
100  
        Windows Vista+ may write only 1 byte for boolean options.
101  

101  

102  
        @param s The number of bytes actually written by `getsockopt`.
102  
        @param s The number of bytes actually written by `getsockopt`.
103  
    */
103  
    */
104  
    void resize(std::size_t s) noexcept
104  
    void resize(std::size_t s) noexcept
105  
    {
105  
    {
106  
        if (s == sizeof(char))
106  
        if (s == sizeof(char))
107  
            value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
107  
            value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
108  
    }
108  
    }
109  
};
109  
};
110  

110  

111  
/** Base class for concrete integer socket options.
111  
/** Base class for concrete integer socket options.
112  

112  

113  
    Stores an integer suitable for `setsockopt`/`getsockopt`.
113  
    Stores an integer suitable for `setsockopt`/`getsockopt`.
114  
    Derived types provide `level()` and `name()` for the specific option.
114  
    Derived types provide `level()` and `name()` for the specific option.
115  
*/
115  
*/
116  
class integer_option
116  
class integer_option
117  
{
117  
{
118  
    int value_ = 0;
118  
    int value_ = 0;
119  

119  

120  
public:
120  
public:
121  
    /// Construct with default value (zero).
121  
    /// Construct with default value (zero).
122  
    integer_option() = default;
122  
    integer_option() = default;
123  

123  

124  
    /** Construct with an explicit value.
124  
    /** Construct with an explicit value.
125  

125  

126  
        @param v The option value.
126  
        @param v The option value.
127  
    */
127  
    */
128  
    explicit integer_option(int v) noexcept : value_(v) {}
128  
    explicit integer_option(int v) noexcept : value_(v) {}
129  

129  

130  
    /// Assign a new value.
130  
    /// Assign a new value.
131  
    integer_option& operator=(int v) noexcept
131  
    integer_option& operator=(int v) noexcept
132  
    {
132  
    {
133  
        value_ = v;
133  
        value_ = v;
134  
        return *this;
134  
        return *this;
135  
    }
135  
    }
136  

136  

137  
    /// Return the option value.
137  
    /// Return the option value.
138  
    int value() const noexcept
138  
    int value() const noexcept
139  
    {
139  
    {
140  
        return value_;
140  
        return value_;
141  
    }
141  
    }
142  

142  

143  
    /// Return a pointer to the underlying storage.
143  
    /// Return a pointer to the underlying storage.
144  
    void* data() noexcept
144  
    void* data() noexcept
145  
    {
145  
    {
146  
        return &value_;
146  
        return &value_;
147  
    }
147  
    }
148  

148  

149  
    /// Return a pointer to the underlying storage.
149  
    /// Return a pointer to the underlying storage.
150  
    void const* data() const noexcept
150  
    void const* data() const noexcept
151  
    {
151  
    {
152  
        return &value_;
152  
        return &value_;
153  
    }
153  
    }
154  

154  

155  
    /// Return the size of the underlying storage.
155  
    /// Return the size of the underlying storage.
156  
    std::size_t size() const noexcept
156  
    std::size_t size() const noexcept
157  
    {
157  
    {
158  
        return sizeof(value_);
158  
        return sizeof(value_);
159  
    }
159  
    }
160  

160  

161  
    /** Normalize after `getsockopt` returns fewer bytes than expected.
161  
    /** Normalize after `getsockopt` returns fewer bytes than expected.
162  

162  

163  
        @param s The number of bytes actually written by `getsockopt`.
163  
        @param s The number of bytes actually written by `getsockopt`.
164  
    */
164  
    */
165  
    void resize(std::size_t s) noexcept
165  
    void resize(std::size_t s) noexcept
166  
    {
166  
    {
167  
        if (s == sizeof(char))
167  
        if (s == sizeof(char))
168  
            value_ =
168  
            value_ =
169  
                static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
169  
                static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
170  
    }
170  
    }
171  
};
171  
};
172  

172  

173  
/** Disable Nagle's algorithm (TCP_NODELAY).
173  
/** Disable Nagle's algorithm (TCP_NODELAY).
174  

174  

175  
    @par Example
175  
    @par Example
176  
    @code
176  
    @code
177  
    sock.set_option( socket_option::no_delay( true ) );
177  
    sock.set_option( socket_option::no_delay( true ) );
178  
    auto nd = sock.get_option<socket_option::no_delay>();
178  
    auto nd = sock.get_option<socket_option::no_delay>();
179  
    if ( nd.value() )
179  
    if ( nd.value() )
180  
        // Nagle's algorithm is disabled
180  
        // Nagle's algorithm is disabled
181  
    @endcode
181  
    @endcode
182  
*/
182  
*/
183  
class BOOST_COROSIO_DECL no_delay : public boolean_option
183  
class BOOST_COROSIO_DECL no_delay : public boolean_option
184  
{
184  
{
185  
public:
185  
public:
186  
    using boolean_option::boolean_option;
186  
    using boolean_option::boolean_option;
187  
    using boolean_option::operator=;
187  
    using boolean_option::operator=;
188  

188  

189  
    /// Return the protocol level.
189  
    /// Return the protocol level.
190  
    static int level() noexcept;
190  
    static int level() noexcept;
191  

191  

192  
    /// Return the option name.
192  
    /// Return the option name.
193  
    static int name() noexcept;
193  
    static int name() noexcept;
194  
};
194  
};
195  

195  

196  
/** Enable periodic keepalive probes (SO_KEEPALIVE).
196  
/** Enable periodic keepalive probes (SO_KEEPALIVE).
197  

197  

198  
    @par Example
198  
    @par Example
199  
    @code
199  
    @code
200  
    sock.set_option( socket_option::keep_alive( true ) );
200  
    sock.set_option( socket_option::keep_alive( true ) );
201  
    @endcode
201  
    @endcode
202  
*/
202  
*/
203  
class BOOST_COROSIO_DECL keep_alive : public boolean_option
203  
class BOOST_COROSIO_DECL keep_alive : public boolean_option
204  
{
204  
{
205  
public:
205  
public:
206  
    using boolean_option::boolean_option;
206  
    using boolean_option::boolean_option;
207  
    using boolean_option::operator=;
207  
    using boolean_option::operator=;
208  

208  

209  
    /// Return the protocol level.
209  
    /// Return the protocol level.
210  
    static int level() noexcept;
210  
    static int level() noexcept;
211  

211  

212  
    /// Return the option name.
212  
    /// Return the option name.
213  
    static int name() noexcept;
213  
    static int name() noexcept;
214  
};
214  
};
215  

215  

216  
/** Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
216  
/** Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
217  

217  

218  
    When enabled, the socket only accepts IPv6 connections.
218  
    When enabled, the socket only accepts IPv6 connections.
219  
    When disabled, the socket accepts both IPv4 and IPv6
219  
    When disabled, the socket accepts both IPv4 and IPv6
220  
    connections (dual-stack mode).
220  
    connections (dual-stack mode).
221  

221  

222  
    @par Example
222  
    @par Example
223  
    @code
223  
    @code
224  
    sock.set_option( socket_option::v6_only( true ) );
224  
    sock.set_option( socket_option::v6_only( true ) );
225  
    @endcode
225  
    @endcode
226  
*/
226  
*/
227  
class BOOST_COROSIO_DECL v6_only : public boolean_option
227  
class BOOST_COROSIO_DECL v6_only : public boolean_option
228  
{
228  
{
229  
public:
229  
public:
230  
    using boolean_option::boolean_option;
230  
    using boolean_option::boolean_option;
231  
    using boolean_option::operator=;
231  
    using boolean_option::operator=;
232  

232  

233  
    /// Return the protocol level.
233  
    /// Return the protocol level.
234  
    static int level() noexcept;
234  
    static int level() noexcept;
235  

235  

236  
    /// Return the option name.
236  
    /// Return the option name.
237  
    static int name() noexcept;
237  
    static int name() noexcept;
238  
};
238  
};
239  

239  

240  
/** Allow local address reuse (SO_REUSEADDR).
240  
/** Allow local address reuse (SO_REUSEADDR).
241  

241  

242  
    @par Example
242  
    @par Example
243  
    @code
243  
    @code
244  
    acc.set_option( socket_option::reuse_address( true ) );
244  
    acc.set_option( socket_option::reuse_address( true ) );
245  
    @endcode
245  
    @endcode
246  
*/
246  
*/
247  
class BOOST_COROSIO_DECL reuse_address : public boolean_option
247  
class BOOST_COROSIO_DECL reuse_address : public boolean_option
248  
{
248  
{
249  
public:
249  
public:
250  
    using boolean_option::boolean_option;
250  
    using boolean_option::boolean_option;
251  
    using boolean_option::operator=;
251  
    using boolean_option::operator=;
252  

252  

253  
    /// Return the protocol level.
253  
    /// Return the protocol level.
254  
    static int level() noexcept;
254  
    static int level() noexcept;
255  

255  

256  
    /// Return the option name.
256  
    /// Return the option name.
257  
    static int name() noexcept;
257  
    static int name() noexcept;
258  
};
258  
};
259  

259  

260  
/** Allow multiple sockets to bind to the same port (SO_REUSEPORT).
260  
/** Allow multiple sockets to bind to the same port (SO_REUSEPORT).
261  

261  

262  
    Not available on all platforms. On unsupported platforms,
262  
    Not available on all platforms. On unsupported platforms,
263  
    `set_option` will return an error.
263  
    `set_option` will return an error.
264  

264  

265  
    @par Example
265  
    @par Example
266  
    @code
266  
    @code
267  
    acc.open( tcp::v6() );
267  
    acc.open( tcp::v6() );
268  
    acc.set_option( socket_option::reuse_port( true ) );
268  
    acc.set_option( socket_option::reuse_port( true ) );
269  
    acc.bind( endpoint( ipv6_address::any(), 8080 ) );
269  
    acc.bind( endpoint( ipv6_address::any(), 8080 ) );
270  
    acc.listen();
270  
    acc.listen();
271  
    @endcode
271  
    @endcode
272  
*/
272  
*/
273  
class BOOST_COROSIO_DECL reuse_port : public boolean_option
273  
class BOOST_COROSIO_DECL reuse_port : public boolean_option
274  
{
274  
{
275  
public:
275  
public:
276  
    using boolean_option::boolean_option;
276  
    using boolean_option::boolean_option;
277  
    using boolean_option::operator=;
277  
    using boolean_option::operator=;
278  

278  

279  
    /// Return the protocol level.
279  
    /// Return the protocol level.
280  
    static int level() noexcept;
280  
    static int level() noexcept;
281  

281  

282  
    /// Return the option name.
282  
    /// Return the option name.
283  
    static int name() noexcept;
283  
    static int name() noexcept;
284  
};
284  
};
285  

285  

286  
/** Set the receive buffer size (SO_RCVBUF).
286  
/** Set the receive buffer size (SO_RCVBUF).
287  

287  

288  
    @par Example
288  
    @par Example
289  
    @code
289  
    @code
290  
    sock.set_option( socket_option::receive_buffer_size( 65536 ) );
290  
    sock.set_option( socket_option::receive_buffer_size( 65536 ) );
291  
    auto opt = sock.get_option<socket_option::receive_buffer_size>();
291  
    auto opt = sock.get_option<socket_option::receive_buffer_size>();
292  
    int sz = opt.value();
292  
    int sz = opt.value();
293  
    @endcode
293  
    @endcode
294  
*/
294  
*/
295  
class BOOST_COROSIO_DECL receive_buffer_size : public integer_option
295  
class BOOST_COROSIO_DECL receive_buffer_size : public integer_option
296  
{
296  
{
297  
public:
297  
public:
298  
    using integer_option::integer_option;
298  
    using integer_option::integer_option;
299  
    using integer_option::operator=;
299  
    using integer_option::operator=;
300  

300  

301  
    /// Return the protocol level.
301  
    /// Return the protocol level.
302  
    static int level() noexcept;
302  
    static int level() noexcept;
303  

303  

304  
    /// Return the option name.
304  
    /// Return the option name.
305  
    static int name() noexcept;
305  
    static int name() noexcept;
306  
};
306  
};
307  

307  

308  
/** Set the send buffer size (SO_SNDBUF).
308  
/** Set the send buffer size (SO_SNDBUF).
309  

309  

310  
    @par Example
310  
    @par Example
311  
    @code
311  
    @code
312  
    sock.set_option( socket_option::send_buffer_size( 65536 ) );
312  
    sock.set_option( socket_option::send_buffer_size( 65536 ) );
313  
    @endcode
313  
    @endcode
314  
*/
314  
*/
315  
class BOOST_COROSIO_DECL send_buffer_size : public integer_option
315  
class BOOST_COROSIO_DECL send_buffer_size : public integer_option
316  
{
316  
{
317  
public:
317  
public:
318  
    using integer_option::integer_option;
318  
    using integer_option::integer_option;
319  
    using integer_option::operator=;
319  
    using integer_option::operator=;
320  

320  

321  
    /// Return the protocol level.
321  
    /// Return the protocol level.
322  
    static int level() noexcept;
322  
    static int level() noexcept;
323  

323  

324  
    /// Return the option name.
324  
    /// Return the option name.
325  
    static int name() noexcept;
325  
    static int name() noexcept;
326  
};
326  
};
327  

327  

328  
/** The SO_LINGER socket option.
328  
/** The SO_LINGER socket option.
329  

329  

330  
    Controls behavior when closing a socket with unsent data.
330  
    Controls behavior when closing a socket with unsent data.
331  
    When enabled, `close()` blocks until pending data is sent
331  
    When enabled, `close()` blocks until pending data is sent
332  
    or the timeout expires.
332  
    or the timeout expires.
333  

333  

334  
    @par Example
334  
    @par Example
335  
    @code
335  
    @code
336  
    sock.set_option( socket_option::linger( true, 5 ) );
336  
    sock.set_option( socket_option::linger( true, 5 ) );
337  
    auto opt = sock.get_option<socket_option::linger>();
337  
    auto opt = sock.get_option<socket_option::linger>();
338  
    if ( opt.enabled() )
338  
    if ( opt.enabled() )
339  
        std::cout << "linger timeout: " << opt.timeout() << "s\n";
339  
        std::cout << "linger timeout: " << opt.timeout() << "s\n";
340  
    @endcode
340  
    @endcode
341  
*/
341  
*/
342  
class BOOST_COROSIO_DECL linger
342  
class BOOST_COROSIO_DECL linger
343  
{
343  
{
344  
    // Opaque storage for the platform's struct linger.
344  
    // Opaque storage for the platform's struct linger.
345  
    // POSIX: { int, int } = 8 bytes.
345  
    // POSIX: { int, int } = 8 bytes.
346  
    // Windows: { u_short, u_short } = 4 bytes.
346  
    // Windows: { u_short, u_short } = 4 bytes.
347  
    static constexpr std::size_t max_storage_ = 8;
347  
    static constexpr std::size_t max_storage_ = 8;
348  
    alignas(4) unsigned char storage_[max_storage_]{};
348  
    alignas(4) unsigned char storage_[max_storage_]{};
349  

349  

350  
public:
350  
public:
351  
    /// Construct with default values (disabled, zero timeout).
351  
    /// Construct with default values (disabled, zero timeout).
352  
    linger() noexcept = default;
352  
    linger() noexcept = default;
353  

353  

354  
    /** Construct with explicit values.
354  
    /** Construct with explicit values.
355  

355  

356  
        @param enabled `true` to enable linger behavior on close.
356  
        @param enabled `true` to enable linger behavior on close.
357  
        @param timeout The linger timeout in seconds.
357  
        @param timeout The linger timeout in seconds.
358  
    */
358  
    */
359  
    linger(bool enabled, int timeout) noexcept;
359  
    linger(bool enabled, int timeout) noexcept;
360  

360  

361  
    /// Return whether linger is enabled.
361  
    /// Return whether linger is enabled.
362  
    bool enabled() const noexcept;
362  
    bool enabled() const noexcept;
363  

363  

364  
    /// Set whether linger is enabled.
364  
    /// Set whether linger is enabled.
365  
    void enabled(bool v) noexcept;
365  
    void enabled(bool v) noexcept;
366  

366  

367  
    /// Return the linger timeout in seconds.
367  
    /// Return the linger timeout in seconds.
368  
    int timeout() const noexcept;
368  
    int timeout() const noexcept;
369  

369  

370  
    /// Set the linger timeout in seconds.
370  
    /// Set the linger timeout in seconds.
371  
    void timeout(int v) noexcept;
371  
    void timeout(int v) noexcept;
372  

372  

373  
    /// Return the protocol level.
373  
    /// Return the protocol level.
374  
    static int level() noexcept;
374  
    static int level() noexcept;
375  

375  

376  
    /// Return the option name.
376  
    /// Return the option name.
377  
    static int name() noexcept;
377  
    static int name() noexcept;
378  

378  

379  
    /// Return a pointer to the underlying storage.
379  
    /// Return a pointer to the underlying storage.
380  
    void* data() noexcept
380  
    void* data() noexcept
381  
    {
381  
    {
382  
        return storage_;
382  
        return storage_;
383  
    }
383  
    }
384  

384  

385  
    /// Return a pointer to the underlying storage.
385  
    /// Return a pointer to the underlying storage.
386  
    void const* data() const noexcept
386  
    void const* data() const noexcept
387  
    {
387  
    {
388  
        return storage_;
388  
        return storage_;
389  
    }
389  
    }
390  

390  

391  
    /// Return the size of the underlying storage.
391  
    /// Return the size of the underlying storage.
392  
    std::size_t size() const noexcept;
392  
    std::size_t size() const noexcept;
393  

393  

394  
    /** Normalize after `getsockopt`.
394  
    /** Normalize after `getsockopt`.
395  

395  

396  
        No-op — `struct linger` is always returned at full size.
396  
        No-op — `struct linger` is always returned at full size.
397  

397  

398  
        @param s The number of bytes actually written by `getsockopt`.
398  
        @param s The number of bytes actually written by `getsockopt`.
399  
    */
399  
    */
400  
    void resize(std::size_t) noexcept {}
400  
    void resize(std::size_t) noexcept {}
401  
};
401  
};
402  

402  

403  
} // namespace boost::corosio::socket_option
403  
} // namespace boost::corosio::socket_option
404  

404  

405  
#endif // BOOST_COROSIO_SOCKET_OPTION_HPP
405  
#endif // BOOST_COROSIO_SOCKET_OPTION_HPP