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