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