include/boost/corosio/socket_option.hpp

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