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