include/boost/corosio/native/native_socket_option.hpp

100.0% Lines (21/21) 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 { return value_ != 0; }
90
91 /// Return the option value.
92 explicit operator bool() const noexcept { return value_ != 0; }
93
94 /// Return the negated option value.
95 bool operator!() const noexcept { return value_ == 0; }
96
97 /// Return the protocol level for `setsockopt`/`getsockopt`.
98 207 static constexpr int level() noexcept { return Level; }
99
100 /// Return the option name for `setsockopt`/`getsockopt`.
101 207 static constexpr int name() noexcept { return Name; }
102
103 /// Return a pointer to the underlying storage.
104 void* data() noexcept { return &value_; }
105
106 /// Return a pointer to the underlying storage.
107 void const* data() const noexcept { return &value_; }
108
109 /// Return the size of the underlying storage.
110 std::size_t size() const noexcept { return sizeof( value_ ); }
111
112 /** Normalize after `getsockopt` returns fewer bytes than expected.
113
114 Windows Vista+ may write only 1 byte for boolean options.
115
116 @param s The number of bytes actually written by `getsockopt`.
117 */
118 void resize( std::size_t s ) noexcept
119 {
120 if ( s == sizeof( char ) )
121 value_ = *reinterpret_cast<unsigned char*>( &value_ ) ? 1 : 0;
122 }
123 };
124
125 /** A socket option with an integer value.
126
127 Models socket options whose underlying representation is a
128 plain `int`. The option's protocol level and name are encoded
129 as template parameters.
130
131 This is the native (inline) variant that includes platform
132 headers. For a type-erased version that avoids platform
133 includes, use `boost::corosio::socket_option` instead.
134
135 @par Example
136 @code
137 sock.set_option( native_socket_option::receive_buffer_size( 65536 ) );
138 auto opt = sock.get_option<native_socket_option::receive_buffer_size>();
139 int sz = opt.value();
140 @endcode
141
142 @tparam Level The protocol level (e.g. `SOL_SOCKET`).
143 @tparam Name The option name (e.g. `SO_RCVBUF`).
144 */
145 template<int Level, int Name>
146 class integer
147 {
148 int value_ = 0;
149
150 public:
151 /// Construct with default value (zero).
152 integer() = default;
153
154 /** Construct with an explicit value.
155
156 @param v The option value.
157 */
158 explicit integer( int v ) noexcept : value_( v ) {}
159
160 /// Assign a new value.
161 integer& operator=( int v ) noexcept
162 {
163 value_ = v;
164 return *this;
165 }
166
167 /// Return the option value.
168 int value() const noexcept { return value_; }
169
170 /// Return the protocol level for `setsockopt`/`getsockopt`.
171 24 static constexpr int level() noexcept { return Level; }
172
173 /// Return the option name for `setsockopt`/`getsockopt`.
174 24 static constexpr int name() noexcept { return Name; }
175
176 /// Return a pointer to the underlying storage.
177 void* data() noexcept { return &value_; }
178
179 /// Return a pointer to the underlying storage.
180 void const* data() const noexcept { return &value_; }
181
182 /// Return the size of the underlying storage.
183 std::size_t size() const noexcept { return sizeof( value_ ); }
184
185 /** Normalize after `getsockopt` returns fewer bytes than expected.
186
187 @param s The number of bytes actually written by `getsockopt`.
188 */
189 void resize( std::size_t s ) noexcept
190 {
191 if ( s == sizeof( char ) )
192 value_ = static_cast<int>(
193 *reinterpret_cast<unsigned char*>( &value_ ) );
194 }
195 };
196
197 /** The SO_LINGER socket option (native variant).
198
199 Controls behavior when closing a socket with unsent data.
200 When enabled, `close()` blocks until pending data is sent
201 or the timeout expires.
202
203 This variant stores the platform's `struct linger` directly,
204 avoiding the opaque-storage indirection of the type-erased
205 version.
206
207 @par Example
208 @code
209 sock.set_option( native_socket_option::linger( true, 5 ) );
210 auto opt = sock.get_option<native_socket_option::linger>();
211 if ( opt.enabled() )
212 std::cout << "linger timeout: " << opt.timeout() << "s\n";
213 @endcode
214 */
215 class linger
216 {
217 struct ::linger value_{};
218
219 public:
220 /// Construct with default values (disabled, zero timeout).
221 28 linger() = default;
222
223 /** Construct with explicit values.
224
225 @param enabled `true` to enable linger behavior on close.
226 @param timeout The linger timeout in seconds.
227 */
228 16 linger( bool enabled, int timeout ) noexcept
229 16 {
230 16 value_.l_onoff = enabled ? 1 : 0;
231 16 value_.l_linger =
232 static_cast<decltype( value_.l_linger )>( timeout );
233 16 }
234
235 /// Return whether linger is enabled.
236 14 bool enabled() const noexcept { return value_.l_onoff != 0; }
237
238 /// Set whether linger is enabled.
239 2 void enabled( bool v ) noexcept { value_.l_onoff = v ? 1 : 0; }
240
241 /// Return the linger timeout in seconds.
242 12 int timeout() const noexcept
243 {
244 12 return static_cast<int>( value_.l_linger );
245 }
246
247 /// Set the linger timeout in seconds.
248 2 void timeout( int v ) noexcept
249 {
250 2 value_.l_linger =
251 static_cast<decltype( value_.l_linger )>( v );
252 2 }
253
254 /// Return the protocol level for `setsockopt`/`getsockopt`.
255 28 static constexpr int level() noexcept { return SOL_SOCKET; }
256
257 /// Return the option name for `setsockopt`/`getsockopt`.
258 28 static constexpr int name() noexcept { return SO_LINGER; }
259
260 /// Return a pointer to the underlying storage.
261 50 void* data() noexcept { return &value_; }
262
263 /// Return a pointer to the underlying storage.
264 void const* data() const noexcept { return &value_; }
265
266 /// Return the size of the underlying storage.
267 78 std::size_t size() const noexcept { return sizeof( value_ ); }
268
269 /** Normalize after `getsockopt`.
270
271 No-op — `struct linger` is always returned at full size.
272
273 @param s The number of bytes actually written by `getsockopt`.
274 */
275 void resize( std::size_t ) noexcept {}
276 };
277
278 /// Disable Nagle's algorithm (TCP_NODELAY).
279 using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
280
281 /// Enable periodic keepalive probes (SO_KEEPALIVE).
282 using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
283
284 /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
285 using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
286
287 /// Allow local address reuse (SO_REUSEADDR).
288 using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
289
290 /// Set the receive buffer size (SO_RCVBUF).
291 using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
292
293 /// Set the send buffer size (SO_SNDBUF).
294 using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
295
296 #ifdef SO_REUSEPORT
297 /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
298 using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
299 #endif
300
301 } // namespace boost::corosio::native_socket_option
302
303 #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
304