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