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