include/boost/corosio/native/native_socket_option.hpp

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