include/boost/corosio/socket_option.hpp

100.0% Lines (97 / 97) 100.0% Functions (38 / 38)
socket_option.hpp
f(x) Functions (38)
Function Calls Lines Blocks
boost::corosio::socket_option::boolean_option::boolean_option(bool) :59 666x 100.0% 100.0% boost::corosio::socket_option::boolean_option::operator=(bool) :62 4x 100.0% 100.0% boost::corosio::socket_option::boolean_option::value() const :69 60x 100.0% 100.0% boost::corosio::socket_option::boolean_option::operator bool() const :75 4x 100.0% 100.0% boost::corosio::socket_option::boolean_option::operator!() const :81 4x 100.0% 100.0% boost::corosio::socket_option::boolean_option::data(boost::corosio::family) :87 85x 100.0% 100.0% boost::corosio::socket_option::boolean_option::data(boost::corosio::family) const :93 658x 100.0% 100.0% boost::corosio::socket_option::boolean_option::size(boost::corosio::family) const :99 743x 100.0% 100.0% boost::corosio::socket_option::boolean_option::resize(boost::corosio::family, unsigned long) :110 64x 100.0% 83.0% boost::corosio::socket_option::integer_option::integer_option(int) :134 83x 100.0% 100.0% boost::corosio::socket_option::integer_option::operator=(int) :137 2x 100.0% 100.0% boost::corosio::socket_option::integer_option::value() const :144 58x 100.0% 100.0% boost::corosio::socket_option::integer_option::data(boost::corosio::family) :150 54x 100.0% 100.0% boost::corosio::socket_option::integer_option::data(boost::corosio::family) const :156 77x 100.0% 100.0% boost::corosio::socket_option::integer_option::size(boost::corosio::family) const :162 131x 100.0% 100.0% boost::corosio::socket_option::integer_option::resize(boost::corosio::family, unsigned long) :171 56x 100.0% 100.0% boost::corosio::socket_option::linger::data(boost::corosio::family) :411 12x 100.0% 100.0% boost::corosio::socket_option::linger::data(boost::corosio::family) const :417 203x 100.0% 100.0% boost::corosio::socket_option::linger::resize(boost::corosio::family, unsigned long) :429 12x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::multicast_loop(bool) :455 20x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::value() const :468 16x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::data(boost::corosio::family) :480 20x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::data(boost::corosio::family) const :487 18x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::size(boost::corosio::family) const :494 38x 100.0% 100.0% boost::corosio::socket_option::multicast_loop::resize(boost::corosio::family, unsigned long) :506 16x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::multicast_hops(int) :540 14x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::value() const :562 8x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::data(boost::corosio::family) :574 12x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::data(boost::corosio::family) const :581 8x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::size(boost::corosio::family) const :588 20x 100.0% 100.0% boost::corosio::socket_option::multicast_hops::resize(boost::corosio::family, unsigned long) :597 8x 100.0% 100.0% boost::corosio::socket_option::join_group::data(boost::corosio::family) const :659 14x 100.0% 100.0% boost::corosio::socket_option::leave_group::data(boost::corosio::family) const :718 12x 100.0% 100.0% boost::corosio::socket_option::multicast_interface::multicast_interface(unsigned int) :760 4x 100.0% 100.0% boost::corosio::socket_option::multicast_interface::if_index() const :769 6x 100.0% 100.0% boost::corosio::socket_option::multicast_interface::data(boost::corosio::family) :781 4x 100.0% 80.0% boost::corosio::socket_option::multicast_interface::data(boost::corosio::family) const :788 4x 100.0% 100.0% boost::corosio::socket_option::multicast_interface::resize(boost::corosio::family, unsigned long) :798 2x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_SOCKET_OPTION_HPP
12 #define BOOST_COROSIO_SOCKET_OPTION_HPP
13
14 #include <boost/corosio/detail/config.hpp>
15 #include <boost/corosio/detail/except.hpp>
16 #include <boost/corosio/family.hpp>
17 #include <boost/corosio/ip_address.hpp>
18 #include <boost/corosio/ipv4_address.hpp>
19 #include <boost/corosio/ipv6_address.hpp>
20
21 #include <cstddef>
22
23 /** @file socket_option.hpp
24
25 Type-erased socket option types that avoid platform-specific
26 headers. The protocol level and option name for each type are
27 resolved at link time via the compiled library.
28
29 For an inline (zero-overhead) alternative that includes platform
30 headers, use `<boost/corosio/native/native_socket_option.hpp>`
31 (`boost::corosio::native_socket_option`).
32
33 Both variants satisfy the same option-type interface and work
34 interchangeably with `tcp_socket::set_option` /
35 `tcp_socket::get_option` and the corresponding acceptor methods.
36
37 @see native_socket_option
38 */
39
40 namespace boost::corosio::socket_option {
41
42 /** Base class for concrete boolean socket options.
43
44 Stores a boolean as an `int` suitable for `setsockopt`/`getsockopt`.
45 Derived types provide `level()` and `name()` for the specific option.
46 */
47 class BOOST_COROSIO_DECL boolean_option
48 {
49 int value_ = 0;
50
51 public:
52 /// Construct with default value (disabled).
53 boolean_option() = default;
54
55 /** Construct with an explicit value.
56
57 @param v `true` to enable the option, `false` to disable.
58 */
59 666x explicit boolean_option(bool v) noexcept : value_(v ? 1 : 0) {}
60
61 /// Assign a new value.
62 4x boolean_option& operator=(bool v) noexcept
63 {
64 4x value_ = v ? 1 : 0;
65 4x return *this;
66 }
67
68 /// Return the option value.
69 60x bool value() const noexcept
70 {
71 60x return value_ != 0;
72 }
73
74 /// Return the option value.
75 4x explicit operator bool() const noexcept
76 {
77 4x return value_ != 0;
78 }
79
80 /// Return the negated option value.
81 4x bool operator!() const noexcept
82 {
83 4x return value_ == 0;
84 }
85
86 /// Return a pointer to the underlying storage.
87 85x void* data(family) noexcept
88 {
89 85x return &value_;
90 }
91
92 /// Return a pointer to the underlying storage.
93 658x void const* data(family) const noexcept
94 {
95 658x return &value_;
96 }
97
98 /// Return the size of the underlying storage.
99 743x std::size_t size(family) const noexcept
100 {
101 743x return sizeof(value_);
102 }
103
104 /** Normalize after `getsockopt` returns fewer bytes than expected.
105
106 Windows Vista+ may write only 1 byte for boolean options.
107
108 @param s The number of bytes actually written by `getsockopt`.
109 */
110 64x void resize(family, std::size_t s) noexcept
111 {
112 64x if (s == sizeof(char))
113 2x value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
114 64x }
115 };
116
117 /** Base class for concrete integer socket options.
118
119 Stores an integer suitable for `setsockopt`/`getsockopt`.
120 Derived types provide `level()` and `name()` for the specific option.
121 */
122 class BOOST_COROSIO_DECL integer_option
123 {
124 int value_ = 0;
125
126 public:
127 /// Construct with default value (zero).
128 integer_option() = default;
129
130 /** Construct with an explicit value.
131
132 @param v The option value.
133 */
134 83x explicit integer_option(int v) noexcept : value_(v) {}
135
136 /// Assign a new value.
137 2x integer_option& operator=(int v) noexcept
138 {
139 2x value_ = v;
140 2x return *this;
141 }
142
143 /// Return the option value.
144 58x int value() const noexcept
145 {
146 58x return value_;
147 }
148
149 /// Return a pointer to the underlying storage.
150 54x void* data(family) noexcept
151 {
152 54x return &value_;
153 }
154
155 /// Return a pointer to the underlying storage.
156 77x void const* data(family) const noexcept
157 {
158 77x return &value_;
159 }
160
161 /// Return the size of the underlying storage.
162 131x std::size_t size(family) const noexcept
163 {
164 131x return sizeof(value_);
165 }
166
167 /** Normalize after `getsockopt` returns fewer bytes than expected.
168
169 @param s The number of bytes actually written by `getsockopt`.
170 */
171 56x void resize(family, std::size_t s) noexcept
172 {
173 56x if (s == sizeof(char))
174 2x value_ =
175 2x static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
176 56x }
177 };
178
179 /** Disable Nagle's algorithm (TCP_NODELAY).
180
181 @par Example
182 @par !example no_delay
183 */
184 class BOOST_COROSIO_DECL no_delay : public boolean_option
185 {
186 public:
187 /// Inherit the base constructors.
188 using boolean_option::boolean_option;
189
190 /// Inherit assignment from the base.
191 using boolean_option::operator=;
192
193 /// Return the protocol level.
194 int level(family) const noexcept;
195
196 /// Return the option name.
197 int name(family) const noexcept;
198 };
199
200 /** Enable periodic keepalive probes (SO_KEEPALIVE).
201
202 @par Example
203 @par !example keep_alive
204 */
205 class BOOST_COROSIO_DECL keep_alive : public boolean_option
206 {
207 public:
208 /// Inherit the base constructors.
209 using boolean_option::boolean_option;
210
211 /// Inherit assignment from the base.
212 using boolean_option::operator=;
213
214 /// Return the protocol level.
215 int level(family) const noexcept;
216
217 /// Return the option name.
218 int name(family) const noexcept;
219 };
220
221 /** Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
222
223 When enabled, the socket only accepts IPv6 connections.
224 When disabled, the socket accepts both IPv4 and IPv6
225 connections (dual-stack mode).
226
227 @par Example
228 @par !example v6_only
229 */
230 class BOOST_COROSIO_DECL v6_only : public boolean_option
231 {
232 public:
233 /// Inherit the base constructors.
234 using boolean_option::boolean_option;
235
236 /// Inherit assignment from the base.
237 using boolean_option::operator=;
238
239 /// Return the protocol level.
240 int level(family) const noexcept;
241
242 /// Return the option name.
243 int name(family) const noexcept;
244 };
245
246 /** Allow local address reuse (SO_REUSEADDR).
247
248 @par Example
249 @par !example reuse_address
250 */
251 class BOOST_COROSIO_DECL reuse_address : public boolean_option
252 {
253 public:
254 /// Inherit the base constructors.
255 using boolean_option::boolean_option;
256
257 /// Inherit assignment from the base.
258 using boolean_option::operator=;
259
260 /// Return the protocol level.
261 int level(family) const noexcept;
262
263 /// Return the option name.
264 int name(family) const noexcept;
265 };
266
267 /** Allow sending to broadcast addresses (SO_BROADCAST).
268
269 Required for UDP sockets that send to broadcast addresses
270 such as 255.255.255.255. Without this option, `send_to`
271 returns an error.
272
273 @par Example
274 @par !example broadcast
275 */
276 class BOOST_COROSIO_DECL broadcast : public boolean_option
277 {
278 public:
279 /// Inherit the base constructors.
280 using boolean_option::boolean_option;
281
282 /// Inherit assignment from the base.
283 using boolean_option::operator=;
284
285 /// Return the protocol level.
286 int level(family) const noexcept;
287
288 /// Return the option name.
289 int name(family) const noexcept;
290 };
291
292 /** Allow multiple sockets to bind to the same port (SO_REUSEPORT).
293
294 Not available on all platforms. On unsupported platforms,
295 `set_option` throws `std::system_error`.
296
297 @par Example
298 @par !example reuse_port
299 */
300 class BOOST_COROSIO_DECL reuse_port : public boolean_option
301 {
302 public:
303 /// Inherit the base constructors.
304 using boolean_option::boolean_option;
305
306 /// Inherit assignment from the base.
307 using boolean_option::operator=;
308
309 /// Return the protocol level.
310 int level(family) const noexcept;
311
312 /// Return the option name.
313 int name(family) const noexcept;
314 };
315
316 /** Set the receive buffer size (SO_RCVBUF).
317
318 @par Example
319 @par !example receive_buffer_size
320 */
321 class BOOST_COROSIO_DECL receive_buffer_size : public integer_option
322 {
323 public:
324 /// Inherit the base constructors.
325 using integer_option::integer_option;
326
327 /// Inherit assignment from the base.
328 using integer_option::operator=;
329
330 /// Return the protocol level.
331 int level(family) const noexcept;
332
333 /// Return the option name.
334 int name(family) const noexcept;
335 };
336
337 /** Set the send buffer size (SO_SNDBUF).
338
339 @par Example
340 @par !example send_buffer_size
341 */
342 class BOOST_COROSIO_DECL send_buffer_size : public integer_option
343 {
344 public:
345 /// Inherit the base constructors.
346 using integer_option::integer_option;
347
348 /// Inherit assignment from the base.
349 using integer_option::operator=;
350
351 /// Return the protocol level.
352 int level(family) const noexcept;
353
354 /// Return the option name.
355 int name(family) const noexcept;
356 };
357
358 /** The SO_LINGER socket option.
359
360 Controls behavior when closing a socket with unsent data.
361 When enabled, `close()` blocks until pending data is sent
362 or the timeout expires.
363
364 @par Example
365 @par !example linger
366 */
367 class BOOST_COROSIO_DECL linger
368 {
369 // Opaque storage for the platform's struct linger.
370 // POSIX: { int, int } = 8 bytes.
371 // Windows: { u_short, u_short } = 4 bytes.
372 static constexpr std::size_t max_storage_ = 8;
373 alignas(4) unsigned char storage_[max_storage_]{};
374
375 public:
376 /// Construct with default values (disabled, zero timeout).
377 linger() noexcept = default;
378
379 /** Construct with explicit values.
380
381 @param enabled `true` to enable linger behavior on close.
382 @param timeout The linger timeout in seconds.
383 */
384 linger(bool enabled, int timeout) noexcept;
385
386 /// Return whether linger is enabled.
387 bool enabled() const noexcept;
388
389 /** Set whether linger is enabled.
390
391 @param v `true` to linger on close.
392 */
393 void enabled(bool v) noexcept;
394
395 /// Return the linger timeout in seconds.
396 int timeout() const noexcept;
397
398 /** Set the linger timeout in seconds.
399
400 @param v The timeout in seconds.
401 */
402 void timeout(int v) noexcept;
403
404 /// Return the protocol level.
405 int level(family) const noexcept;
406
407 /// Return the option name.
408 int name(family) const noexcept;
409
410 /// Return a pointer to the underlying storage.
411 12x void* data(family) noexcept
412 {
413 12x return storage_;
414 }
415
416 /// Return a pointer to the underlying storage.
417 203x void const* data(family) const noexcept
418 {
419 203x return storage_;
420 }
421
422 /// Return the size of the underlying storage.
423 std::size_t size(family) const noexcept;
424
425 /** Normalize after `getsockopt`.
426
427 No-op — `struct linger` is always returned at full size.
428 */
429 12x void resize(family, std::size_t) noexcept {}
430 };
431
432 /** Enable loopback of outgoing multicast (IP_MULTICAST_LOOP /
433 IPV6_MULTICAST_LOOP).
434
435 The socket's family selects the wire rendering. A single byte
436 at the IPv4 level (BSD-derived kernels reject the four-byte
437 form), an `int` at the IPv6 level.
438
439 @par Example
440 @par !example multicast_loop
441 */
442 class BOOST_COROSIO_DECL multicast_loop
443 {
444 unsigned char byte_ = 0; // IPv4 rendering
445 int int_ = 0; // IPv6 rendering
446
447 public:
448 /// Construct with default value (disabled).
449 multicast_loop() = default;
450
451 /** Construct with an explicit value.
452
453 @param v `true` to enable loopback, `false` to disable.
454 */
455 20x explicit multicast_loop(bool v) noexcept : byte_(v ? 1 : 0), int_(v ? 1 : 0)
456 {
457 20x }
458
459 /// Assign a new value.
460 multicast_loop& operator=(bool v) noexcept
461 {
462 byte_ = v ? 1 : 0;
463 int_ = v ? 1 : 0;
464 return *this;
465 }
466
467 /// Return the option value.
468 16x bool value() const noexcept
469 {
470 16x return int_ != 0;
471 }
472
473 /// Return the protocol level.
474 int level(family) const noexcept;
475
476 /// Return the option name.
477 int name(family) const noexcept;
478
479 /// Return a pointer to the rendering for `f`.
480 20x void* data(family f) noexcept
481 {
482 20x return f == family::v6 ? static_cast<void*>(&int_)
483 20x : static_cast<void*>(&byte_);
484 }
485
486 /// Return a pointer to the rendering for `f`.
487 18x void const* data(family f) const noexcept
488 {
489 18x return f == family::v6 ? static_cast<void const*>(&int_)
490 18x : static_cast<void const*>(&byte_);
491 }
492
493 /// Return the size of the rendering for `f`.
494 38x std::size_t size(family f) const noexcept
495 {
496 38x return f == family::v6 ? sizeof(int_) : sizeof(byte_);
497 }
498
499 /** Synchronize both renderings after `getsockopt`.
500
501 Only the rendering the socket's family selected was written;
502 fold it into the other so `value()` answers from either.
503
504 @param f The family `getsockopt` was performed for.
505 */
506 16x void resize(family f, std::size_t) noexcept
507 {
508 16x if (f == family::v6)
509 8x byte_ = int_ ? 1 : 0;
510 else
511 8x int_ = byte_ ? 1 : 0;
512 16x }
513 };
514
515 /** Set the multicast TTL / hop limit (IP_MULTICAST_TTL /
516 IPV6_MULTICAST_HOPS).
517
518 The socket's family selects the wire rendering: a single byte
519 at the IPv4 level, an `int` at the IPv6 level.
520
521 @par Example
522 @par !example multicast_hops
523 */
524 class BOOST_COROSIO_DECL multicast_hops
525 {
526 unsigned char byte_ = 0; // IPv4 rendering
527 int int_ = 0; // IPv6 rendering
528
529 public:
530 /// Construct with default value (zero).
531 multicast_hops() = default;
532
533 /** Construct with an explicit value.
534
535 @param v The hop count, 0 to 255 — the range the IPv4 wire
536 rendering can carry.
537
538 @throws std::logic_error if `v` is outside [0, 255].
539 */
540 14x explicit multicast_hops(int v)
541 14x {
542 14x if (v < 0 || v > 255)
543 4x detail::throw_logic_error("multicast hops value out of range");
544 10x byte_ = static_cast<unsigned char>(v);
545 10x int_ = v;
546 10x }
547
548 /** Assign a new value.
549
550 @throws std::logic_error if `v` is outside [0, 255].
551 */
552 multicast_hops& operator=(int v)
553 {
554 if (v < 0 || v > 255)
555 detail::throw_logic_error("multicast hops value out of range");
556 byte_ = static_cast<unsigned char>(v);
557 int_ = v;
558 return *this;
559 }
560
561 /// Return the option value.
562 8x int value() const noexcept
563 {
564 8x return int_;
565 }
566
567 /// Return the protocol level.
568 int level(family) const noexcept;
569
570 /// Return the option name.
571 int name(family) const noexcept;
572
573 /// Return a pointer to the rendering for `f`.
574 12x void* data(family f) noexcept
575 {
576 12x return f == family::v6 ? static_cast<void*>(&int_)
577 12x : static_cast<void*>(&byte_);
578 }
579
580 /// Return a pointer to the rendering for `f`.
581 8x void const* data(family f) const noexcept
582 {
583 8x return f == family::v6 ? static_cast<void const*>(&int_)
584 8x : static_cast<void const*>(&byte_);
585 }
586
587 /// Return the size of the rendering for `f`.
588 20x std::size_t size(family f) const noexcept
589 {
590 20x return f == family::v6 ? sizeof(int_) : sizeof(byte_);
591 }
592
593 /** Synchronize both renderings after `getsockopt`.
594
595 @param f The family `getsockopt` was performed for.
596 */
597 8x void resize(family f, std::size_t) noexcept
598 {
599 8x if (f == family::v6)
600 4x byte_ = static_cast<unsigned char>(int_);
601 else
602 4x int_ = byte_;
603 8x }
604 };
605
606 /** Join a multicast group (IP_ADD_MEMBERSHIP / IPV6_JOIN_GROUP).
607
608 The group's family — not the socket's — selects the wire struct and
609 protocol level. A v4 group renders as an `ip_mreq` at the IPv4 level
610 even when applied to a dual-stack v6 socket. That is the level such a
611 join actually targets.
612
613 @par Example
614 @par !example join_group
615 */
616 class BOOST_COROSIO_DECL join_group
617 {
618 // Opaque storage sized for the larger of ip_mreq / ipv6_mreq
619 static constexpr std::size_t max_storage_ = 20;
620 alignas(4) unsigned char storage_[max_storage_]{};
621 family group_family_ = family::v4;
622
623 public:
624 /// Construct with default values.
625 join_group() noexcept = default;
626
627 /** Construct from a group address.
628
629 The group's family selects the wire representation; the
630 interface defaults to any (v4) or the group's zone (v6).
631
632 @param group The multicast group address to join.
633 */
634 explicit join_group(ip_address const& group) noexcept;
635
636 /** Construct from an IPv4 group and interface address.
637
638 @param group The multicast group address to join.
639 @param iface The local interface to use (default: any).
640 */
641 join_group(
642 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept;
643
644 /** Construct from an IPv6 group and interface index.
645
646 @param group The multicast group address to join.
647 @param if_index The interface index; 0 uses the group's
648 zone, and a zone of 0 lets the kernel choose.
649 */
650 join_group(ipv6_address const& group, unsigned int if_index = 0) noexcept;
651
652 /// Return the protocol level for the group's family.
653 int level(family) const noexcept;
654
655 /// Return the option name for the group's family.
656 int name(family) const noexcept;
657
658 /// Return a pointer to the underlying storage.
659 14x void const* data(family) const noexcept
660 {
661 14x return storage_;
662 }
663
664 /// Return the size of the wire struct for the group's family.
665 std::size_t size(family) const noexcept;
666
667 /// No-op resize.
668 void resize(family, std::size_t) noexcept {}
669 };
670
671 /** Leave a multicast group (IP_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP).
672
673 The group's family — not the socket's — selects the wire
674 struct and protocol level, mirroring @ref join_group.
675
676 @par Example
677 @par !example leave_group
678 */
679 class BOOST_COROSIO_DECL leave_group
680 {
681 static constexpr std::size_t max_storage_ = 20;
682 alignas(4) unsigned char storage_[max_storage_]{};
683 family group_family_ = family::v4;
684
685 public:
686 /// Construct with default values.
687 leave_group() noexcept = default;
688
689 /** Construct from a group address.
690
691 @param group The multicast group address to leave.
692 */
693 explicit leave_group(ip_address const& group) noexcept;
694
695 /** Construct from an IPv4 group and interface address.
696
697 @param group The multicast group address to leave.
698 @param iface The local interface (default: any).
699 */
700 leave_group(
701 ipv4_address group, ipv4_address iface = ipv4_address()) noexcept;
702
703 /** Construct from an IPv6 group and interface index.
704
705 @param group The multicast group address to leave.
706 @param if_index The interface index; 0 uses the group's
707 zone, and a zone of 0 lets the kernel choose.
708 */
709 leave_group(ipv6_address const& group, unsigned int if_index = 0) noexcept;
710
711 /// Return the protocol level for the group's family.
712 int level(family) const noexcept;
713
714 /// Return the option name for the group's family.
715 int name(family) const noexcept;
716
717 /// Return a pointer to the underlying storage.
718 12x void const* data(family) const noexcept
719 {
720 12x return storage_;
721 }
722
723 /// Return the size of the wire struct for the group's family.
724 std::size_t size(family) const noexcept;
725
726 /// No-op resize.
727 void resize(family, std::size_t) noexcept {}
728 };
729
730 /** Set the outgoing multicast interface (IP_MULTICAST_IF /
731 IPV6_MULTICAST_IF).
732
733 The two families name interfaces differently on the wire: IPv4 by
734 interface address, IPv6 by interface index. The option stores both
735 renderings and the socket's family selects one; the other stays at its
736 default (any address, kernel-chosen index).
737
738 @par Example
739 @par !example multicast_interface
740 */
741 class BOOST_COROSIO_DECL multicast_interface
742 {
743 alignas(4) unsigned char v4_storage_[4]{};
744 unsigned int if_index_ = 0;
745
746 public:
747 /// Construct with default values (any address, kernel-chosen index).
748 multicast_interface() noexcept = default;
749
750 /** Construct with an IPv4 interface address.
751
752 @param iface The local interface address.
753 */
754 explicit multicast_interface(ipv4_address iface) noexcept;
755
756 /** Construct with an IPv6 interface index.
757
758 @param if_index The interface index (0 = kernel chooses).
759 */
760 4x explicit multicast_interface(unsigned int if_index) noexcept
761 4x : if_index_(if_index)
762 {
763 4x }
764
765 /// Return the IPv4 rendering as an address.
766 ipv4_address address() const noexcept;
767
768 /// Return the IPv6 rendering as an interface index.
769 6x unsigned int if_index() const noexcept
770 {
771 6x return if_index_;
772 }
773
774 /// Return the protocol level.
775 int level(family) const noexcept;
776
777 /// Return the option name.
778 int name(family) const noexcept;
779
780 /// Return a pointer to the rendering for `f`.
781 4x void* data(family f) noexcept
782 {
783 4x return f == family::v6 ? static_cast<void*>(&if_index_)
784 4x : static_cast<void*>(v4_storage_);
785 }
786
787 /// Return a pointer to the rendering for `f`.
788 4x void const* data(family f) const noexcept
789 {
790 4x return f == family::v6 ? static_cast<void const*>(&if_index_)
791 4x : static_cast<void const*>(v4_storage_);
792 }
793
794 /// Return the size of the rendering for `f`.
795 std::size_t size(family) const noexcept;
796
797 /// No-op resize.
798 2x void resize(family, std::size_t) noexcept {}
799 };
800
801 } // namespace boost::corosio::socket_option
802
803 #endif // BOOST_COROSIO_SOCKET_OPTION_HPP
804