TLA Line data 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 HIT 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
|