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