include/boost/corosio/native/native_socket_option.hpp

98.2% Lines (162/165) 100.0% List of functions (129/129)
native_socket_option.hpp
f(x) Functions (129)
Function Calls Lines Blocks
boost::corosio::native_socket_option::boolean<1, 15>::boolean(bool) :91 2x 100.0% 75.0% boost::corosio::native_socket_option::boolean<1, 2>::boolean(bool) :91 10x 100.0% 75.0% boost::corosio::native_socket_option::boolean<1, 6>::boolean(bool) :91 2x 100.0% 75.0% boost::corosio::native_socket_option::boolean<41, 19>::boolean(bool) :91 2x 100.0% 75.0% boost::corosio::native_socket_option::boolean<6, 1>::boolean(bool) :91 6x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::value() const :101 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::value() const :101 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::value() const :101 6x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::level() :119 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 2>::level() :119 225x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::level() :119 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 9>::level() :119 16x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 19>::level() :119 10x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 26>::level() :119 14x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::level() :119 54x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::name() :125 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 2>::name() :125 225x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::name() :125 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 9>::name() :125 16x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 19>::name() :125 10x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 26>::name() :125 14x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::name() :125 54x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::data() :131 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::data() :131 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::data() :131 6x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::data() const :137 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 2>::data() const :137 10x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::data() const :137 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 19>::data() const :137 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::data() const :137 6x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::size() const :143 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 2>::size() const :143 10x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 6>::size() const :143 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 19>::size() const :143 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::size() const :143 10x 100.0% 100.0% boost::corosio::native_socket_option::boolean<1, 15>::resize(unsigned long) :154 2x 75.0% 33.0% boost::corosio::native_socket_option::boolean<1, 6>::resize(unsigned long) :154 2x 75.0% 33.0% boost::corosio::native_socket_option::boolean<6, 1>::resize(unsigned long) :154 4x 75.0% 33.0% boost::corosio::native_socket_option::integer<1, 7>::integer(int) :194 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::integer(int) :194 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::integer(int) :194 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 18>::integer(int) :194 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::value() const :204 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::value() const :204 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::value() const :204 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::level() :210 18x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::level() :210 34x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::level() :210 8x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 18>::level() :210 6x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::name() :216 18x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::name() :216 34x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::name() :216 8x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 18>::name() :216 6x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::data() :222 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::data() :222 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::data() :222 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::data() const :228 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::data() const :228 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::data() const :228 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 18>::data() const :228 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::size() const :234 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 8>::size() const :234 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 17>::size() const :234 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 18>::size() const :234 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<1, 7>::resize(unsigned long) :243 2x 60.0% 67.0% boost::corosio::native_socket_option::integer<1, 8>::resize(unsigned long) :243 2x 60.0% 67.0% boost::corosio::native_socket_option::integer<41, 17>::resize(unsigned long) :243 2x 60.0% 67.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::byte_boolean(bool) :269 2x 100.0% 75.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::value() const :277 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::level() :281 14x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::name() :282 14x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::data() :284 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::data() const :285 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::size() const :286 4x 100.0% 100.0% boost::corosio::native_socket_option::byte_boolean<0, 34>::resize(unsigned long) :288 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::byte_integer(int) :309 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::value() const :319 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::level() :321 8x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::name() :322 8x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::data() :324 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::data() const :325 2x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::size() const :326 4x 100.0% 100.0% boost::corosio::native_socket_option::byte_integer<0, 33>::resize(unsigned long) :328 2x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger() :355 44x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger(bool, int) :362 34x 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled() const :369 20x 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled(bool) :375 4x 100.0% 75.0% boost::corosio::native_socket_option::linger::timeout() const :381 18x 100.0% 100.0% boost::corosio::native_socket_option::linger::timeout(int) :387 4x 100.0% 100.0% boost::corosio::native_socket_option::linger::level() :393 46x 100.0% 100.0% boost::corosio::native_socket_option::linger::name() :399 46x 100.0% 100.0% boost::corosio::native_socket_option::linger::data() :405 68x 100.0% 100.0% boost::corosio::native_socket_option::linger::data() const :411 2x 100.0% 100.0% boost::corosio::native_socket_option::linger::size() const :417 112x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4() :486 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :493 6x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::level() :503 8x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::name() :509 8x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::data() :515 6x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::data() const :521 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::size() const :527 12x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4() :550 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :557 4x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::level() :567 6x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::name() :573 6x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::data() :579 4x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::data() const :585 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::size() const :591 8x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6() :614 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6(boost::corosio::ipv6_address, unsigned int) :621 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::level() :629 6x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::name() :635 6x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::data() :641 4x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::data() const :647 2x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v6::size() const :653 8x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6() :676 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6(boost::corosio::ipv6_address, unsigned int) :683 4x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::level() :691 6x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::name() :697 6x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::data() :703 4x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::data() const :709 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v6::size() const :715 8x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4() :741 2x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4(boost::corosio::ipv4_address) :747 4x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::level() :754 6x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::name() :760 6x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::data() :766 4x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::data() const :772 2x 100.0% 100.0% boost::corosio::native_socket_option::multicast_interface_v4::size() const :778 8x 100.0% 100.0%
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 // 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 22x 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 10x bool value() const noexcept
102 {
103 10x 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 335x static constexpr int level() noexcept
120 {
121 335x return Level;
122 }
123
124 /// Return the option name for `setsockopt`/`getsockopt`.
125 335x static constexpr int name() noexcept
126 {
127 335x return Name;
128 }
129
130 /// Return a pointer to the underlying storage.
131 10x void* data() noexcept
132 {
133 10x return &value_;
134 }
135
136 /// Return a pointer to the underlying storage.
137 22x void const* data() const noexcept
138 {
139 22x return &value_;
140 }
141
142 /// Return the size of the underlying storage.
143 30x std::size_t size() const noexcept
144 {
145 30x 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 8x void resize(std::size_t s) noexcept
155 {
156 8x if (s == sizeof(char))
157 value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
158 8x }
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 8x 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 6x int value() const noexcept
205 {
206 6x return value_;
207 }
208
209 /// Return the protocol level for `setsockopt`/`getsockopt`.
210 66x static constexpr int level() noexcept
211 {
212 66x return Level;
213 }
214
215 /// Return the option name for `setsockopt`/`getsockopt`.
216 66x static constexpr int name() noexcept
217 {
218 66x return Name;
219 }
220
221 /// Return a pointer to the underlying storage.
222 6x void* data() noexcept
223 {
224 6x return &value_;
225 }
226
227 /// Return a pointer to the underlying storage.
228 8x void const* data() const noexcept
229 {
230 8x return &value_;
231 }
232
233 /// Return the size of the underlying storage.
234 14x std::size_t size() const noexcept
235 {
236 14x 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 6x void resize(std::size_t s) noexcept
244 {
245 6x if (s == sizeof(char))
246 value_ =
247 static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
248 6x }
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 2x 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 2x 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 14x static constexpr int level() noexcept { return Level; }
282 14x static constexpr int name() noexcept { return Name; }
283
284 2x void* data() noexcept { return &value_; }
285 2x void const* data() const noexcept { return &value_; }
286 4x std::size_t size() const noexcept { return sizeof(value_); }
287
288 2x 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 2x explicit byte_integer(int v) noexcept
310 2x : value_(static_cast<unsigned char>(v))
311 2x {}
312
313 byte_integer& operator=(int v) noexcept
314 {
315 value_ = static_cast<unsigned char>(v);
316 return *this;
317 }
318
319 2x int value() const noexcept { return value_; }
320
321 8x static constexpr int level() noexcept { return Level; }
322 8x static constexpr int name() noexcept { return Name; }
323
324 2x void* data() noexcept { return &value_; }
325 2x void const* data() const noexcept { return &value_; }
326 4x std::size_t size() const noexcept { return sizeof(value_); }
327
328 2x 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 44x 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 34x linger(bool enabled, int timeout) noexcept
363 34x {
364 34x value_.l_onoff = enabled ? 1 : 0;
365 34x value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
366 34x }
367
368 /// Return whether linger is enabled.
369 20x bool enabled() const noexcept
370 {
371 20x return value_.l_onoff != 0;
372 }
373
374 /// Set whether linger is enabled.
375 4x void enabled(bool v) noexcept
376 {
377 4x value_.l_onoff = v ? 1 : 0;
378 4x }
379
380 /// Return the linger timeout in seconds.
381 18x int timeout() const noexcept
382 {
383 18x return static_cast<int>(value_.l_linger);
384 }
385
386 /// Set the linger timeout in seconds.
387 4x void timeout(int v) noexcept
388 {
389 4x value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
390 4x }
391
392 /// Return the protocol level for `setsockopt`/`getsockopt`.
393 46x static constexpr int level() noexcept
394 {
395 46x return SOL_SOCKET;
396 }
397
398 /// Return the option name for `setsockopt`/`getsockopt`.
399 46x static constexpr int name() noexcept
400 {
401 46x return SO_LINGER;
402 }
403
404 /// Return a pointer to the underlying storage.
405 68x void* data() noexcept
406 {
407 68x return &value_;
408 }
409
410 /// Return a pointer to the underlying storage.
411 2x void const* data() const noexcept
412 {
413 2x return &value_;
414 }
415
416 /// Return the size of the underlying storage.
417 112x std::size_t size() const noexcept
418 {
419 112x 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 4x 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 6x join_group_v4(
494 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
495 6x {
496 6x auto gb = group.to_bytes();
497 6x auto ib = iface.to_bytes();
498 6x std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
499 6x std::memcpy(&value_.imr_interface, ib.data(), 4);
500 6x }
501
502 /// Return the protocol level for `setsockopt`/`getsockopt`.
503 8x static constexpr int level() noexcept
504 {
505 8x return IPPROTO_IP;
506 }
507
508 /// Return the option name for `setsockopt`/`getsockopt`.
509 8x static constexpr int name() noexcept
510 {
511 8x return IP_ADD_MEMBERSHIP;
512 }
513
514 /// Return a pointer to the underlying storage.
515 6x void* data() noexcept
516 {
517 6x return &value_;
518 }
519
520 /// Return a pointer to the underlying storage.
521 2x void const* data() const noexcept
522 {
523 2x return &value_;
524 }
525
526 /// Return the size of the underlying storage.
527 12x std::size_t size() const noexcept
528 {
529 12x 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 2x 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 4x leave_group_v4(
558 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
559 4x {
560 4x auto gb = group.to_bytes();
561 4x auto ib = iface.to_bytes();
562 4x std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
563 4x std::memcpy(&value_.imr_interface, ib.data(), 4);
564 4x }
565
566 /// Return the protocol level for `setsockopt`/`getsockopt`.
567 6x static constexpr int level() noexcept
568 {
569 6x return IPPROTO_IP;
570 }
571
572 /// Return the option name for `setsockopt`/`getsockopt`.
573 6x static constexpr int name() noexcept
574 {
575 6x return IP_DROP_MEMBERSHIP;
576 }
577
578 /// Return a pointer to the underlying storage.
579 4x void* data() noexcept
580 {
581 4x return &value_;
582 }
583
584 /// Return a pointer to the underlying storage.
585 2x void const* data() const noexcept
586 {
587 2x return &value_;
588 }
589
590 /// Return the size of the underlying storage.
591 8x std::size_t size() const noexcept
592 {
593 8x 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 2x 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 4x join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
622 4x {
623 4x auto gb = group.to_bytes();
624 4x std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
625 4x value_.ipv6mr_interface = if_index;
626 4x }
627
628 /// Return the protocol level for `setsockopt`/`getsockopt`.
629 6x static constexpr int level() noexcept
630 {
631 6x return IPPROTO_IPV6;
632 }
633
634 /// Return the option name for `setsockopt`/`getsockopt`.
635 6x static constexpr int name() noexcept
636 {
637 6x return IPV6_JOIN_GROUP;
638 }
639
640 /// Return a pointer to the underlying storage.
641 4x void* data() noexcept
642 {
643 4x return &value_;
644 }
645
646 /// Return a pointer to the underlying storage.
647 2x void const* data() const noexcept
648 {
649 2x return &value_;
650 }
651
652 /// Return the size of the underlying storage.
653 8x std::size_t size() const noexcept
654 {
655 8x 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 2x 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 4x leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
684 4x {
685 4x auto gb = group.to_bytes();
686 4x std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
687 4x value_.ipv6mr_interface = if_index;
688 4x }
689
690 /// Return the protocol level for `setsockopt`/`getsockopt`.
691 6x static constexpr int level() noexcept
692 {
693 6x return IPPROTO_IPV6;
694 }
695
696 /// Return the option name for `setsockopt`/`getsockopt`.
697 6x static constexpr int name() noexcept
698 {
699 6x return IPV6_LEAVE_GROUP;
700 }
701
702 /// Return a pointer to the underlying storage.
703 4x void* data() noexcept
704 {
705 4x return &value_;
706 }
707
708 /// Return a pointer to the underlying storage.
709 2x void const* data() const noexcept
710 {
711 2x return &value_;
712 }
713
714 /// Return the size of the underlying storage.
715 8x std::size_t size() const noexcept
716 {
717 8x 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 2x multicast_interface_v4() = default;
742
743 /** Construct with an interface address.
744
745 @param iface The local interface address.
746 */
747 4x explicit multicast_interface_v4(ipv4_address iface) noexcept
748 4x {
749 4x auto b = iface.to_bytes();
750 4x std::memcpy(&value_, b.data(), 4);
751 4x }
752
753 /// Return the protocol level for `setsockopt`/`getsockopt`.
754 6x static constexpr int level() noexcept
755 {
756 6x return IPPROTO_IP;
757 }
758
759 /// Return the option name for `setsockopt`/`getsockopt`.
760 6x static constexpr int name() noexcept
761 {
762 6x return IP_MULTICAST_IF;
763 }
764
765 /// Return a pointer to the underlying storage.
766 4x void* data() noexcept
767 {
768 4x return &value_;
769 }
770
771 /// Return a pointer to the underlying storage.
772 2x void const* data() const noexcept
773 {
774 2x return &value_;
775 }
776
777 /// Return the size of the underlying storage.
778 8x std::size_t size() const noexcept
779 {
780 8x 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