include/boost/corosio/socket_option.hpp

90.0% Lines (27/30) 100.0% Functions (19/19)
include/boost/corosio/socket_option.hpp
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 //
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)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_SOCKET_OPTION_HPP
11 #define BOOST_COROSIO_SOCKET_OPTION_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14
15 #include <cstddef>
16
17 /** @file socket_option.hpp
18
19 Type-erased socket option types that avoid platform-specific
20 headers. The protocol level and option name for each type are
21 resolved at link time via the compiled library.
22
23 For an inline (zero-overhead) alternative that includes platform
24 headers, use `<boost/corosio/native/native_socket_option.hpp>`
25 (`boost::corosio::native_socket_option`).
26
27 Both variants satisfy the same option-type interface and work
28 interchangeably with `tcp_socket::set_option` /
29 `tcp_socket::get_option` and the corresponding acceptor methods.
30
31 @see native_socket_option
32 */
33
34 namespace boost::corosio::socket_option {
35
36 /** Base class for concrete boolean socket options.
37
38 Stores a boolean as an `int` suitable for `setsockopt`/`getsockopt`.
39 Derived types provide `level()` and `name()` for the specific option.
40 */
41 class boolean_option
42 {
43 int value_ = 0;
44
45 public:
46 /// Construct with default value (disabled).
47 boolean_option() = default;
48
49 /** Construct with an explicit value.
50
51 @param v `true` to enable the option, `false` to disable.
52 */
53 169 explicit boolean_option( bool v ) noexcept : value_( v ? 1 : 0 ) {}
54
55 /// Assign a new value.
56 4 boolean_option& operator=( bool v ) noexcept
57 {
58 4 value_ = v ? 1 : 0;
59 4 return *this;
60 }
61
62 /// Return the option value.
63 34 bool value() const noexcept { return value_ != 0; }
64
65 /// Return the option value.
66 4 explicit operator bool() const noexcept { return value_ != 0; }
67
68 /// Return the negated option value.
69 4 bool operator!() const noexcept { return value_ == 0; }
70
71 /// Return a pointer to the underlying storage.
72 36 void* data() noexcept { return &value_; }
73
74 /// Return a pointer to the underlying storage.
75 171 void const* data() const noexcept { return &value_; }
76
77 /// Return the size of the underlying storage.
78 207 std::size_t size() const noexcept { return sizeof( value_ ); }
79
80 /** Normalize after `getsockopt` returns fewer bytes than expected.
81
82 Windows Vista+ may write only 1 byte for boolean options.
83
84 @param s The number of bytes actually written by `getsockopt`.
85 */
86 36 void resize( std::size_t s ) noexcept
87 {
88 36 if ( s == sizeof( char ) )
89 value_ = *reinterpret_cast<unsigned char*>( &value_ ) ? 1 : 0;
90 36 }
91 };
92
93 /** Base class for concrete integer socket options.
94
95 Stores an integer suitable for `setsockopt`/`getsockopt`.
96 Derived types provide `level()` and `name()` for the specific option.
97 */
98 class integer_option
99 {
100 int value_ = 0;
101
102 public:
103 /// Construct with default value (zero).
104 integer_option() = default;
105
106 /** Construct with an explicit value.
107
108 @param v The option value.
109 */
110 8 explicit integer_option( int v ) noexcept : value_( v ) {}
111
112 /// Assign a new value.
113 2 integer_option& operator=( int v ) noexcept
114 {
115 2 value_ = v;
116 2 return *this;
117 }
118
119 /// Return the option value.
120 18 int value() const noexcept { return value_; }
121
122 /// Return a pointer to the underlying storage.
123 16 void* data() noexcept { return &value_; }
124
125 /// Return a pointer to the underlying storage.
126 8 void const* data() const noexcept { return &value_; }
127
128 /// Return the size of the underlying storage.
129 24 std::size_t size() const noexcept { return sizeof( value_ ); }
130
131 /** Normalize after `getsockopt` returns fewer bytes than expected.
132
133 @param s The number of bytes actually written by `getsockopt`.
134 */
135 16 void resize( std::size_t s ) noexcept
136 {
137 16 if ( s == sizeof( char ) )
138 value_ = static_cast<int>(
139 *reinterpret_cast<unsigned char*>( &value_ ) );
140 16 }
141 };
142
143 /** Disable Nagle's algorithm (TCP_NODELAY).
144
145 @par Example
146 @code
147 sock.set_option( socket_option::no_delay( true ) );
148 auto nd = sock.get_option<socket_option::no_delay>();
149 if ( nd.value() )
150 // Nagle's algorithm is disabled
151 @endcode
152 */
153 class BOOST_COROSIO_DECL no_delay : public boolean_option
154 {
155 public:
156 using boolean_option::boolean_option;
157 using boolean_option::operator=;
158
159 /// Return the protocol level.
160 static int level() noexcept;
161
162 /// Return the option name.
163 static int name() noexcept;
164 };
165
166 /** Enable periodic keepalive probes (SO_KEEPALIVE).
167
168 @par Example
169 @code
170 sock.set_option( socket_option::keep_alive( true ) );
171 @endcode
172 */
173 class BOOST_COROSIO_DECL keep_alive : public boolean_option
174 {
175 public:
176 using boolean_option::boolean_option;
177 using boolean_option::operator=;
178
179 /// Return the protocol level.
180 static int level() noexcept;
181
182 /// Return the option name.
183 static int name() noexcept;
184 };
185
186 /** Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
187
188 When enabled, the socket only accepts IPv6 connections.
189 When disabled, the socket accepts both IPv4 and IPv6
190 connections (dual-stack mode).
191
192 @par Example
193 @code
194 sock.set_option( socket_option::v6_only( true ) );
195 @endcode
196 */
197 class BOOST_COROSIO_DECL v6_only : public boolean_option
198 {
199 public:
200 using boolean_option::boolean_option;
201 using boolean_option::operator=;
202
203 /// Return the protocol level.
204 static int level() noexcept;
205
206 /// Return the option name.
207 static int name() noexcept;
208 };
209
210 /** Allow local address reuse (SO_REUSEADDR).
211
212 @par Example
213 @code
214 acc.set_option( socket_option::reuse_address( true ) );
215 @endcode
216 */
217 class BOOST_COROSIO_DECL reuse_address : public boolean_option
218 {
219 public:
220 using boolean_option::boolean_option;
221 using boolean_option::operator=;
222
223 /// Return the protocol level.
224 static int level() noexcept;
225
226 /// Return the option name.
227 static int name() noexcept;
228 };
229
230 /** Allow multiple sockets to bind to the same port (SO_REUSEPORT).
231
232 Not available on all platforms. On unsupported platforms,
233 `set_option` will return an error.
234
235 @par Example
236 @code
237 acc.open( tcp::v6() );
238 acc.set_option( socket_option::reuse_port( true ) );
239 acc.bind( endpoint( ipv6_address::any(), 8080 ) );
240 acc.listen();
241 @endcode
242 */
243 class BOOST_COROSIO_DECL reuse_port : public boolean_option
244 {
245 public:
246 using boolean_option::boolean_option;
247 using boolean_option::operator=;
248
249 /// Return the protocol level.
250 static int level() noexcept;
251
252 /// Return the option name.
253 static int name() noexcept;
254 };
255
256 /** Set the receive buffer size (SO_RCVBUF).
257
258 @par Example
259 @code
260 sock.set_option( socket_option::receive_buffer_size( 65536 ) );
261 auto opt = sock.get_option<socket_option::receive_buffer_size>();
262 int sz = opt.value();
263 @endcode
264 */
265 class BOOST_COROSIO_DECL receive_buffer_size : public integer_option
266 {
267 public:
268 using integer_option::integer_option;
269 using integer_option::operator=;
270
271 /// Return the protocol level.
272 static int level() noexcept;
273
274 /// Return the option name.
275 static int name() noexcept;
276 };
277
278 /** Set the send buffer size (SO_SNDBUF).
279
280 @par Example
281 @code
282 sock.set_option( socket_option::send_buffer_size( 65536 ) );
283 @endcode
284 */
285 class BOOST_COROSIO_DECL send_buffer_size : public integer_option
286 {
287 public:
288 using integer_option::integer_option;
289 using integer_option::operator=;
290
291 /// Return the protocol level.
292 static int level() noexcept;
293
294 /// Return the option name.
295 static int name() noexcept;
296 };
297
298 /** The SO_LINGER socket option.
299
300 Controls behavior when closing a socket with unsent data.
301 When enabled, `close()` blocks until pending data is sent
302 or the timeout expires.
303
304 @par Example
305 @code
306 sock.set_option( socket_option::linger( true, 5 ) );
307 auto opt = sock.get_option<socket_option::linger>();
308 if ( opt.enabled() )
309 std::cout << "linger timeout: " << opt.timeout() << "s\n";
310 @endcode
311 */
312 class BOOST_COROSIO_DECL linger
313 {
314 // Opaque storage for the platform's struct linger.
315 // POSIX: { int, int } = 8 bytes.
316 // Windows: { u_short, u_short } = 4 bytes.
317 static constexpr std::size_t max_storage_ = 8;
318 alignas( 4 ) unsigned char storage_[max_storage_]{};
319
320 public:
321 /// Construct with default values (disabled, zero timeout).
322 linger() noexcept = default;
323
324 /** Construct with explicit values.
325
326 @param enabled `true` to enable linger behavior on close.
327 @param timeout The linger timeout in seconds.
328 */
329 linger( bool enabled, int timeout ) noexcept;
330
331 /// Return whether linger is enabled.
332 bool enabled() const noexcept;
333
334 /// Set whether linger is enabled.
335 void enabled( bool v ) noexcept;
336
337 /// Return the linger timeout in seconds.
338 int timeout() const noexcept;
339
340 /// Set the linger timeout in seconds.
341 void timeout( int v ) noexcept;
342
343 /// Return the protocol level.
344 static int level() noexcept;
345
346 /// Return the option name.
347 static int name() noexcept;
348
349 /// Return a pointer to the underlying storage.
350 10 void* data() noexcept { return storage_; }
351
352 /// Return a pointer to the underlying storage.
353 18 void const* data() const noexcept { return storage_; }
354
355 /// Return the size of the underlying storage.
356 std::size_t size() const noexcept;
357
358 /** Normalize after `getsockopt`.
359
360 No-op — `struct linger` is always returned at full size.
361
362 @param s The number of bytes actually written by `getsockopt`.
363 */
364 10 void resize( std::size_t ) noexcept {}
365 };
366
367 } // namespace boost::corosio::socket_option
368
369 #endif // BOOST_COROSIO_SOCKET_OPTION_HPP
370