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