include/boost/corosio/socket_option.hpp

92.9% Lines (39/42) 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
64 {
65 34 return value_ != 0;
66 }
67
68 /// Return the option value.
69 4 explicit operator bool() const noexcept
70 {
71 4 return value_ != 0;
72 }
73
74 /// Return the negated option value.
75 4 bool operator!() const noexcept
76 {
77 4 return value_ == 0;
78 }
79
80 /// Return a pointer to the underlying storage.
81 36 void* data() noexcept
82 {
83 36 return &value_;
84 }
85
86 /// Return a pointer to the underlying storage.
87 171 void const* data() const noexcept
88 {
89 171 return &value_;
90 }
91
92 /// Return the size of the underlying storage.
93 207 std::size_t size() const noexcept
94 {
95 207 return sizeof(value_);
96 }
97
98 /** Normalize after `getsockopt` returns fewer bytes than expected.
99
100 Windows Vista+ may write only 1 byte for boolean options.
101
102 @param s The number of bytes actually written by `getsockopt`.
103 */
104 36 void resize(std::size_t s) noexcept
105 {
106 36 if (s == sizeof(char))
107 value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
108 36 }
109 };
110
111 /** Base class for concrete integer socket options.
112
113 Stores an integer suitable for `setsockopt`/`getsockopt`.
114 Derived types provide `level()` and `name()` for the specific option.
115 */
116 class integer_option
117 {
118 int value_ = 0;
119
120 public:
121 /// Construct with default value (zero).
122 integer_option() = default;
123
124 /** Construct with an explicit value.
125
126 @param v The option value.
127 */
128 8 explicit integer_option(int v) noexcept : value_(v) {}
129
130 /// Assign a new value.
131 2 integer_option& operator=(int v) noexcept
132 {
133 2 value_ = v;
134 2 return *this;
135 }
136
137 /// Return the option value.
138 18 int value() const noexcept
139 {
140 18 return value_;
141 }
142
143 /// Return a pointer to the underlying storage.
144 16 void* data() noexcept
145 {
146 16 return &value_;
147 }
148
149 /// Return a pointer to the underlying storage.
150 8 void const* data() const noexcept
151 {
152 8 return &value_;
153 }
154
155 /// Return the size of the underlying storage.
156 24 std::size_t size() const noexcept
157 {
158 24 return sizeof(value_);
159 }
160
161 /** Normalize after `getsockopt` returns fewer bytes than expected.
162
163 @param s The number of bytes actually written by `getsockopt`.
164 */
165 16 void resize(std::size_t s) noexcept
166 {
167 16 if (s == sizeof(char))
168 value_ =
169 static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
170 16 }
171 };
172
173 /** Disable Nagle's algorithm (TCP_NODELAY).
174
175 @par Example
176 @code
177 sock.set_option( socket_option::no_delay( true ) );
178 auto nd = sock.get_option<socket_option::no_delay>();
179 if ( nd.value() )
180 // Nagle's algorithm is disabled
181 @endcode
182 */
183 class BOOST_COROSIO_DECL no_delay : public boolean_option
184 {
185 public:
186 using boolean_option::boolean_option;
187 using boolean_option::operator=;
188
189 /// Return the protocol level.
190 static int level() noexcept;
191
192 /// Return the option name.
193 static int name() noexcept;
194 };
195
196 /** Enable periodic keepalive probes (SO_KEEPALIVE).
197
198 @par Example
199 @code
200 sock.set_option( socket_option::keep_alive( true ) );
201 @endcode
202 */
203 class BOOST_COROSIO_DECL keep_alive : public boolean_option
204 {
205 public:
206 using boolean_option::boolean_option;
207 using boolean_option::operator=;
208
209 /// Return the protocol level.
210 static int level() noexcept;
211
212 /// Return the option name.
213 static int name() noexcept;
214 };
215
216 /** Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
217
218 When enabled, the socket only accepts IPv6 connections.
219 When disabled, the socket accepts both IPv4 and IPv6
220 connections (dual-stack mode).
221
222 @par Example
223 @code
224 sock.set_option( socket_option::v6_only( true ) );
225 @endcode
226 */
227 class BOOST_COROSIO_DECL v6_only : public boolean_option
228 {
229 public:
230 using boolean_option::boolean_option;
231 using boolean_option::operator=;
232
233 /// Return the protocol level.
234 static int level() noexcept;
235
236 /// Return the option name.
237 static int name() noexcept;
238 };
239
240 /** Allow local address reuse (SO_REUSEADDR).
241
242 @par Example
243 @code
244 acc.set_option( socket_option::reuse_address( true ) );
245 @endcode
246 */
247 class BOOST_COROSIO_DECL reuse_address : public boolean_option
248 {
249 public:
250 using boolean_option::boolean_option;
251 using boolean_option::operator=;
252
253 /// Return the protocol level.
254 static int level() noexcept;
255
256 /// Return the option name.
257 static int name() noexcept;
258 };
259
260 /** Allow multiple sockets to bind to the same port (SO_REUSEPORT).
261
262 Not available on all platforms. On unsupported platforms,
263 `set_option` will return an error.
264
265 @par Example
266 @code
267 acc.open( tcp::v6() );
268 acc.set_option( socket_option::reuse_port( true ) );
269 acc.bind( endpoint( ipv6_address::any(), 8080 ) );
270 acc.listen();
271 @endcode
272 */
273 class BOOST_COROSIO_DECL reuse_port : public boolean_option
274 {
275 public:
276 using boolean_option::boolean_option;
277 using boolean_option::operator=;
278
279 /// Return the protocol level.
280 static int level() noexcept;
281
282 /// Return the option name.
283 static int name() noexcept;
284 };
285
286 /** Set the receive buffer size (SO_RCVBUF).
287
288 @par Example
289 @code
290 sock.set_option( socket_option::receive_buffer_size( 65536 ) );
291 auto opt = sock.get_option<socket_option::receive_buffer_size>();
292 int sz = opt.value();
293 @endcode
294 */
295 class BOOST_COROSIO_DECL receive_buffer_size : public integer_option
296 {
297 public:
298 using integer_option::integer_option;
299 using integer_option::operator=;
300
301 /// Return the protocol level.
302 static int level() noexcept;
303
304 /// Return the option name.
305 static int name() noexcept;
306 };
307
308 /** Set the send buffer size (SO_SNDBUF).
309
310 @par Example
311 @code
312 sock.set_option( socket_option::send_buffer_size( 65536 ) );
313 @endcode
314 */
315 class BOOST_COROSIO_DECL send_buffer_size : public integer_option
316 {
317 public:
318 using integer_option::integer_option;
319 using integer_option::operator=;
320
321 /// Return the protocol level.
322 static int level() noexcept;
323
324 /// Return the option name.
325 static int name() noexcept;
326 };
327
328 /** The SO_LINGER socket option.
329
330 Controls behavior when closing a socket with unsent data.
331 When enabled, `close()` blocks until pending data is sent
332 or the timeout expires.
333
334 @par Example
335 @code
336 sock.set_option( socket_option::linger( true, 5 ) );
337 auto opt = sock.get_option<socket_option::linger>();
338 if ( opt.enabled() )
339 std::cout << "linger timeout: " << opt.timeout() << "s\n";
340 @endcode
341 */
342 class BOOST_COROSIO_DECL linger
343 {
344 // Opaque storage for the platform's struct linger.
345 // POSIX: { int, int } = 8 bytes.
346 // Windows: { u_short, u_short } = 4 bytes.
347 static constexpr std::size_t max_storage_ = 8;
348 alignas(4) unsigned char storage_[max_storage_]{};
349
350 public:
351 /// Construct with default values (disabled, zero timeout).
352 linger() noexcept = default;
353
354 /** Construct with explicit values.
355
356 @param enabled `true` to enable linger behavior on close.
357 @param timeout The linger timeout in seconds.
358 */
359 linger(bool enabled, int timeout) noexcept;
360
361 /// Return whether linger is enabled.
362 bool enabled() const noexcept;
363
364 /// Set whether linger is enabled.
365 void enabled(bool v) noexcept;
366
367 /// Return the linger timeout in seconds.
368 int timeout() const noexcept;
369
370 /// Set the linger timeout in seconds.
371 void timeout(int v) noexcept;
372
373 /// Return the protocol level.
374 static int level() noexcept;
375
376 /// Return the option name.
377 static int name() noexcept;
378
379 /// Return a pointer to the underlying storage.
380 10 void* data() noexcept
381 {
382 10 return storage_;
383 }
384
385 /// Return a pointer to the underlying storage.
386 18 void const* data() const noexcept
387 {
388 18 return storage_;
389 }
390
391 /// Return the size of the underlying storage.
392 std::size_t size() const noexcept;
393
394 /** Normalize after `getsockopt`.
395
396 No-op — `struct linger` is always returned at full size.
397
398 @param s The number of bytes actually written by `getsockopt`.
399 */
400 10 void resize(std::size_t) noexcept {}
401 };
402
403 } // namespace boost::corosio::socket_option
404
405 #endif // BOOST_COROSIO_SOCKET_OPTION_HPP
406