include/boost/corosio/native/native_socket_option.hpp

98.8% Lines (163/165) 100.0% List of functions (121/121) 78.6% Branches (11/14)
native_socket_option.hpp
f(x) Functions (121)
Function Calls Lines Branches Blocks
boost::corosio::native_socket_option::boolean<41, 11>::boolean(bool) :91 1x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::boolean<6, 1>::boolean(bool) :91 3x 100.0% 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::boolean(bool) :91 1x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::boolean<65535, 4>::boolean(bool) :91 4x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::boolean<6, 1>::value() const :101 3x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::value() const :101 1x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::level() :119 5x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 27>::level() :119 7x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::level() :119 27x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::level() :119 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::level() :119 1332x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 8>::level() :119 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::name() :125 5x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 27>::name() :125 7x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::name() :125 27x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::name() :125 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::name() :125 1332x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 8>::name() :125 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::data() :131 3x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::data() :131 1x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::data() const :137 1x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::data() const :137 3x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::data() const :137 1x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::data() const :137 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::size() const :143 1x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::size() const :143 5x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::size() const :143 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::size() const :143 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::resize(unsigned long long) :154 2x 100.0% 75.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::resize(unsigned long long) :154 1x 75.0% 25.0% 33.3% boost::corosio::native_socket_option::integer<41, 10>::integer(int) :194 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::integer(int) :194 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::integer(int) :194 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::integer(int) :194 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::value() const :204 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::value() const :204 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::value() const :204 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::level() :210 3x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::level() :210 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::level() :210 8x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::level() :210 16x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::name() :216 3x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::name() :216 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::name() :216 8x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::name() :216 16x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::data() :222 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::data() :222 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::data() :222 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::data() const :228 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::data() const :228 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::data() const :228 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::data() const :228 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::size() const :234 1x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::size() const :234 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4097>::size() const :234 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::size() const :234 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::resize(unsigned long long) :243 1x 60.0% 50.0% 66.7% boost::corosio::native_socket_option::integer<65535, 4097>::resize(unsigned long long) :243 1x 60.0% 50.0% 66.7% boost::corosio::native_socket_option::integer<65535, 4098>::resize(unsigned long long) :243 1x 60.0% 50.0% 66.7% boost::corosio::native_socket_option::byte_boolean<0, 11>::byte_boolean(bool) :269 1x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::value() const :277 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::level() :281 7x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::name() :282 7x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::data() :284 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::data() const :285 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::size() const :286 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 11>::resize(unsigned long long) :288 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::byte_integer(int) :309 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::value() const :319 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::level() :321 4x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::name() :322 4x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::data() :324 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::data() const :325 1x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::size() const :326 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 10>::resize(unsigned long long) :328 1x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger() :355 2392x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger(bool, int) :362 2387x 100.0% 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled() const :369 10x 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled(bool) :375 2x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::linger::timeout() const :381 9x 100.0% 100.0% boost::corosio::native_socket_option::linger::timeout(int) :387 2x 100.0% 100.0% boost::corosio::native_socket_option::linger::level() :393 2393x 100.0% 100.0% boost::corosio::native_socket_option::linger::name() :399 2393x 100.0% 100.0% boost::corosio::native_socket_option::linger::data() :405 2404x 100.0% 100.0% boost::corosio::native_socket_option::linger::data() const :411 1x 100.0% 100.0% boost::corosio::native_socket_option::linger::size() const :417 4796x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4() :486 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :493 3x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::level() :503 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::name() :509 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::data() :515 3x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::data() const :521 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::size() const :527 6x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4() :550 1x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :557 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::level() :567 3x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::name() :573 3x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::data() :579 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::data() const :585 1x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::size() const :591 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6() :614 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6(boost::corosio::ipv6_address, unsigned int) :621 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::level() :629 3x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::name() :635 3x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::data() :641 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::data() const :647 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::size() const :653 4x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6() :676 1x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6(boost::corosio::ipv6_address, unsigned int) :683 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::level() :691 3x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::name() :697 3x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::data() :703 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::data() const :709 1x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::size() const :715 4x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4() :741 1x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4(boost::corosio::ipv4_address) :747 2x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::level() :754 3x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::name() :760 3x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::data() :766 2x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::data() const :772 1x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::size() const :778 4x 100.0% 100.0%
Line Branch 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 // Some older systems define only the legacy names
42 #ifndef IPV6_JOIN_GROUP
43 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
44 #endif
45 #ifndef IPV6_LEAVE_GROUP
46 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
47 #endif
48
49 #include <boost/corosio/ipv4_address.hpp>
50 #include <boost/corosio/ipv6_address.hpp>
51
52 #include <cstddef>
53 #include <cstring>
54
55 namespace boost::corosio::native_socket_option {
56
57 /** A socket option with a boolean value.
58
59 Models socket options whose underlying representation is an `int`
60 where 0 means disabled and non-zero means enabled. The option's
61 protocol level and name are encoded as template parameters.
62
63 This is the native (inline) variant that includes platform
64 headers. For a type-erased version that avoids platform
65 includes, use `boost::corosio::socket_option` instead.
66
67 @par Example
68 @code
69 sock.set_option( native_socket_option::no_delay( true ) );
70 auto nd = sock.get_option<native_socket_option::no_delay>();
71 if ( nd.value() )
72 // Nagle's algorithm is disabled
73 @endcode
74
75 @tparam Level The protocol level (e.g. `SOL_SOCKET`, `IPPROTO_TCP`).
76 @tparam Name The option name (e.g. `TCP_NODELAY`, `SO_KEEPALIVE`).
77 */
78 template<int Level, int Name>
79 class boolean
80 {
81 int value_ = 0;
82
83 public:
84 /// Construct with default value (disabled).
85 boolean() = default;
86
87 /** Construct with an explicit value.
88
89 @param v `true` to enable the option, `false` to disable.
90 */
91
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 4 taken 1 time.
9x explicit boolean(bool v) noexcept : value_(v ? 1 : 0) {}
92
93 /// Assign a new value.
94 boolean& operator=(bool v) noexcept
95 {
96 value_ = v ? 1 : 0;
97 return *this;
98 }
99
100 /// Return the option value.
101 4x bool value() const noexcept
102 {
103 4x return value_ != 0;
104 }
105
106 /// Return the option value.
107 explicit operator bool() const noexcept
108 {
109 return value_ != 0;
110 }
111
112 /// Return the negated option value.
113 bool operator!() const noexcept
114 {
115 return value_ == 0;
116 }
117
118 /// Return the protocol level for `setsockopt`/`getsockopt`.
119 1383x static constexpr int level() noexcept
120 {
121 1383x return Level;
122 }
123
124 /// Return the option name for `setsockopt`/`getsockopt`.
125 1383x static constexpr int name() noexcept
126 {
127 1383x return Name;
128 }
129
130 /// Return a pointer to the underlying storage.
131 4x void* data() noexcept
132 {
133 4x return &value_;
134 }
135
136 /// Return a pointer to the underlying storage.
137 9x void const* data() const noexcept
138 {
139 9x return &value_;
140 }
141
142 /// Return the size of the underlying storage.
143 12x std::size_t size() const noexcept
144 {
145 12x return sizeof(value_);
146 }
147
148 /** Normalize after `getsockopt` returns fewer bytes than expected.
149
150 Windows Vista+ may write only 1 byte for boolean options.
151
152 @param s The number of bytes actually written by `getsockopt`.
153 */
154 3x void resize(std::size_t s) noexcept
155 {
156
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 7 taken 1 time.
3x if (s == sizeof(char))
157
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
2x value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
158 3x }
159 };
160
161 /** A socket option with an integer value.
162
163 Models socket options whose underlying representation is a
164 plain `int`. The option's protocol level and name are encoded
165 as template parameters.
166
167 This is the native (inline) variant that includes platform
168 headers. For a type-erased version that avoids platform
169 includes, use `boost::corosio::socket_option` instead.
170
171 @par Example
172 @code
173 sock.set_option( native_socket_option::receive_buffer_size( 65536 ) );
174 auto opt = sock.get_option<native_socket_option::receive_buffer_size>();
175 int sz = opt.value();
176 @endcode
177
178 @tparam Level The protocol level (e.g. `SOL_SOCKET`).
179 @tparam Name The option name (e.g. `SO_RCVBUF`).
180 */
181 template<int Level, int Name>
182 class integer
183 {
184 int value_ = 0;
185
186 public:
187 /// Construct with default value (zero).
188 integer() = default;
189
190 /** Construct with an explicit value.
191
192 @param v The option value.
193 */
194 4x explicit integer(int v) noexcept : value_(v) {}
195
196 /// Assign a new value.
197 integer& operator=(int v) noexcept
198 {
199 value_ = v;
200 return *this;
201 }
202
203 /// Return the option value.
204 3x int value() const noexcept
205 {
206 3x return value_;
207 }
208
209 /// Return the protocol level for `setsockopt`/`getsockopt`.
210 31x static constexpr int level() noexcept
211 {
212 31x return Level;
213 }
214
215 /// Return the option name for `setsockopt`/`getsockopt`.
216 31x static constexpr int name() noexcept
217 {
218 31x return Name;
219 }
220
221 /// Return a pointer to the underlying storage.
222 3x void* data() noexcept
223 {
224 3x return &value_;
225 }
226
227 /// Return a pointer to the underlying storage.
228 4x void const* data() const noexcept
229 {
230 4x return &value_;
231 }
232
233 /// Return the size of the underlying storage.
234 7x std::size_t size() const noexcept
235 {
236 7x return sizeof(value_);
237 }
238
239 /** Normalize after `getsockopt` returns fewer bytes than expected.
240
241 @param s The number of bytes actually written by `getsockopt`.
242 */
243 3x void resize(std::size_t s) noexcept
244 {
245
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 3 times.
3x if (s == sizeof(char))
246 value_ =
247 static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
248 3x }
249 };
250
251 /** A boolean socket option with single-byte storage.
252
253 Some BSD-derived kernels (macOS, FreeBSD) require certain IPv4 multicast
254 options (`IP_MULTICAST_LOOP`) to be set with a one-byte value and return
255 `EINVAL` for the four-byte form that Linux accepts. This template
256 provides `unsigned char` storage so the option works on every platform.
257
258 @tparam Level The protocol level.
259 @tparam Name The option name.
260 */
261 template<int Level, int Name>
262 class byte_boolean
263 {
264 unsigned char value_ = 0;
265
266 public:
267 byte_boolean() = default;
268
269
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
1x explicit byte_boolean(bool v) noexcept : value_(v ? 1 : 0) {}
270
271 byte_boolean& operator=(bool v) noexcept
272 {
273 value_ = v ? 1 : 0;
274 return *this;
275 }
276
277 1x bool value() const noexcept { return value_ != 0; }
278 explicit operator bool() const noexcept { return value_ != 0; }
279 bool operator!() const noexcept { return value_ == 0; }
280
281 7x static constexpr int level() noexcept { return Level; }
282 7x static constexpr int name() noexcept { return Name; }
283
284 1x void* data() noexcept { return &value_; }
285 1x void const* data() const noexcept { return &value_; }
286 2x std::size_t size() const noexcept { return sizeof(value_); }
287
288 1x void resize(std::size_t) noexcept {}
289 };
290
291 /** An integer socket option with single-byte storage.
292
293 Same rationale as `byte_boolean`: BSD-derived kernels require
294 `IP_MULTICAST_TTL` to be set with a one-byte value. Linux accepts
295 one byte too, so single-byte storage is portable. Values are
296 truncated to the 0–255 range.
297
298 @tparam Level The protocol level.
299 @tparam Name The option name.
300 */
301 template<int Level, int Name>
302 class byte_integer
303 {
304 unsigned char value_ = 0;
305
306 public:
307 byte_integer() = default;
308
309 1x explicit byte_integer(int v) noexcept
310 1x : value_(static_cast<unsigned char>(v))
311 1x {}
312
313 byte_integer& operator=(int v) noexcept
314 {
315 value_ = static_cast<unsigned char>(v);
316 return *this;
317 }
318
319 1x int value() const noexcept { return value_; }
320
321 4x static constexpr int level() noexcept { return Level; }
322 4x static constexpr int name() noexcept { return Name; }
323
324 1x void* data() noexcept { return &value_; }
325 1x void const* data() const noexcept { return &value_; }
326 2x std::size_t size() const noexcept { return sizeof(value_); }
327
328 1x void resize(std::size_t) noexcept {}
329 };
330
331 /** The SO_LINGER socket option (native variant).
332
333 Controls behavior when closing a socket with unsent data.
334 When enabled, `close()` blocks until pending data is sent
335 or the timeout expires.
336
337 This variant stores the platform's `struct linger` directly,
338 avoiding the opaque-storage indirection of the type-erased
339 version.
340
341 @par Example
342 @code
343 sock.set_option( native_socket_option::linger( true, 5 ) );
344 auto opt = sock.get_option<native_socket_option::linger>();
345 if ( opt.enabled() )
346 std::cout << "linger timeout: " << opt.timeout() << "s\n";
347 @endcode
348 */
349 class linger
350 {
351 struct ::linger value_{};
352
353 public:
354 /// Construct with default values (disabled, zero timeout).
355 2392x linger() = default;
356
357 /** Construct with explicit values.
358
359 @param enabled `true` to enable linger behavior on close.
360 @param timeout The linger timeout in seconds.
361 */
362 2387x linger(bool enabled, int timeout) noexcept
363 2387x {
364
2/2
✓ Branch 2 → 3 taken 2386 times.
✓ Branch 2 → 4 taken 1 time.
2387x value_.l_onoff = enabled ? 1 : 0;
365 2387x value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
366 2387x }
367
368 /// Return whether linger is enabled.
369 10x bool enabled() const noexcept
370 {
371 10x return value_.l_onoff != 0;
372 }
373
374 /// Set whether linger is enabled.
375 2x void enabled(bool v) noexcept
376 {
377
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2x value_.l_onoff = v ? 1 : 0;
378 2x }
379
380 /// Return the linger timeout in seconds.
381 9x int timeout() const noexcept
382 {
383 9x return static_cast<int>(value_.l_linger);
384 }
385
386 /// Set the linger timeout in seconds.
387 2x void timeout(int v) noexcept
388 {
389 2x value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
390 2x }
391
392 /// Return the protocol level for `setsockopt`/`getsockopt`.
393 2393x static constexpr int level() noexcept
394 {
395 2393x return SOL_SOCKET;
396 }
397
398 /// Return the option name for `setsockopt`/`getsockopt`.
399 2393x static constexpr int name() noexcept
400 {
401 2393x return SO_LINGER;
402 }
403
404 /// Return a pointer to the underlying storage.
405 2404x void* data() noexcept
406 {
407 2404x return &value_;
408 }
409
410 /// Return a pointer to the underlying storage.
411 1x void const* data() const noexcept
412 {
413 1x return &value_;
414 }
415
416 /// Return the size of the underlying storage.
417 4796x std::size_t size() const noexcept
418 {
419 4796x return sizeof(value_);
420 }
421
422 /** Normalize after `getsockopt`.
423
424 No-op — `struct linger` is always returned at full size.
425
426 @param s The number of bytes actually written by `getsockopt`.
427 */
428 void resize(std::size_t) noexcept {}
429 };
430
431 /// Disable Nagle's algorithm (TCP_NODELAY).
432 using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
433
434 /// Enable periodic keepalive probes (SO_KEEPALIVE).
435 using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
436
437 /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
438 using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
439
440 /// Allow local address reuse (SO_REUSEADDR).
441 using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
442
443 /// Allow sending to broadcast addresses (SO_BROADCAST).
444 using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
445
446 /// Set the receive buffer size (SO_RCVBUF).
447 using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
448
449 /// Set the send buffer size (SO_SNDBUF).
450 using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
451
452 #ifdef SO_REUSEPORT
453 /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
454 using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
455 #endif
456
457 /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
458 using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
459
460 /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
461 using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
462
463 /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
464 using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>;
465
466 /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
467 using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
468
469 /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
470 using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
471
472 /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
473
474 @par Example
475 @code
476 sock.set_option( native_socket_option::join_group_v4(
477 ipv4_address( "239.255.0.1" ) ) );
478 @endcode
479 */
480 class join_group_v4
481 {
482 struct ip_mreq value_{};
483
484 public:
485 /// Construct with default values.
486 2x join_group_v4() = default;
487
488 /** Construct with a group and optional interface address.
489
490 @param group The multicast group address to join.
491 @param iface The local interface to use (default: any).
492 */
493 3x join_group_v4(
494 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
495 3x {
496 3x auto gb = group.to_bytes();
497 3x auto ib = iface.to_bytes();
498 3x std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
499 3x std::memcpy(&value_.imr_interface, ib.data(), 4);
500 3x }
501
502 /// Return the protocol level for `setsockopt`/`getsockopt`.
503 4x static constexpr int level() noexcept
504 {
505 4x return IPPROTO_IP;
506 }
507
508 /// Return the option name for `setsockopt`/`getsockopt`.
509 4x static constexpr int name() noexcept
510 {
511 4x return IP_ADD_MEMBERSHIP;
512 }
513
514 /// Return a pointer to the underlying storage.
515 3x void* data() noexcept
516 {
517 3x return &value_;
518 }
519
520 /// Return a pointer to the underlying storage.
521 1x void const* data() const noexcept
522 {
523 1x return &value_;
524 }
525
526 /// Return the size of the underlying storage.
527 6x std::size_t size() const noexcept
528 {
529 6x return sizeof(value_);
530 }
531
532 /// No-op resize.
533 void resize(std::size_t) noexcept {}
534 };
535
536 /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
537
538 @par Example
539 @code
540 sock.set_option( native_socket_option::leave_group_v4(
541 ipv4_address( "239.255.0.1" ) ) );
542 @endcode
543 */
544 class leave_group_v4
545 {
546 struct ip_mreq value_{};
547
548 public:
549 /// Construct with default values.
550 1x leave_group_v4() = default;
551
552 /** Construct with a group and optional interface address.
553
554 @param group The multicast group address to leave.
555 @param iface The local interface (default: any).
556 */
557 2x leave_group_v4(
558 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
559 2x {
560 2x auto gb = group.to_bytes();
561 2x auto ib = iface.to_bytes();
562 2x std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
563 2x std::memcpy(&value_.imr_interface, ib.data(), 4);
564 2x }
565
566 /// Return the protocol level for `setsockopt`/`getsockopt`.
567 3x static constexpr int level() noexcept
568 {
569 3x return IPPROTO_IP;
570 }
571
572 /// Return the option name for `setsockopt`/`getsockopt`.
573 3x static constexpr int name() noexcept
574 {
575 3x return IP_DROP_MEMBERSHIP;
576 }
577
578 /// Return a pointer to the underlying storage.
579 2x void* data() noexcept
580 {
581 2x return &value_;
582 }
583
584 /// Return a pointer to the underlying storage.
585 1x void const* data() const noexcept
586 {
587 1x return &value_;
588 }
589
590 /// Return the size of the underlying storage.
591 4x std::size_t size() const noexcept
592 {
593 4x return sizeof(value_);
594 }
595
596 /// No-op resize.
597 void resize(std::size_t) noexcept {}
598 };
599
600 /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
601
602 @par Example
603 @code
604 sock.set_option( native_socket_option::join_group_v6(
605 ipv6_address( "ff02::1" ), 0 ) );
606 @endcode
607 */
608 class join_group_v6
609 {
610 struct ipv6_mreq value_{};
611
612 public:
613 /// Construct with default values.
614 1x join_group_v6() = default;
615
616 /** Construct with a group and optional interface index.
617
618 @param group The multicast group address to join.
619 @param if_index The interface index (0 = kernel chooses).
620 */
621 2x join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
622 2x {
623 2x auto gb = group.to_bytes();
624 2x std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
625 2x value_.ipv6mr_interface = if_index;
626 2x }
627
628 /// Return the protocol level for `setsockopt`/`getsockopt`.
629 3x static constexpr int level() noexcept
630 {
631 3x return IPPROTO_IPV6;
632 }
633
634 /// Return the option name for `setsockopt`/`getsockopt`.
635 3x static constexpr int name() noexcept
636 {
637 3x return IPV6_JOIN_GROUP;
638 }
639
640 /// Return a pointer to the underlying storage.
641 2x void* data() noexcept
642 {
643 2x return &value_;
644 }
645
646 /// Return a pointer to the underlying storage.
647 1x void const* data() const noexcept
648 {
649 1x return &value_;
650 }
651
652 /// Return the size of the underlying storage.
653 4x std::size_t size() const noexcept
654 {
655 4x return sizeof(value_);
656 }
657
658 /// No-op resize.
659 void resize(std::size_t) noexcept {}
660 };
661
662 /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
663
664 @par Example
665 @code
666 sock.set_option( native_socket_option::leave_group_v6(
667 ipv6_address( "ff02::1" ), 0 ) );
668 @endcode
669 */
670 class leave_group_v6
671 {
672 struct ipv6_mreq value_{};
673
674 public:
675 /// Construct with default values.
676 1x leave_group_v6() = default;
677
678 /** Construct with a group and optional interface index.
679
680 @param group The multicast group address to leave.
681 @param if_index The interface index (0 = kernel chooses).
682 */
683 2x leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
684 2x {
685 2x auto gb = group.to_bytes();
686 2x std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
687 2x value_.ipv6mr_interface = if_index;
688 2x }
689
690 /// Return the protocol level for `setsockopt`/`getsockopt`.
691 3x static constexpr int level() noexcept
692 {
693 3x return IPPROTO_IPV6;
694 }
695
696 /// Return the option name for `setsockopt`/`getsockopt`.
697 3x static constexpr int name() noexcept
698 {
699 3x return IPV6_LEAVE_GROUP;
700 }
701
702 /// Return a pointer to the underlying storage.
703 2x void* data() noexcept
704 {
705 2x return &value_;
706 }
707
708 /// Return a pointer to the underlying storage.
709 1x void const* data() const noexcept
710 {
711 1x return &value_;
712 }
713
714 /// Return the size of the underlying storage.
715 4x std::size_t size() const noexcept
716 {
717 4x return sizeof(value_);
718 }
719
720 /// No-op resize.
721 void resize(std::size_t) noexcept {}
722 };
723
724 /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
725
726 Unlike the integer-based `multicast_interface_v6`, this option
727 takes an `ipv4_address` identifying the local interface.
728
729 @par Example
730 @code
731 sock.set_option( native_socket_option::multicast_interface_v4(
732 ipv4_address( "192.168.1.1" ) ) );
733 @endcode
734 */
735 class multicast_interface_v4
736 {
737 struct in_addr value_{};
738
739 public:
740 /// Construct with default values (INADDR_ANY).
741 1x multicast_interface_v4() = default;
742
743 /** Construct with an interface address.
744
745 @param iface The local interface address.
746 */
747 2x explicit multicast_interface_v4(ipv4_address iface) noexcept
748 2x {
749 2x auto b = iface.to_bytes();
750 2x std::memcpy(&value_, b.data(), 4);
751 2x }
752
753 /// Return the protocol level for `setsockopt`/`getsockopt`.
754 3x static constexpr int level() noexcept
755 {
756 3x return IPPROTO_IP;
757 }
758
759 /// Return the option name for `setsockopt`/`getsockopt`.
760 3x static constexpr int name() noexcept
761 {
762 3x return IP_MULTICAST_IF;
763 }
764
765 /// Return a pointer to the underlying storage.
766 2x void* data() noexcept
767 {
768 2x return &value_;
769 }
770
771 /// Return a pointer to the underlying storage.
772 1x void const* data() const noexcept
773 {
774 1x return &value_;
775 }
776
777 /// Return the size of the underlying storage.
778 4x std::size_t size() const noexcept
779 {
780 4x return sizeof(value_);
781 }
782
783 /// No-op resize.
784 void resize(std::size_t) noexcept {}
785 };
786
787 } // namespace boost::corosio::native_socket_option
788
789 #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
790