TLA Line data 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 HIT 1445 : explicit boolean_option(bool v) noexcept : value_(v ? 1 : 0) {}
58 :
59 : /// Assign a new value.
60 4 : boolean_option& operator=(bool v) noexcept
61 : {
62 4 : value_ = v ? 1 : 0;
63 4 : return *this;
64 : }
65 :
66 : /// Return the option value.
67 60 : bool value() const noexcept
68 : {
69 60 : return value_ != 0;
70 : }
71 :
72 : /// Return the option value.
73 4 : explicit operator bool() const noexcept
74 : {
75 4 : return value_ != 0;
76 : }
77 :
78 : /// Return the negated option value.
79 4 : bool operator!() const noexcept
80 : {
81 4 : return value_ == 0;
82 : }
83 :
84 : /// Return a pointer to the underlying storage.
85 85 : void* data(family) noexcept
86 : {
87 85 : return &value_;
88 : }
89 :
90 : /// Return a pointer to the underlying storage.
91 1437 : void const* data(family) const noexcept
92 : {
93 1437 : return &value_;
94 : }
95 :
96 : /// Return the size of the underlying storage.
97 1522 : std::size_t size(family) const noexcept
98 : {
99 1522 : 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 64 : void resize(family, std::size_t s) noexcept
109 : {
110 64 : if (s == sizeof(char))
111 2 : value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
112 64 : }
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 83 : explicit integer_option(int v) noexcept : value_(v) {}
133 :
134 : /// Assign a new value.
135 2 : integer_option& operator=(int v) noexcept
136 : {
137 2 : value_ = v;
138 2 : return *this;
139 : }
140 :
141 : /// Return the option value.
142 58 : int value() const noexcept
143 : {
144 58 : return value_;
145 : }
146 :
147 : /// Return a pointer to the underlying storage.
148 54 : void* data(family) noexcept
149 : {
150 54 : return &value_;
151 : }
152 :
153 : /// Return a pointer to the underlying storage.
154 77 : void const* data(family) const noexcept
155 : {
156 77 : return &value_;
157 : }
158 :
159 : /// Return the size of the underlying storage.
160 131 : std::size_t size(family) const noexcept
161 : {
162 131 : 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 56 : void resize(family, std::size_t s) noexcept
170 : {
171 56 : if (s == sizeof(char))
172 2 : value_ =
173 2 : static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
174 56 : }
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 12 : void* data(family) noexcept
410 : {
411 12 : return storage_;
412 : }
413 :
414 : /// Return a pointer to the underlying storage.
415 6375 : void const* data(family) const noexcept
416 : {
417 6375 : 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 12 : 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 20 : explicit multicast_loop(bool v) noexcept : byte_(v ? 1 : 0), int_(v ? 1 : 0)
454 : {
455 20 : }
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 16 : bool value() const noexcept
467 : {
468 16 : 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 20 : void* data(family f) noexcept
479 : {
480 20 : return f == family::v6 ? static_cast<void*>(&int_)
481 20 : : static_cast<void*>(&byte_);
482 : }
483 :
484 : /// Return a pointer to the rendering for `f`.
485 18 : void const* data(family f) const noexcept
486 : {
487 18 : return f == family::v6 ? static_cast<void const*>(&int_)
488 18 : : static_cast<void const*>(&byte_);
489 : }
490 :
491 : /// Return the size of the rendering for `f`.
492 38 : std::size_t size(family f) const noexcept
493 : {
494 38 : 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 16 : void resize(family f, std::size_t) noexcept
505 : {
506 16 : if (f == family::v6)
507 8 : byte_ = int_ ? 1 : 0;
508 : else
509 8 : int_ = byte_ ? 1 : 0;
510 16 : }
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 14 : explicit multicast_hops(int v)
539 14 : {
540 14 : if (v < 0 || v > 255)
541 4 : detail::throw_logic_error("multicast hops value out of range");
542 10 : byte_ = static_cast<unsigned char>(v);
543 10 : int_ = v;
544 10 : }
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 8 : int value() const noexcept
561 : {
562 8 : 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 12 : void* data(family f) noexcept
573 : {
574 12 : return f == family::v6 ? static_cast<void*>(&int_)
575 12 : : static_cast<void*>(&byte_);
576 : }
577 :
578 : /// Return a pointer to the rendering for `f`.
579 8 : void const* data(family f) const noexcept
580 : {
581 8 : return f == family::v6 ? static_cast<void const*>(&int_)
582 8 : : static_cast<void const*>(&byte_);
583 : }
584 :
585 : /// Return the size of the rendering for `f`.
586 20 : std::size_t size(family f) const noexcept
587 : {
588 20 : 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 8 : void resize(family f, std::size_t) noexcept
596 : {
597 8 : if (f == family::v6)
598 4 : byte_ = static_cast<unsigned char>(int_);
599 : else
600 4 : int_ = byte_;
601 8 : }
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 14 : void const* data(family) const noexcept
658 : {
659 14 : 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 12 : void const* data(family) const noexcept
717 : {
718 12 : 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 4 : explicit multicast_interface(unsigned int if_index) noexcept
759 4 : : if_index_(if_index)
760 : {
761 4 : }
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 6 : unsigned int if_index() const noexcept
768 : {
769 6 : 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 4 : void* data(family f) noexcept
780 : {
781 4 : return f == family::v6 ? static_cast<void*>(&if_index_)
782 4 : : static_cast<void*>(v4_storage_);
783 : }
784 :
785 : /// Return a pointer to the rendering for `f`.
786 4 : void const* data(family f) const noexcept
787 : {
788 4 : return f == family::v6 ? static_cast<void const*>(&if_index_)
789 4 : : 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 2 : void resize(family, std::size_t) noexcept {}
797 : };
798 :
799 : } // namespace boost::corosio::socket_option
800 :
801 : #endif // BOOST_COROSIO_SOCKET_OPTION_HPP
|