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 { return value_ != 0; }
270 : explicit operator bool() const noexcept { return value_ != 0; }
271 : bool operator!() const noexcept { return value_ == 0; }
272 :
273 22 : static constexpr int level() noexcept { return Level; }
274 22 : static constexpr int name() noexcept { return Name; }
275 :
276 2 : void* data() noexcept { return &value_; }
277 2 : void const* data() const noexcept { return &value_; }
278 4 : std::size_t size() const noexcept { return sizeof(value_); }
279 :
280 2 : void resize(std::size_t) noexcept {}
281 : };
282 :
283 : /** An integer socket option with single-byte storage.
284 :
285 : Same rationale as `byte_boolean`: BSD-derived kernels require
286 : `IP_MULTICAST_TTL` to be set with a one-byte value. Linux accepts
287 : one byte too, so single-byte storage is portable. Values are
288 : truncated to the 0–255 range.
289 :
290 : @tparam Level The protocol level.
291 : @tparam Name The option name.
292 : */
293 : template<int Level, int Name>
294 : class byte_integer
295 : {
296 : unsigned char value_ = 0;
297 :
298 : public:
299 : byte_integer() = default;
300 :
301 2 : explicit byte_integer(int v) noexcept
302 2 : : value_(static_cast<unsigned char>(v))
303 2 : {}
304 :
305 : byte_integer& operator=(int v) noexcept
306 : {
307 : value_ = static_cast<unsigned char>(v);
308 : return *this;
309 : }
310 :
311 2 : int value() const noexcept { return value_; }
312 :
313 12 : static constexpr int level() noexcept { return Level; }
314 12 : static constexpr int name() noexcept { return Name; }
315 :
316 2 : void* data() noexcept { return &value_; }
317 2 : void const* data() const noexcept { return &value_; }
318 4 : std::size_t size() const noexcept { return sizeof(value_); }
319 :
320 2 : void resize(std::size_t) noexcept {}
321 : };
322 :
323 : /** The SO_LINGER socket option (native variant).
324 :
325 : Controls behavior when closing a socket with unsent data.
326 : When enabled, `close()` blocks until pending data is sent
327 : or the timeout expires.
328 :
329 : This variant stores the platform's `struct linger` directly,
330 : avoiding the opaque-storage indirection of the type-erased
331 : version.
332 :
333 : @par Example
334 : @par !example linger
335 : */
336 : class linger
337 : {
338 : struct ::linger value_{};
339 :
340 : public:
341 : /// Construct with default values (disabled, zero timeout).
342 215 : linger() = default;
343 :
344 : /** Construct with explicit values.
345 :
346 : @param enabled `true` to enable linger behavior on close.
347 : @param timeout The linger timeout in seconds.
348 : */
349 203 : linger(bool enabled, int timeout) noexcept
350 203 : {
351 203 : value_.l_onoff = enabled ? 1 : 0;
352 203 : value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
353 203 : }
354 :
355 : /// Return whether linger is enabled.
356 22 : bool enabled() const noexcept
357 : {
358 22 : return value_.l_onoff != 0;
359 : }
360 :
361 : /// Set whether linger is enabled.
362 4 : void enabled(bool v) noexcept
363 : {
364 4 : value_.l_onoff = v ? 1 : 0;
365 4 : }
366 :
367 : /// Return the linger timeout in seconds.
368 20 : int timeout() const noexcept
369 : {
370 20 : return static_cast<int>(value_.l_linger);
371 : }
372 :
373 : /// Set the linger timeout in seconds.
374 4 : void timeout(int v) noexcept
375 : {
376 4 : value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
377 4 : }
378 :
379 : /// Return the protocol level for `setsockopt`/`getsockopt`.
380 217 : static constexpr int level() noexcept
381 : {
382 217 : return SOL_SOCKET;
383 : }
384 :
385 : /// Return the option name for `setsockopt`/`getsockopt`.
386 217 : static constexpr int name() noexcept
387 : {
388 217 : return SO_LINGER;
389 : }
390 :
391 : /// Return a pointer to the underlying storage.
392 241 : void* data() noexcept
393 : {
394 241 : return &value_;
395 : }
396 :
397 : /// Return a pointer to the underlying storage.
398 2 : void const* data() const noexcept
399 : {
400 2 : return &value_;
401 : }
402 :
403 : /// Return the size of the underlying storage.
404 456 : std::size_t size() const noexcept
405 : {
406 456 : return sizeof(value_);
407 : }
408 :
409 : /** Normalize after `getsockopt`.
410 :
411 : No-op — `struct linger` is always returned at full size.
412 :
413 : @param s The number of bytes actually written by `getsockopt`.
414 : */
415 : void resize(std::size_t) noexcept {}
416 : };
417 :
418 : /// Disable Nagle's algorithm (TCP_NODELAY).
419 : using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
420 :
421 : /// Enable periodic keepalive probes (SO_KEEPALIVE).
422 : using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
423 :
424 : /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
425 : using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
426 :
427 : /// Allow local address reuse (SO_REUSEADDR).
428 : using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
429 :
430 : /// Allow sending to broadcast addresses (SO_BROADCAST).
431 : using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
432 :
433 : /// Set the receive buffer size (SO_RCVBUF).
434 : using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
435 :
436 : /// Set the send buffer size (SO_SNDBUF).
437 : using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
438 :
439 : #ifdef SO_REUSEPORT
440 : /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
441 : using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
442 : #endif
443 :
444 : /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
445 : using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
446 :
447 : /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
448 : using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
449 :
450 : /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
451 : using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>;
452 :
453 : /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
454 : using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
455 :
456 : /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
457 : using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
458 :
459 : /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
460 :
461 : @par Example
462 : @par !example join_group_v4
463 : */
464 : class join_group_v4
465 : {
466 : struct ip_mreq value_{};
467 :
468 : public:
469 : /// Construct with default values.
470 4 : join_group_v4() = default;
471 :
472 : /** Construct with a group and optional interface address.
473 :
474 : @param group The multicast group address to join.
475 : @param iface The local interface to use (default: any).
476 : */
477 6 : join_group_v4(
478 : ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
479 6 : {
480 6 : auto gb = group.to_bytes();
481 6 : auto ib = iface.to_bytes();
482 6 : std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
483 6 : std::memcpy(&value_.imr_interface, ib.data(), 4);
484 6 : }
485 :
486 : /// Return the protocol level for `setsockopt`/`getsockopt`.
487 8 : static constexpr int level() noexcept
488 : {
489 8 : return IPPROTO_IP;
490 : }
491 :
492 : /// Return the option name for `setsockopt`/`getsockopt`.
493 8 : static constexpr int name() noexcept
494 : {
495 8 : return IP_ADD_MEMBERSHIP;
496 : }
497 :
498 : /// Return a pointer to the underlying storage.
499 6 : void* data() noexcept
500 : {
501 6 : return &value_;
502 : }
503 :
504 : /// Return a pointer to the underlying storage.
505 2 : void const* data() const noexcept
506 : {
507 2 : return &value_;
508 : }
509 :
510 : /// Return the size of the underlying storage.
511 12 : std::size_t size() const noexcept
512 : {
513 12 : return sizeof(value_);
514 : }
515 :
516 : /// No-op resize.
517 : void resize(std::size_t) noexcept {}
518 : };
519 :
520 : /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
521 :
522 : @par Example
523 : @par !example leave_group_v4
524 : */
525 : class leave_group_v4
526 : {
527 : struct ip_mreq value_{};
528 :
529 : public:
530 : /// Construct with default values.
531 2 : leave_group_v4() = default;
532 :
533 : /** Construct with a group and optional interface address.
534 :
535 : @param group The multicast group address to leave.
536 : @param iface The local interface (default: any).
537 : */
538 4 : leave_group_v4(
539 : ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
540 4 : {
541 4 : auto gb = group.to_bytes();
542 4 : auto ib = iface.to_bytes();
543 4 : std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
544 4 : std::memcpy(&value_.imr_interface, ib.data(), 4);
545 4 : }
546 :
547 : /// Return the protocol level for `setsockopt`/`getsockopt`.
548 6 : static constexpr int level() noexcept
549 : {
550 6 : return IPPROTO_IP;
551 : }
552 :
553 : /// Return the option name for `setsockopt`/`getsockopt`.
554 6 : static constexpr int name() noexcept
555 : {
556 6 : return IP_DROP_MEMBERSHIP;
557 : }
558 :
559 : /// Return a pointer to the underlying storage.
560 4 : void* data() noexcept
561 : {
562 4 : return &value_;
563 : }
564 :
565 : /// Return a pointer to the underlying storage.
566 2 : void const* data() const noexcept
567 : {
568 2 : return &value_;
569 : }
570 :
571 : /// Return the size of the underlying storage.
572 8 : std::size_t size() const noexcept
573 : {
574 8 : return sizeof(value_);
575 : }
576 :
577 : /// No-op resize.
578 : void resize(std::size_t) noexcept {}
579 : };
580 :
581 : /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
582 :
583 : @par Example
584 : @par !example join_group_v6
585 : */
586 : class join_group_v6
587 : {
588 : struct ipv6_mreq value_{};
589 :
590 : public:
591 : /// Construct with default values.
592 4 : join_group_v6() = default;
593 :
594 : /** Construct with a group and optional interface index.
595 :
596 : @param group The multicast group address to join.
597 : @param if_index The interface index (0 = kernel chooses).
598 : */
599 6 : join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
600 6 : {
601 6 : auto gb = group.to_bytes();
602 6 : std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
603 6 : value_.ipv6mr_interface = if_index;
604 6 : }
605 :
606 : /// Return the protocol level for `setsockopt`/`getsockopt`.
607 8 : static constexpr int level() noexcept
608 : {
609 8 : return IPPROTO_IPV6;
610 : }
611 :
612 : /// Return the option name for `setsockopt`/`getsockopt`.
613 8 : static constexpr int name() noexcept
614 : {
615 8 : return IPV6_JOIN_GROUP;
616 : }
617 :
618 : /// Return a pointer to the underlying storage.
619 6 : void* data() noexcept
620 : {
621 6 : return &value_;
622 : }
623 :
624 : /// Return a pointer to the underlying storage.
625 2 : void const* data() const noexcept
626 : {
627 2 : return &value_;
628 : }
629 :
630 : /// Return the size of the underlying storage.
631 12 : std::size_t size() const noexcept
632 : {
633 12 : return sizeof(value_);
634 : }
635 :
636 : /// No-op resize.
637 : void resize(std::size_t) noexcept {}
638 : };
639 :
640 : /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
641 :
642 : @par Example
643 : @par !example leave_group_v6
644 : */
645 : class leave_group_v6
646 : {
647 : struct ipv6_mreq value_{};
648 :
649 : public:
650 : /// Construct with default values.
651 4 : leave_group_v6() = default;
652 :
653 : /** Construct with a group and optional interface index.
654 :
655 : @param group The multicast group address to leave.
656 : @param if_index The interface index (0 = kernel chooses).
657 : */
658 6 : leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
659 6 : {
660 6 : auto gb = group.to_bytes();
661 6 : std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
662 6 : value_.ipv6mr_interface = if_index;
663 6 : }
664 :
665 : /// Return the protocol level for `setsockopt`/`getsockopt`.
666 8 : static constexpr int level() noexcept
667 : {
668 8 : return IPPROTO_IPV6;
669 : }
670 :
671 : /// Return the option name for `setsockopt`/`getsockopt`.
672 8 : static constexpr int name() noexcept
673 : {
674 8 : return IPV6_LEAVE_GROUP;
675 : }
676 :
677 : /// Return a pointer to the underlying storage.
678 6 : void* data() noexcept
679 : {
680 6 : return &value_;
681 : }
682 :
683 : /// Return a pointer to the underlying storage.
684 2 : void const* data() const noexcept
685 : {
686 2 : return &value_;
687 : }
688 :
689 : /// Return the size of the underlying storage.
690 12 : std::size_t size() const noexcept
691 : {
692 12 : return sizeof(value_);
693 : }
694 :
695 : /// No-op resize.
696 : void resize(std::size_t) noexcept {}
697 : };
698 :
699 : /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
700 :
701 : Unlike the integer-based `multicast_interface_v6`, this option
702 : takes an `ipv4_address` identifying the local interface.
703 :
704 : @par Example
705 : @par !example multicast_interface_v4
706 : */
707 : class multicast_interface_v4
708 : {
709 : struct in_addr value_{};
710 :
711 : public:
712 : /// Construct with default values (INADDR_ANY).
713 2 : multicast_interface_v4() = default;
714 :
715 : /** Construct with an interface address.
716 :
717 : @param iface The local interface address.
718 : */
719 4 : explicit multicast_interface_v4(ipv4_address iface) noexcept
720 4 : {
721 4 : auto b = iface.to_bytes();
722 4 : std::memcpy(&value_, b.data(), 4);
723 4 : }
724 :
725 : /// Return the protocol level for `setsockopt`/`getsockopt`.
726 6 : static constexpr int level() noexcept
727 : {
728 6 : return IPPROTO_IP;
729 : }
730 :
731 : /// Return the option name for `setsockopt`/`getsockopt`.
732 6 : static constexpr int name() noexcept
733 : {
734 6 : return IP_MULTICAST_IF;
735 : }
736 :
737 : /// Return a pointer to the underlying storage.
738 4 : void* data() noexcept
739 : {
740 4 : return &value_;
741 : }
742 :
743 : /// Return a pointer to the underlying storage.
744 2 : void const* data() const noexcept
745 : {
746 2 : return &value_;
747 : }
748 :
749 : /// Return the size of the underlying storage.
750 8 : std::size_t size() const noexcept
751 : {
752 8 : return sizeof(value_);
753 : }
754 :
755 : /// No-op resize.
756 : void resize(std::size_t) noexcept {}
757 : };
758 :
759 : } // namespace boost::corosio::native_socket_option
760 :
761 : #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
|