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 { 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 HIT 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
|