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 : /** @file native_socket_option.hpp
12 :
13 : Inline socket option types using platform-specific constants.
14 : All methods are `constexpr` or trivially inlined, giving zero
15 : overhead compared to hand-written `setsockopt` calls.
16 :
17 : This header includes platform socket headers
18 : (`<sys/socket.h>`, `<netinet/tcp.h>`, etc.).
19 : For a version that avoids platform includes, use
20 : `<boost/corosio/socket_option.hpp>`
21 : (`boost::corosio::socket_option`).
22 :
23 : Both variants satisfy the same option-type interface and work
24 : interchangeably with `tcp_socket::set_option` /
25 : `tcp_socket::get_option` and the corresponding acceptor methods.
26 :
27 : @see boost::corosio::socket_option
28 : */
29 :
30 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
31 : #define BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
32 :
33 : #ifdef _WIN32
34 : #include <winsock2.h>
35 : #include <ws2tcpip.h>
36 : #else
37 : #include <netinet/in.h>
38 : #include <netinet/tcp.h>
39 : #include <sys/socket.h>
40 : #endif
41 :
42 : // Some older systems define only the legacy names
43 : #ifndef IPV6_JOIN_GROUP
44 : #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
45 : #endif
46 : #ifndef IPV6_LEAVE_GROUP
47 : #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
48 : #endif
49 :
50 : #include <boost/corosio/ipv4_address.hpp>
51 : #include <boost/corosio/ipv6_address.hpp>
52 :
53 : #include <cstddef>
54 : #include <cstring>
55 :
56 : namespace boost::corosio::native_socket_option {
57 :
58 : /** A socket option with a boolean value.
59 :
60 : Models socket options whose underlying representation is an `int`
61 : where 0 means disabled and non-zero means enabled. The option's
62 : protocol level and name are encoded as template parameters.
63 :
64 : This is the native (inline) variant that includes platform
65 : headers. For a type-erased version that avoids platform
66 : includes, use `boost::corosio::socket_option` instead.
67 :
68 : @par Example
69 : @par !example boolean
70 :
71 : @tparam Level The protocol level (e.g. `SOL_SOCKET`, `IPPROTO_TCP`).
72 : @tparam Name The option name (e.g. `TCP_NODELAY`, `SO_KEEPALIVE`).
73 : */
74 : template<int Level, int Name>
75 : class boolean
76 : {
77 : int value_ = 0;
78 :
79 : public:
80 : /// Construct with default value (disabled).
81 : boolean() = default;
82 :
83 : /** Construct with an explicit value.
84 :
85 : @param v `true` to enable the option, `false` to disable.
86 : */
87 HIT 25 : explicit boolean(bool v) noexcept : value_(v ? 1 : 0) {}
88 :
89 : /// Assign a new value.
90 : boolean& operator=(bool v) noexcept
91 : {
92 : value_ = v ? 1 : 0;
93 : return *this;
94 : }
95 :
96 : /// Return the option value.
97 11 : bool value() const noexcept
98 : {
99 11 : return value_ != 0;
100 : }
101 :
102 : /// Return the option value.
103 : explicit operator bool() const noexcept
104 : {
105 : return value_ != 0;
106 : }
107 :
108 : /// Return the negated option value.
109 : bool operator!() const noexcept
110 : {
111 : return value_ == 0;
112 : }
113 :
114 : /// Return the protocol level for `setsockopt`/`getsockopt`.
115 775 : static constexpr int level() noexcept
116 : {
117 775 : return Level;
118 : }
119 :
120 : /// Return the option name for `setsockopt`/`getsockopt`.
121 775 : static constexpr int name() noexcept
122 : {
123 775 : return Name;
124 : }
125 :
126 : /// Return a pointer to the underlying storage.
127 10 : void* data() noexcept
128 : {
129 10 : return &value_;
130 : }
131 :
132 : /// Return a pointer to the underlying storage.
133 24 : void const* data() const noexcept
134 : {
135 24 : return &value_;
136 : }
137 :
138 : /// Return the size of the underlying storage.
139 32 : std::size_t size() const noexcept
140 : {
141 32 : return sizeof(value_);
142 : }
143 :
144 : /** Normalize after `getsockopt` returns fewer bytes than expected.
145 :
146 : Windows Vista+ may write only 1 byte for boolean options.
147 :
148 : @param s The number of bytes actually written by `getsockopt`.
149 : */
150 9 : void resize(std::size_t s) noexcept
151 : {
152 9 : if (s == sizeof(char))
153 1 : value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
154 9 : }
155 : };
156 :
157 : /** A socket option with an integer value.
158 :
159 : Models socket options whose underlying representation is a
160 : plain `int`. The option's protocol level and name are encoded
161 : as template parameters.
162 :
163 : This is the native (inline) variant that includes platform
164 : headers. For a type-erased version that avoids platform
165 : includes, use `boost::corosio::socket_option` instead.
166 :
167 : @par Example
168 : @par !example integer
169 :
170 : @tparam Level The protocol level (e.g. `SOL_SOCKET`).
171 : @tparam Name The option name (e.g. `SO_RCVBUF`).
172 : */
173 : template<int Level, int Name>
174 : class integer
175 : {
176 : int value_ = 0;
177 :
178 : public:
179 : /// Construct with default value (zero).
180 : integer() = default;
181 :
182 : /** Construct with an explicit value.
183 :
184 : @param v The option value.
185 : */
186 9 : explicit integer(int v) noexcept : value_(v) {}
187 :
188 : /// Assign a new value.
189 : integer& operator=(int v) noexcept
190 : {
191 : value_ = v;
192 : return *this;
193 : }
194 :
195 : /// Return the option value.
196 7 : int value() const noexcept
197 : {
198 7 : return value_;
199 : }
200 :
201 : /// Return the protocol level for `setsockopt`/`getsockopt`.
202 153 : static constexpr int level() noexcept
203 : {
204 153 : return Level;
205 : }
206 :
207 : /// Return the option name for `setsockopt`/`getsockopt`.
208 153 : static constexpr int name() noexcept
209 : {
210 153 : return Name;
211 : }
212 :
213 : /// Return a pointer to the underlying storage.
214 6 : void* data() noexcept
215 : {
216 6 : return &value_;
217 : }
218 :
219 : /// Return a pointer to the underlying storage.
220 8 : void const* data() const noexcept
221 : {
222 8 : return &value_;
223 : }
224 :
225 : /// Return the size of the underlying storage.
226 14 : std::size_t size() const noexcept
227 : {
228 14 : return sizeof(value_);
229 : }
230 :
231 : /** Normalize after `getsockopt` returns fewer bytes than expected.
232 :
233 : @param s The number of bytes actually written by `getsockopt`.
234 : */
235 7 : void resize(std::size_t s) noexcept
236 : {
237 7 : if (s == sizeof(char))
238 1 : value_ =
239 1 : static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
240 7 : }
241 : };
242 :
243 : /** A boolean socket option with single-byte storage.
244 :
245 : Some BSD-derived kernels (macOS, FreeBSD) require certain IPv4 multicast
246 : options (`IP_MULTICAST_LOOP`) to be set with a one-byte value and return
247 : `EINVAL` for the four-byte form that Linux accepts. This template
248 : provides `unsigned char` storage so the option works on every platform.
249 :
250 : @tparam Level The protocol level.
251 : @tparam Name The option name.
252 : */
253 : template<int Level, int Name>
254 : class byte_boolean
255 : {
256 : unsigned char value_ = 0;
257 :
258 : public:
259 : byte_boolean() = default;
260 :
261 2 : explicit byte_boolean(bool v) noexcept : value_(v ? 1 : 0) {}
262 :
263 : byte_boolean& operator=(bool v) noexcept
264 : {
265 : value_ = v ? 1 : 0;
266 : return *this;
267 : }
268 :
269 2 : bool value() const noexcept
270 : {
271 2 : return value_ != 0;
272 : }
273 : explicit operator bool() const noexcept
274 : {
275 : return value_ != 0;
276 : }
277 : bool operator!() const noexcept
278 : {
279 : return value_ == 0;
280 : }
281 :
282 22 : static constexpr int level() noexcept
283 : {
284 22 : return Level;
285 : }
286 22 : static constexpr int name() noexcept
287 : {
288 22 : return Name;
289 : }
290 :
291 2 : void* data() noexcept
292 : {
293 2 : return &value_;
294 : }
295 2 : void const* data() const noexcept
296 : {
297 2 : return &value_;
298 : }
299 4 : std::size_t size() const noexcept
300 : {
301 4 : return sizeof(value_);
302 : }
303 :
304 2 : void resize(std::size_t) noexcept {}
305 : };
306 :
307 : /** An integer socket option with single-byte storage.
308 :
309 : Same rationale as `byte_boolean`: BSD-derived kernels require
310 : `IP_MULTICAST_TTL` to be set with a one-byte value. Linux accepts
311 : one byte too, so single-byte storage is portable. Values are
312 : truncated to the 0–255 range.
313 :
314 : @tparam Level The protocol level.
315 : @tparam Name The option name.
316 : */
317 : template<int Level, int Name>
318 : class byte_integer
319 : {
320 : unsigned char value_ = 0;
321 :
322 : public:
323 : byte_integer() = default;
324 :
325 2 : explicit byte_integer(int v) noexcept
326 2 : : value_(static_cast<unsigned char>(v))
327 : {
328 2 : }
329 :
330 : byte_integer& operator=(int v) noexcept
331 : {
332 : value_ = static_cast<unsigned char>(v);
333 : return *this;
334 : }
335 :
336 2 : int value() const noexcept
337 : {
338 2 : return value_;
339 : }
340 :
341 12 : static constexpr int level() noexcept
342 : {
343 12 : return Level;
344 : }
345 12 : static constexpr int name() noexcept
346 : {
347 12 : return Name;
348 : }
349 :
350 2 : void* data() noexcept
351 : {
352 2 : return &value_;
353 : }
354 2 : void const* data() const noexcept
355 : {
356 2 : return &value_;
357 : }
358 4 : std::size_t size() const noexcept
359 : {
360 4 : return sizeof(value_);
361 : }
362 :
363 2 : void resize(std::size_t) noexcept {}
364 : };
365 :
366 : /** The SO_LINGER socket option (native variant).
367 :
368 : Controls behavior when closing a socket with unsent data.
369 : When enabled, `close()` blocks until pending data is sent
370 : or the timeout expires.
371 :
372 : This variant stores the platform's `struct linger` directly,
373 : avoiding the opaque-storage indirection of the type-erased
374 : version.
375 :
376 : @par Example
377 : @par !example linger
378 : */
379 : class linger
380 : {
381 : struct ::linger value_{};
382 :
383 : public:
384 : /// Construct with default values (disabled, zero timeout).
385 215 : linger() = default;
386 :
387 : /** Construct with explicit values.
388 :
389 : @param enabled `true` to enable linger behavior on close.
390 : @param timeout The linger timeout in seconds.
391 : */
392 203 : linger(bool enabled, int timeout) noexcept
393 203 : {
394 203 : value_.l_onoff = enabled ? 1 : 0;
395 203 : value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
396 203 : }
397 :
398 : /// Return whether linger is enabled.
399 22 : bool enabled() const noexcept
400 : {
401 22 : return value_.l_onoff != 0;
402 : }
403 :
404 : /// Set whether linger is enabled.
405 4 : void enabled(bool v) noexcept
406 : {
407 4 : value_.l_onoff = v ? 1 : 0;
408 4 : }
409 :
410 : /// Return the linger timeout in seconds.
411 20 : int timeout() const noexcept
412 : {
413 20 : return static_cast<int>(value_.l_linger);
414 : }
415 :
416 : /// Set the linger timeout in seconds.
417 4 : void timeout(int v) noexcept
418 : {
419 4 : value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
420 4 : }
421 :
422 : /// Return the protocol level for `setsockopt`/`getsockopt`.
423 217 : static constexpr int level() noexcept
424 : {
425 217 : return SOL_SOCKET;
426 : }
427 :
428 : /// Return the option name for `setsockopt`/`getsockopt`.
429 217 : static constexpr int name() noexcept
430 : {
431 217 : return SO_LINGER;
432 : }
433 :
434 : /// Return a pointer to the underlying storage.
435 241 : void* data() noexcept
436 : {
437 241 : return &value_;
438 : }
439 :
440 : /// Return a pointer to the underlying storage.
441 2 : void const* data() const noexcept
442 : {
443 2 : return &value_;
444 : }
445 :
446 : /// Return the size of the underlying storage.
447 456 : std::size_t size() const noexcept
448 : {
449 456 : return sizeof(value_);
450 : }
451 :
452 : /** Normalize after `getsockopt`.
453 :
454 : No-op — `struct linger` is always returned at full size.
455 :
456 : @param s The number of bytes actually written by `getsockopt`.
457 : */
458 : void resize(std::size_t) noexcept {}
459 : };
460 :
461 : /// Disable Nagle's algorithm (TCP_NODELAY).
462 : using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
463 :
464 : /// Enable periodic keepalive probes (SO_KEEPALIVE).
465 : using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
466 :
467 : /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
468 : using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
469 :
470 : /// Allow local address reuse (SO_REUSEADDR).
471 : using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
472 :
473 : /// Allow sending to broadcast addresses (SO_BROADCAST).
474 : using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
475 :
476 : /// Set the receive buffer size (SO_RCVBUF).
477 : using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
478 :
479 : /// Set the send buffer size (SO_SNDBUF).
480 : using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
481 :
482 : #ifdef SO_REUSEPORT
483 : /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
484 : using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
485 : #endif
486 :
487 : /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
488 : using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
489 :
490 : /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
491 : using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
492 :
493 : /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
494 : using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>;
495 :
496 : /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
497 : using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
498 :
499 : /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
500 : using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
501 :
502 : /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
503 :
504 : @par Example
505 : @par !example join_group_v4
506 : */
507 : class join_group_v4
508 : {
509 : struct ip_mreq value_{};
510 :
511 : public:
512 : /// Construct with default values.
513 4 : join_group_v4() = default;
514 :
515 : /** Construct with a group and optional interface address.
516 :
517 : @param group The multicast group address to join.
518 : @param iface The local interface to use (default: any).
519 : */
520 6 : join_group_v4(
521 : ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
522 6 : {
523 6 : auto gb = group.to_bytes();
524 6 : auto ib = iface.to_bytes();
525 6 : std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
526 6 : std::memcpy(&value_.imr_interface, ib.data(), 4);
527 6 : }
528 :
529 : /// Return the protocol level for `setsockopt`/`getsockopt`.
530 8 : static constexpr int level() noexcept
531 : {
532 8 : return IPPROTO_IP;
533 : }
534 :
535 : /// Return the option name for `setsockopt`/`getsockopt`.
536 8 : static constexpr int name() noexcept
537 : {
538 8 : return IP_ADD_MEMBERSHIP;
539 : }
540 :
541 : /// Return a pointer to the underlying storage.
542 6 : void* data() noexcept
543 : {
544 6 : return &value_;
545 : }
546 :
547 : /// Return a pointer to the underlying storage.
548 2 : void const* data() const noexcept
549 : {
550 2 : return &value_;
551 : }
552 :
553 : /// Return the size of the underlying storage.
554 12 : std::size_t size() const noexcept
555 : {
556 12 : return sizeof(value_);
557 : }
558 :
559 : /// No-op resize.
560 : void resize(std::size_t) noexcept {}
561 : };
562 :
563 : /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
564 :
565 : @par Example
566 : @par !example leave_group_v4
567 : */
568 : class leave_group_v4
569 : {
570 : struct ip_mreq value_{};
571 :
572 : public:
573 : /// Construct with default values.
574 2 : leave_group_v4() = default;
575 :
576 : /** Construct with a group and optional interface address.
577 :
578 : @param group The multicast group address to leave.
579 : @param iface The local interface (default: any).
580 : */
581 4 : leave_group_v4(
582 : ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
583 4 : {
584 4 : auto gb = group.to_bytes();
585 4 : auto ib = iface.to_bytes();
586 4 : std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
587 4 : std::memcpy(&value_.imr_interface, ib.data(), 4);
588 4 : }
589 :
590 : /// Return the protocol level for `setsockopt`/`getsockopt`.
591 6 : static constexpr int level() noexcept
592 : {
593 6 : return IPPROTO_IP;
594 : }
595 :
596 : /// Return the option name for `setsockopt`/`getsockopt`.
597 6 : static constexpr int name() noexcept
598 : {
599 6 : return IP_DROP_MEMBERSHIP;
600 : }
601 :
602 : /// Return a pointer to the underlying storage.
603 4 : void* data() noexcept
604 : {
605 4 : return &value_;
606 : }
607 :
608 : /// Return a pointer to the underlying storage.
609 2 : void const* data() const noexcept
610 : {
611 2 : return &value_;
612 : }
613 :
614 : /// Return the size of the underlying storage.
615 8 : std::size_t size() const noexcept
616 : {
617 8 : return sizeof(value_);
618 : }
619 :
620 : /// No-op resize.
621 : void resize(std::size_t) noexcept {}
622 : };
623 :
624 : /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
625 :
626 : @par Example
627 : @par !example join_group_v6
628 : */
629 : class join_group_v6
630 : {
631 : struct ipv6_mreq value_{};
632 :
633 : public:
634 : /// Construct with default values.
635 4 : join_group_v6() = default;
636 :
637 : /** Construct with a group and optional interface index.
638 :
639 : @param group The multicast group address to join.
640 : @param if_index The interface index (0 = kernel chooses).
641 : */
642 6 : join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
643 6 : {
644 6 : auto gb = group.to_bytes();
645 6 : std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
646 6 : value_.ipv6mr_interface = if_index;
647 6 : }
648 :
649 : /// Return the protocol level for `setsockopt`/`getsockopt`.
650 8 : static constexpr int level() noexcept
651 : {
652 8 : return IPPROTO_IPV6;
653 : }
654 :
655 : /// Return the option name for `setsockopt`/`getsockopt`.
656 8 : static constexpr int name() noexcept
657 : {
658 8 : return IPV6_JOIN_GROUP;
659 : }
660 :
661 : /// Return a pointer to the underlying storage.
662 6 : void* data() noexcept
663 : {
664 6 : return &value_;
665 : }
666 :
667 : /// Return a pointer to the underlying storage.
668 2 : void const* data() const noexcept
669 : {
670 2 : return &value_;
671 : }
672 :
673 : /// Return the size of the underlying storage.
674 12 : std::size_t size() const noexcept
675 : {
676 12 : return sizeof(value_);
677 : }
678 :
679 : /// No-op resize.
680 : void resize(std::size_t) noexcept {}
681 : };
682 :
683 : /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
684 :
685 : @par Example
686 : @par !example leave_group_v6
687 : */
688 : class leave_group_v6
689 : {
690 : struct ipv6_mreq value_{};
691 :
692 : public:
693 : /// Construct with default values.
694 4 : leave_group_v6() = default;
695 :
696 : /** Construct with a group and optional interface index.
697 :
698 : @param group The multicast group address to leave.
699 : @param if_index The interface index (0 = kernel chooses).
700 : */
701 6 : leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
702 6 : {
703 6 : auto gb = group.to_bytes();
704 6 : std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
705 6 : value_.ipv6mr_interface = if_index;
706 6 : }
707 :
708 : /// Return the protocol level for `setsockopt`/`getsockopt`.
709 8 : static constexpr int level() noexcept
710 : {
711 8 : return IPPROTO_IPV6;
712 : }
713 :
714 : /// Return the option name for `setsockopt`/`getsockopt`.
715 8 : static constexpr int name() noexcept
716 : {
717 8 : return IPV6_LEAVE_GROUP;
718 : }
719 :
720 : /// Return a pointer to the underlying storage.
721 6 : void* data() noexcept
722 : {
723 6 : return &value_;
724 : }
725 :
726 : /// Return a pointer to the underlying storage.
727 2 : void const* data() const noexcept
728 : {
729 2 : return &value_;
730 : }
731 :
732 : /// Return the size of the underlying storage.
733 12 : std::size_t size() const noexcept
734 : {
735 12 : return sizeof(value_);
736 : }
737 :
738 : /// No-op resize.
739 : void resize(std::size_t) noexcept {}
740 : };
741 :
742 : /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
743 :
744 : Unlike the integer-based `multicast_interface_v6`, this option
745 : takes an `ipv4_address` identifying the local interface.
746 :
747 : @par Example
748 : @par !example multicast_interface_v4
749 : */
750 : class multicast_interface_v4
751 : {
752 : struct in_addr value_{};
753 :
754 : public:
755 : /// Construct with default values (INADDR_ANY).
756 2 : multicast_interface_v4() = default;
757 :
758 : /** Construct with an interface address.
759 :
760 : @param iface The local interface address.
761 : */
762 4 : explicit multicast_interface_v4(ipv4_address iface) noexcept
763 4 : {
764 4 : auto b = iface.to_bytes();
765 4 : std::memcpy(&value_, b.data(), 4);
766 4 : }
767 :
768 : /// Return the protocol level for `setsockopt`/`getsockopt`.
769 6 : static constexpr int level() noexcept
770 : {
771 6 : return IPPROTO_IP;
772 : }
773 :
774 : /// Return the option name for `setsockopt`/`getsockopt`.
775 6 : static constexpr int name() noexcept
776 : {
777 6 : return IP_MULTICAST_IF;
778 : }
779 :
780 : /// Return a pointer to the underlying storage.
781 4 : void* data() noexcept
782 : {
783 4 : return &value_;
784 : }
785 :
786 : /// Return a pointer to the underlying storage.
787 2 : void const* data() const noexcept
788 : {
789 2 : return &value_;
790 : }
791 :
792 : /// Return the size of the underlying storage.
793 8 : std::size_t size() const noexcept
794 : {
795 8 : return sizeof(value_);
796 : }
797 :
798 : /// No-op resize.
799 : void resize(std::size_t) noexcept {}
800 : };
801 :
802 : } // namespace boost::corosio::native_socket_option
803 :
804 : #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
|