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