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