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