include/boost/corosio/native/native_socket_option.hpp

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