include/boost/corosio/native/native_socket_option.hpp

46.9% Lines (53/113) 61.2% List of functions (41/67) 66.7% Branches (4/6)
f(x) Functions (67)
Function Calls Lines Branches Blocks
boost::corosio::native_socket_option::boolean<65535, 4>::boolean(bool) :91 3x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::boolean<0, 11>::level() :119 5x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::level() :119 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 27>::level() :119 7x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::level() :119 21x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::level() :119 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::level() :119 1175x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 8>::level() :119 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<0, 11>::name() :125 5x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 11>::name() :125 4x 100.0% 100.0% boost::corosio::native_socket_option::boolean<41, 27>::name() :125 7x 100.0% 100.0% boost::corosio::native_socket_option::boolean<6, 1>::name() :125 21x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 32>::name() :125 2x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::name() :125 1175x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 8>::name() :125 8x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::data() const :137 3x 100.0% 100.0% boost::corosio::native_socket_option::boolean<65535, 4>::size() const :143 3x 100.0% 100.0% boost::corosio::native_socket_option::integer<0, 10>::level() :210 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::level() :210 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::level() :210 0 0.0% 0.0% boost::corosio::native_socket_option::integer<65535, 4097>::level() :210 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::level() :210 10x 100.0% 100.0% boost::corosio::native_socket_option::integer<0, 10>::name() :216 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 10>::name() :216 2x 100.0% 100.0% boost::corosio::native_socket_option::integer<41, 9>::name() :216 0 0.0% 0.0% boost::corosio::native_socket_option::integer<65535, 4097>::name() :216 4x 100.0% 100.0% boost::corosio::native_socket_option::integer<65535, 4098>::name() :216 10x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger() :275 2126x 100.0% 100.0% boost::corosio::native_socket_option::linger::linger(bool, int) :282 2120x 100.0% 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled() const :289 7x 100.0% 100.0% boost::corosio::native_socket_option::linger::enabled(bool) :295 1x 100.0% 50.0% 75.0% boost::corosio::native_socket_option::linger::timeout() const :301 6x 100.0% 100.0% boost::corosio::native_socket_option::linger::timeout(int) :307 1x 100.0% 100.0% boost::corosio::native_socket_option::linger::level() :313 2126x 100.0% 100.0% boost::corosio::native_socket_option::linger::name() :319 2126x 100.0% 100.0% boost::corosio::native_socket_option::linger::data() :325 2137x 100.0% 100.0% boost::corosio::native_socket_option::linger::size() const :337 4263x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4() :406 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::join_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :413 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::level() :423 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::name() :429 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::data() :435 1x 100.0% 100.0% boost::corosio::native_socket_option::join_group_v4::size() const :447 2x 100.0% 100.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4() :470 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v4::leave_group_v4(boost::corosio::ipv4_address, boost::corosio::ipv4_address) :477 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v4::level() :487 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v4::name() :493 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v4::data() :499 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v4::size() const :511 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6() :534 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::join_group_v6(boost::corosio::ipv6_address, unsigned int) :541 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::level() :549 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::name() :555 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::data() :561 0 0.0% 0.0% boost::corosio::native_socket_option::join_group_v6::size() const :573 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6() :596 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::leave_group_v6(boost::corosio::ipv6_address, unsigned int) :603 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::level() :611 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::name() :617 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::data() :623 0 0.0% 0.0% boost::corosio::native_socket_option::leave_group_v6::size() const :635 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4() :661 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::multicast_interface_v4(boost::corosio::ipv4_address) :667 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::level() :674 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::name() :680 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::data() :686 0 0.0% 0.0% boost::corosio::native_socket_option::multicast_interface_v4::size() const :698 0 0.0% 0.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 /** @file native_socket_option.hpp
11
12 Inline socket option types using platform-specific constants.
13 All methods are `constexpr` or trivially inlined, giving zero
14 overhead compared to hand-written `setsockopt` calls.
15
16 This header includes platform socket headers
17 (`<sys/socket.h>`, `<netinet/tcp.h>`, etc.).
18 For a version that avoids platform includes, use
19 `<boost/corosio/socket_option.hpp>`
20 (`boost::corosio::socket_option`).
21
22 Both variants satisfy the same option-type interface and work
23 interchangeably with `tcp_socket::set_option` /
24 `tcp_socket::get_option` and the corresponding acceptor methods.
25
26 @see boost::corosio::socket_option
27 */
28
29 #ifndef BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
30 #define BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
31
32 #ifdef _WIN32
33 #include <winsock2.h>
34 #include <ws2tcpip.h>
35 #else
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <sys/socket.h>
39 #endif
40
41 // Some older systems define only the legacy names
42 #ifndef IPV6_JOIN_GROUP
43 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
44 #endif
45 #ifndef IPV6_LEAVE_GROUP
46 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
47 #endif
48
49 #include <boost/corosio/ipv4_address.hpp>
50 #include <boost/corosio/ipv6_address.hpp>
51
52 #include <cstddef>
53 #include <cstring>
54
55 namespace boost::corosio::native_socket_option {
56
57 /** A socket option with a boolean value.
58
59 Models socket options whose underlying representation is an `int`
60 where 0 means disabled and non-zero means enabled. The option's
61 protocol level and name are encoded as template parameters.
62
63 This is the native (inline) variant that includes platform
64 headers. For a type-erased version that avoids platform
65 includes, use `boost::corosio::socket_option` instead.
66
67 @par Example
68 @code
69 sock.set_option( native_socket_option::no_delay( true ) );
70 auto nd = sock.get_option<native_socket_option::no_delay>();
71 if ( nd.value() )
72 // Nagle's algorithm is disabled
73 @endcode
74
75 @tparam Level The protocol level (e.g. `SOL_SOCKET`, `IPPROTO_TCP`).
76 @tparam Name The option name (e.g. `TCP_NODELAY`, `SO_KEEPALIVE`).
77 */
78 template<int Level, int Name>
79 class boolean
80 {
81 int value_ = 0;
82
83 public:
84 /// Construct with default value (disabled).
85 boolean() = default;
86
87 /** Construct with an explicit value.
88
89 @param v `true` to enable the option, `false` to disable.
90 */
91
1/2
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 4 not taken.
3x 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 bool value() const noexcept
102 {
103 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 1222x static constexpr int level() noexcept
120 {
121 1222x return Level;
122 }
123
124 /// Return the option name for `setsockopt`/`getsockopt`.
125 1222x static constexpr int name() noexcept
126 {
127 1222x return Name;
128 }
129
130 /// Return a pointer to the underlying storage.
131 void* data() noexcept
132 {
133 return &value_;
134 }
135
136 /// Return a pointer to the underlying storage.
137 3x void const* data() const noexcept
138 {
139 3x return &value_;
140 }
141
142 /// Return the size of the underlying storage.
143 3x std::size_t size() const noexcept
144 {
145 3x 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 void resize(std::size_t s) noexcept
155 {
156 if (s == sizeof(char))
157 value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
158 }
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 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 int value() const noexcept
205 {
206 return value_;
207 }
208
209 /// Return the protocol level for `setsockopt`/`getsockopt`.
210 18x static constexpr int level() noexcept
211 {
212 18x return Level;
213 }
214
215 /// Return the option name for `setsockopt`/`getsockopt`.
216 18x static constexpr int name() noexcept
217 {
218 18x return Name;
219 }
220
221 /// Return a pointer to the underlying storage.
222 void* data() noexcept
223 {
224 return &value_;
225 }
226
227 /// Return a pointer to the underlying storage.
228 void const* data() const noexcept
229 {
230 return &value_;
231 }
232
233 /// Return the size of the underlying storage.
234 std::size_t size() const noexcept
235 {
236 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 void resize(std::size_t s) noexcept
244 {
245 if (s == sizeof(char))
246 value_ =
247 static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
248 }
249 };
250
251 /** The SO_LINGER socket option (native variant).
252
253 Controls behavior when closing a socket with unsent data.
254 When enabled, `close()` blocks until pending data is sent
255 or the timeout expires.
256
257 This variant stores the platform's `struct linger` directly,
258 avoiding the opaque-storage indirection of the type-erased
259 version.
260
261 @par Example
262 @code
263 sock.set_option( native_socket_option::linger( true, 5 ) );
264 auto opt = sock.get_option<native_socket_option::linger>();
265 if ( opt.enabled() )
266 std::cout << "linger timeout: " << opt.timeout() << "s\n";
267 @endcode
268 */
269 class linger
270 {
271 struct ::linger value_{};
272
273 public:
274 /// Construct with default values (disabled, zero timeout).
275 2126x linger() = default;
276
277 /** Construct with explicit values.
278
279 @param enabled `true` to enable linger behavior on close.
280 @param timeout The linger timeout in seconds.
281 */
282 2120x linger(bool enabled, int timeout) noexcept
283 2120x {
284
2/2
✓ Branch 2 → 3 taken 2119 times.
✓ Branch 2 → 4 taken 1 time.
2120x value_.l_onoff = enabled ? 1 : 0;
285 2120x value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
286 2120x }
287
288 /// Return whether linger is enabled.
289 7x bool enabled() const noexcept
290 {
291 7x return value_.l_onoff != 0;
292 }
293
294 /// Set whether linger is enabled.
295 1x void enabled(bool v) noexcept
296 {
297
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
1x value_.l_onoff = v ? 1 : 0;
298 1x }
299
300 /// Return the linger timeout in seconds.
301 6x int timeout() const noexcept
302 {
303 6x return static_cast<int>(value_.l_linger);
304 }
305
306 /// Set the linger timeout in seconds.
307 1x void timeout(int v) noexcept
308 {
309 1x value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
310 1x }
311
312 /// Return the protocol level for `setsockopt`/`getsockopt`.
313 2126x static constexpr int level() noexcept
314 {
315 2126x return SOL_SOCKET;
316 }
317
318 /// Return the option name for `setsockopt`/`getsockopt`.
319 2126x static constexpr int name() noexcept
320 {
321 2126x return SO_LINGER;
322 }
323
324 /// Return a pointer to the underlying storage.
325 2137x void* data() noexcept
326 {
327 2137x return &value_;
328 }
329
330 /// Return a pointer to the underlying storage.
331 void const* data() const noexcept
332 {
333 return &value_;
334 }
335
336 /// Return the size of the underlying storage.
337 4263x std::size_t size() const noexcept
338 {
339 4263x return sizeof(value_);
340 }
341
342 /** Normalize after `getsockopt`.
343
344 No-op — `struct linger` is always returned at full size.
345
346 @param s The number of bytes actually written by `getsockopt`.
347 */
348 void resize(std::size_t) noexcept {}
349 };
350
351 /// Disable Nagle's algorithm (TCP_NODELAY).
352 using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
353
354 /// Enable periodic keepalive probes (SO_KEEPALIVE).
355 using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
356
357 /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
358 using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
359
360 /// Allow local address reuse (SO_REUSEADDR).
361 using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
362
363 /// Allow sending to broadcast addresses (SO_BROADCAST).
364 using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
365
366 /// Set the receive buffer size (SO_RCVBUF).
367 using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
368
369 /// Set the send buffer size (SO_SNDBUF).
370 using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
371
372 #ifdef SO_REUSEPORT
373 /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
374 using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
375 #endif
376
377 /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
378 using multicast_loop_v4 = boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
379
380 /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
381 using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
382
383 /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
384 using multicast_hops_v4 = integer<IPPROTO_IP, IP_MULTICAST_TTL>;
385
386 /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
387 using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
388
389 /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
390 using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
391
392 /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
393
394 @par Example
395 @code
396 sock.set_option( native_socket_option::join_group_v4(
397 ipv4_address( "239.255.0.1" ) ) );
398 @endcode
399 */
400 class join_group_v4
401 {
402 struct ip_mreq value_{};
403
404 public:
405 /// Construct with default values.
406 1x join_group_v4() = default;
407
408 /** Construct with a group and optional interface address.
409
410 @param group The multicast group address to join.
411 @param iface The local interface to use (default: any).
412 */
413 1x join_group_v4(
414 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
415 1x {
416 1x auto gb = group.to_bytes();
417 1x auto ib = iface.to_bytes();
418 1x std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
419 1x std::memcpy(&value_.imr_interface, ib.data(), 4);
420 1x }
421
422 /// Return the protocol level for `setsockopt`/`getsockopt`.
423 1x static constexpr int level() noexcept
424 {
425 1x return IPPROTO_IP;
426 }
427
428 /// Return the option name for `setsockopt`/`getsockopt`.
429 1x static constexpr int name() noexcept
430 {
431 1x return IP_ADD_MEMBERSHIP;
432 }
433
434 /// Return a pointer to the underlying storage.
435 1x void* data() noexcept
436 {
437 1x return &value_;
438 }
439
440 /// Return a pointer to the underlying storage.
441 void const* data() const noexcept
442 {
443 return &value_;
444 }
445
446 /// Return the size of the underlying storage.
447 2x std::size_t size() const noexcept
448 {
449 2x return sizeof(value_);
450 }
451
452 /// No-op resize.
453 void resize(std::size_t) noexcept {}
454 };
455
456 /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
457
458 @par Example
459 @code
460 sock.set_option( native_socket_option::leave_group_v4(
461 ipv4_address( "239.255.0.1" ) ) );
462 @endcode
463 */
464 class leave_group_v4
465 {
466 struct ip_mreq value_{};
467
468 public:
469 /// Construct with default values.
470 leave_group_v4() = default;
471
472 /** Construct with a group and optional interface address.
473
474 @param group The multicast group address to leave.
475 @param iface The local interface (default: any).
476 */
477 leave_group_v4(
478 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
479 {
480 auto gb = group.to_bytes();
481 auto ib = iface.to_bytes();
482 std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
483 std::memcpy(&value_.imr_interface, ib.data(), 4);
484 }
485
486 /// Return the protocol level for `setsockopt`/`getsockopt`.
487 static constexpr int level() noexcept
488 {
489 return IPPROTO_IP;
490 }
491
492 /// Return the option name for `setsockopt`/`getsockopt`.
493 static constexpr int name() noexcept
494 {
495 return IP_DROP_MEMBERSHIP;
496 }
497
498 /// Return a pointer to the underlying storage.
499 void* data() noexcept
500 {
501 return &value_;
502 }
503
504 /// Return a pointer to the underlying storage.
505 void const* data() const noexcept
506 {
507 return &value_;
508 }
509
510 /// Return the size of the underlying storage.
511 std::size_t size() const noexcept
512 {
513 return sizeof(value_);
514 }
515
516 /// No-op resize.
517 void resize(std::size_t) noexcept {}
518 };
519
520 /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
521
522 @par Example
523 @code
524 sock.set_option( native_socket_option::join_group_v6(
525 ipv6_address( "ff02::1" ), 0 ) );
526 @endcode
527 */
528 class join_group_v6
529 {
530 struct ipv6_mreq value_{};
531
532 public:
533 /// Construct with default values.
534 join_group_v6() = default;
535
536 /** Construct with a group and optional interface index.
537
538 @param group The multicast group address to join.
539 @param if_index The interface index (0 = kernel chooses).
540 */
541 join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
542 {
543 auto gb = group.to_bytes();
544 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
545 value_.ipv6mr_interface = if_index;
546 }
547
548 /// Return the protocol level for `setsockopt`/`getsockopt`.
549 static constexpr int level() noexcept
550 {
551 return IPPROTO_IPV6;
552 }
553
554 /// Return the option name for `setsockopt`/`getsockopt`.
555 static constexpr int name() noexcept
556 {
557 return IPV6_JOIN_GROUP;
558 }
559
560 /// Return a pointer to the underlying storage.
561 void* data() noexcept
562 {
563 return &value_;
564 }
565
566 /// Return a pointer to the underlying storage.
567 void const* data() const noexcept
568 {
569 return &value_;
570 }
571
572 /// Return the size of the underlying storage.
573 std::size_t size() const noexcept
574 {
575 return sizeof(value_);
576 }
577
578 /// No-op resize.
579 void resize(std::size_t) noexcept {}
580 };
581
582 /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
583
584 @par Example
585 @code
586 sock.set_option( native_socket_option::leave_group_v6(
587 ipv6_address( "ff02::1" ), 0 ) );
588 @endcode
589 */
590 class leave_group_v6
591 {
592 struct ipv6_mreq value_{};
593
594 public:
595 /// Construct with default values.
596 leave_group_v6() = default;
597
598 /** Construct with a group and optional interface index.
599
600 @param group The multicast group address to leave.
601 @param if_index The interface index (0 = kernel chooses).
602 */
603 leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
604 {
605 auto gb = group.to_bytes();
606 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
607 value_.ipv6mr_interface = if_index;
608 }
609
610 /// Return the protocol level for `setsockopt`/`getsockopt`.
611 static constexpr int level() noexcept
612 {
613 return IPPROTO_IPV6;
614 }
615
616 /// Return the option name for `setsockopt`/`getsockopt`.
617 static constexpr int name() noexcept
618 {
619 return IPV6_LEAVE_GROUP;
620 }
621
622 /// Return a pointer to the underlying storage.
623 void* data() noexcept
624 {
625 return &value_;
626 }
627
628 /// Return a pointer to the underlying storage.
629 void const* data() const noexcept
630 {
631 return &value_;
632 }
633
634 /// Return the size of the underlying storage.
635 std::size_t size() const noexcept
636 {
637 return sizeof(value_);
638 }
639
640 /// No-op resize.
641 void resize(std::size_t) noexcept {}
642 };
643
644 /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
645
646 Unlike the integer-based `multicast_interface_v6`, this option
647 takes an `ipv4_address` identifying the local interface.
648
649 @par Example
650 @code
651 sock.set_option( native_socket_option::multicast_interface_v4(
652 ipv4_address( "192.168.1.1" ) ) );
653 @endcode
654 */
655 class multicast_interface_v4
656 {
657 struct in_addr value_{};
658
659 public:
660 /// Construct with default values (INADDR_ANY).
661 multicast_interface_v4() = default;
662
663 /** Construct with an interface address.
664
665 @param iface The local interface address.
666 */
667 explicit multicast_interface_v4(ipv4_address iface) noexcept
668 {
669 auto b = iface.to_bytes();
670 std::memcpy(&value_, b.data(), 4);
671 }
672
673 /// Return the protocol level for `setsockopt`/`getsockopt`.
674 static constexpr int level() noexcept
675 {
676 return IPPROTO_IP;
677 }
678
679 /// Return the option name for `setsockopt`/`getsockopt`.
680 static constexpr int name() noexcept
681 {
682 return IP_MULTICAST_IF;
683 }
684
685 /// Return a pointer to the underlying storage.
686 void* data() noexcept
687 {
688 return &value_;
689 }
690
691 /// Return a pointer to the underlying storage.
692 void const* data() const noexcept
693 {
694 return &value_;
695 }
696
697 /// Return the size of the underlying storage.
698 std::size_t size() const noexcept
699 {
700 return sizeof(value_);
701 }
702
703 /// No-op resize.
704 void resize(std::size_t) noexcept {}
705 };
706
707 } // namespace boost::corosio::native_socket_option
708
709 #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
710