100.00% Lines (177/177) 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
270   { 270   {
HITCBC 271   2 return value_ != 0; 271   2 return value_ != 0;
272   } 272   }
273   explicit operator bool() const noexcept 273   explicit operator bool() const noexcept
274   { 274   {
275   return value_ != 0; 275   return value_ != 0;
276   } 276   }
277   bool operator!() const noexcept 277   bool operator!() const noexcept
278   { 278   {
279   return value_ == 0; 279   return value_ == 0;
280   } 280   }
281   281  
HITCBC 282   22 static constexpr int level() noexcept 282   22 static constexpr int level() noexcept
283   { 283   {
HITCBC 284   22 return Level; 284   22 return Level;
285   } 285   }
HITCBC 286   22 static constexpr int name() noexcept 286   22 static constexpr int name() noexcept
287   { 287   {
HITCBC 288   22 return Name; 288   22 return Name;
289   } 289   }
290   290  
HITCBC 291   2 void* data() noexcept 291   2 void* data() noexcept
292   { 292   {
HITCBC 293   2 return &value_; 293   2 return &value_;
294   } 294   }
HITCBC 295   2 void const* data() const noexcept 295   2 void const* data() const noexcept
296   { 296   {
HITCBC 297   2 return &value_; 297   2 return &value_;
298   } 298   }
HITCBC 299   4 std::size_t size() const noexcept 299   4 std::size_t size() const noexcept
300   { 300   {
HITCBC 301   4 return sizeof(value_); 301   4 return sizeof(value_);
302   } 302   }
303   303  
HITCBC 304   2 void resize(std::size_t) noexcept {} 304   2 void resize(std::size_t) noexcept {}
305   }; 305   };
306   306  
307   /** An integer socket option with single-byte storage. 307   /** An integer socket option with single-byte storage.
308   308  
309   Same rationale as `byte_boolean`: BSD-derived kernels require 309   Same rationale as `byte_boolean`: BSD-derived kernels require
310   `IP_MULTICAST_TTL` to be set with a one-byte value. Linux accepts 310   `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 311   one byte too, so single-byte storage is portable. Values are
312   truncated to the 0–255 range. 312   truncated to the 0–255 range.
313   313  
314   @tparam Level The protocol level. 314   @tparam Level The protocol level.
315   @tparam Name The option name. 315   @tparam Name The option name.
316   */ 316   */
317   template<int Level, int Name> 317   template<int Level, int Name>
318   class byte_integer 318   class byte_integer
319   { 319   {
320   unsigned char value_ = 0; 320   unsigned char value_ = 0;
321   321  
322   public: 322   public:
323   byte_integer() = default; 323   byte_integer() = default;
324   324  
HITCBC 325   2 explicit byte_integer(int v) noexcept 325   2 explicit byte_integer(int v) noexcept
HITCBC 326   2 : value_(static_cast<unsigned char>(v)) 326   2 : value_(static_cast<unsigned char>(v))
327   { 327   {
HITCBC 328   2 } 328   2 }
329   329  
330   byte_integer& operator=(int v) noexcept 330   byte_integer& operator=(int v) noexcept
331   { 331   {
332   value_ = static_cast<unsigned char>(v); 332   value_ = static_cast<unsigned char>(v);
333   return *this; 333   return *this;
334   } 334   }
335   335  
HITCBC 336   2 int value() const noexcept 336   2 int value() const noexcept
337   { 337   {
HITCBC 338   2 return value_; 338   2 return value_;
339   } 339   }
340   340  
HITCBC 341   12 static constexpr int level() noexcept 341   12 static constexpr int level() noexcept
342   { 342   {
HITCBC 343   12 return Level; 343   12 return Level;
344   } 344   }
HITCBC 345   12 static constexpr int name() noexcept 345   12 static constexpr int name() noexcept
346   { 346   {
HITCBC 347   12 return Name; 347   12 return Name;
348   } 348   }
349   349  
HITCBC 350   2 void* data() noexcept 350   2 void* data() noexcept
351   { 351   {
HITCBC 352   2 return &value_; 352   2 return &value_;
353   } 353   }
HITCBC 354   2 void const* data() const noexcept 354   2 void const* data() const noexcept
355   { 355   {
HITCBC 356   2 return &value_; 356   2 return &value_;
357   } 357   }
HITCBC 358   4 std::size_t size() const noexcept 358   4 std::size_t size() const noexcept
359   { 359   {
HITCBC 360   4 return sizeof(value_); 360   4 return sizeof(value_);
361   } 361   }
362   362  
HITCBC 363   2 void resize(std::size_t) noexcept {} 363   2 void resize(std::size_t) noexcept {}
364   }; 364   };
365   365  
366   /** The SO_LINGER socket option (native variant). 366   /** The SO_LINGER socket option (native variant).
367   367  
368   Controls behavior when closing a socket with unsent data. 368   Controls behavior when closing a socket with unsent data.
369   When enabled, `close()` blocks until pending data is sent 369   When enabled, `close()` blocks until pending data is sent
370   or the timeout expires. 370   or the timeout expires.
371   371  
372   This variant stores the platform's `struct linger` directly, 372   This variant stores the platform's `struct linger` directly,
373   avoiding the opaque-storage indirection of the type-erased 373   avoiding the opaque-storage indirection of the type-erased
374   version. 374   version.
375   375  
376   @par Example 376   @par Example
377   @par !example linger 377   @par !example linger
378   */ 378   */
379   class linger 379   class linger
380   { 380   {
381   struct ::linger value_{}; 381   struct ::linger value_{};
382   382  
383   public: 383   public:
384   /// Construct with default values (disabled, zero timeout). 384   /// Construct with default values (disabled, zero timeout).
HITCBC 385   215 linger() = default; 385   215 linger() = default;
386   386  
387   /** Construct with explicit values. 387   /** Construct with explicit values.
388   388  
389   @param enabled `true` to enable linger behavior on close. 389   @param enabled `true` to enable linger behavior on close.
390   @param timeout The linger timeout in seconds. 390   @param timeout The linger timeout in seconds.
391   */ 391   */
HITCBC 392   203 linger(bool enabled, int timeout) noexcept 392   203 linger(bool enabled, int timeout) noexcept
HITCBC 393   203 { 393   203 {
HITCBC 394   203 value_.l_onoff = enabled ? 1 : 0; 394   203 value_.l_onoff = enabled ? 1 : 0;
HITCBC 395   203 value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout); 395   203 value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
HITCBC 396   203 } 396   203 }
397   397  
398   /// Return whether linger is enabled. 398   /// Return whether linger is enabled.
HITCBC 399   22 bool enabled() const noexcept 399   22 bool enabled() const noexcept
400   { 400   {
HITCBC 401   22 return value_.l_onoff != 0; 401   22 return value_.l_onoff != 0;
402   } 402   }
403   403  
404   /// Set whether linger is enabled. 404   /// Set whether linger is enabled.
HITCBC 405   4 void enabled(bool v) noexcept 405   4 void enabled(bool v) noexcept
406   { 406   {
HITCBC 407   4 value_.l_onoff = v ? 1 : 0; 407   4 value_.l_onoff = v ? 1 : 0;
HITCBC 408   4 } 408   4 }
409   409  
410   /// Return the linger timeout in seconds. 410   /// Return the linger timeout in seconds.
HITCBC 411   20 int timeout() const noexcept 411   20 int timeout() const noexcept
412   { 412   {
HITCBC 413   20 return static_cast<int>(value_.l_linger); 413   20 return static_cast<int>(value_.l_linger);
414   } 414   }
415   415  
416   /// Set the linger timeout in seconds. 416   /// Set the linger timeout in seconds.
HITCBC 417   4 void timeout(int v) noexcept 417   4 void timeout(int v) noexcept
418   { 418   {
HITCBC 419   4 value_.l_linger = static_cast<decltype(value_.l_linger)>(v); 419   4 value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
HITCBC 420   4 } 420   4 }
421   421  
422   /// Return the protocol level for `setsockopt`/`getsockopt`. 422   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 423   217 static constexpr int level() noexcept 423   217 static constexpr int level() noexcept
424   { 424   {
HITCBC 425   217 return SOL_SOCKET; 425   217 return SOL_SOCKET;
426   } 426   }
427   427  
428   /// Return the option name for `setsockopt`/`getsockopt`. 428   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 429   217 static constexpr int name() noexcept 429   217 static constexpr int name() noexcept
430   { 430   {
HITCBC 431   217 return SO_LINGER; 431   217 return SO_LINGER;
432   } 432   }
433   433  
434   /// Return a pointer to the underlying storage. 434   /// Return a pointer to the underlying storage.
HITCBC 435   241 void* data() noexcept 435   241 void* data() noexcept
436   { 436   {
HITCBC 437   241 return &value_; 437   241 return &value_;
438   } 438   }
439   439  
440   /// Return a pointer to the underlying storage. 440   /// Return a pointer to the underlying storage.
HITCBC 441   2 void const* data() const noexcept 441   2 void const* data() const noexcept
442   { 442   {
HITCBC 443   2 return &value_; 443   2 return &value_;
444   } 444   }
445   445  
446   /// Return the size of the underlying storage. 446   /// Return the size of the underlying storage.
HITCBC 447   456 std::size_t size() const noexcept 447   456 std::size_t size() const noexcept
448   { 448   {
HITCBC 449   456 return sizeof(value_); 449   456 return sizeof(value_);
450   } 450   }
451   451  
452   /** Normalize after `getsockopt`. 452   /** Normalize after `getsockopt`.
453   453  
454   No-op — `struct linger` is always returned at full size. 454   No-op — `struct linger` is always returned at full size.
455   455  
456   @param s The number of bytes actually written by `getsockopt`. 456   @param s The number of bytes actually written by `getsockopt`.
457   */ 457   */
458   void resize(std::size_t) noexcept {} 458   void resize(std::size_t) noexcept {}
459   }; 459   };
460   460  
461   /// Disable Nagle's algorithm (TCP_NODELAY). 461   /// Disable Nagle's algorithm (TCP_NODELAY).
462   using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>; 462   using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
463   463  
464   /// Enable periodic keepalive probes (SO_KEEPALIVE). 464   /// Enable periodic keepalive probes (SO_KEEPALIVE).
465   using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>; 465   using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
466   466  
467   /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY). 467   /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
468   using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>; 468   using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
469   469  
470   /// Allow local address reuse (SO_REUSEADDR). 470   /// Allow local address reuse (SO_REUSEADDR).
471   using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>; 471   using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
472   472  
473   /// Allow sending to broadcast addresses (SO_BROADCAST). 473   /// Allow sending to broadcast addresses (SO_BROADCAST).
474   using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>; 474   using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
475   475  
476   /// Set the receive buffer size (SO_RCVBUF). 476   /// Set the receive buffer size (SO_RCVBUF).
477   using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>; 477   using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
478   478  
479   /// Set the send buffer size (SO_SNDBUF). 479   /// Set the send buffer size (SO_SNDBUF).
480   using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>; 480   using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
481   481  
482   #ifdef SO_REUSEPORT 482   #ifdef SO_REUSEPORT
483   /// Allow multiple sockets to bind to the same port (SO_REUSEPORT). 483   /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
484   using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>; 484   using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
485   #endif 485   #endif
486   486  
487   /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP). 487   /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
488   using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>; 488   using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
489   489  
490   /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP). 490   /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
491   using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>; 491   using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
492   492  
493   /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL). 493   /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
494   using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>; 494   using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>;
495   495  
496   /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS). 496   /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
497   using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>; 497   using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
498   498  
499   /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF). 499   /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
500   using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>; 500   using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
501   501  
502   /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP). 502   /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
503   503  
504   @par Example 504   @par Example
505   @par !example join_group_v4 505   @par !example join_group_v4
506   */ 506   */
507   class join_group_v4 507   class join_group_v4
508   { 508   {
509   struct ip_mreq value_{}; 509   struct ip_mreq value_{};
510   510  
511   public: 511   public:
512   /// Construct with default values. 512   /// Construct with default values.
HITCBC 513   4 join_group_v4() = default; 513   4 join_group_v4() = default;
514   514  
515   /** Construct with a group and optional interface address. 515   /** Construct with a group and optional interface address.
516   516  
517   @param group The multicast group address to join. 517   @param group The multicast group address to join.
518   @param iface The local interface to use (default: any). 518   @param iface The local interface to use (default: any).
519   */ 519   */
HITCBC 520   6 join_group_v4( 520   6 join_group_v4(
521   ipv4_address group, ipv4_address iface = ipv4_address()) noexcept 521   ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
HITCBC 522   6 { 522   6 {
HITCBC 523   6 auto gb = group.to_bytes(); 523   6 auto gb = group.to_bytes();
HITCBC 524   6 auto ib = iface.to_bytes(); 524   6 auto ib = iface.to_bytes();
HITCBC 525   6 std::memcpy(&value_.imr_multiaddr, gb.data(), 4); 525   6 std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
HITCBC 526   6 std::memcpy(&value_.imr_interface, ib.data(), 4); 526   6 std::memcpy(&value_.imr_interface, ib.data(), 4);
HITCBC 527   6 } 527   6 }
528   528  
529   /// Return the protocol level for `setsockopt`/`getsockopt`. 529   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 530   8 static constexpr int level() noexcept 530   8 static constexpr int level() noexcept
531   { 531   {
HITCBC 532   8 return IPPROTO_IP; 532   8 return IPPROTO_IP;
533   } 533   }
534   534  
535   /// Return the option name for `setsockopt`/`getsockopt`. 535   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 536   8 static constexpr int name() noexcept 536   8 static constexpr int name() noexcept
537   { 537   {
HITCBC 538   8 return IP_ADD_MEMBERSHIP; 538   8 return IP_ADD_MEMBERSHIP;
539   } 539   }
540   540  
541   /// Return a pointer to the underlying storage. 541   /// Return a pointer to the underlying storage.
HITCBC 542   6 void* data() noexcept 542   6 void* data() noexcept
543   { 543   {
HITCBC 544   6 return &value_; 544   6 return &value_;
545   } 545   }
546   546  
547   /// Return a pointer to the underlying storage. 547   /// Return a pointer to the underlying storage.
HITCBC 548   2 void const* data() const noexcept 548   2 void const* data() const noexcept
549   { 549   {
HITCBC 550   2 return &value_; 550   2 return &value_;
551   } 551   }
552   552  
553   /// Return the size of the underlying storage. 553   /// Return the size of the underlying storage.
HITCBC 554   12 std::size_t size() const noexcept 554   12 std::size_t size() const noexcept
555   { 555   {
HITCBC 556   12 return sizeof(value_); 556   12 return sizeof(value_);
557   } 557   }
558   558  
559   /// No-op resize. 559   /// No-op resize.
560   void resize(std::size_t) noexcept {} 560   void resize(std::size_t) noexcept {}
561   }; 561   };
562   562  
563   /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP). 563   /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
564   564  
565   @par Example 565   @par Example
566   @par !example leave_group_v4 566   @par !example leave_group_v4
567   */ 567   */
568   class leave_group_v4 568   class leave_group_v4
569   { 569   {
570   struct ip_mreq value_{}; 570   struct ip_mreq value_{};
571   571  
572   public: 572   public:
573   /// Construct with default values. 573   /// Construct with default values.
HITCBC 574   2 leave_group_v4() = default; 574   2 leave_group_v4() = default;
575   575  
576   /** Construct with a group and optional interface address. 576   /** Construct with a group and optional interface address.
577   577  
578   @param group The multicast group address to leave. 578   @param group The multicast group address to leave.
579   @param iface The local interface (default: any). 579   @param iface The local interface (default: any).
580   */ 580   */
HITCBC 581   4 leave_group_v4( 581   4 leave_group_v4(
582   ipv4_address group, ipv4_address iface = ipv4_address()) noexcept 582   ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
HITCBC 583   4 { 583   4 {
HITCBC 584   4 auto gb = group.to_bytes(); 584   4 auto gb = group.to_bytes();
HITCBC 585   4 auto ib = iface.to_bytes(); 585   4 auto ib = iface.to_bytes();
HITCBC 586   4 std::memcpy(&value_.imr_multiaddr, gb.data(), 4); 586   4 std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
HITCBC 587   4 std::memcpy(&value_.imr_interface, ib.data(), 4); 587   4 std::memcpy(&value_.imr_interface, ib.data(), 4);
HITCBC 588   4 } 588   4 }
589   589  
590   /// Return the protocol level for `setsockopt`/`getsockopt`. 590   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 591   6 static constexpr int level() noexcept 591   6 static constexpr int level() noexcept
592   { 592   {
HITCBC 593   6 return IPPROTO_IP; 593   6 return IPPROTO_IP;
594   } 594   }
595   595  
596   /// Return the option name for `setsockopt`/`getsockopt`. 596   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 597   6 static constexpr int name() noexcept 597   6 static constexpr int name() noexcept
598   { 598   {
HITCBC 599   6 return IP_DROP_MEMBERSHIP; 599   6 return IP_DROP_MEMBERSHIP;
600   } 600   }
601   601  
602   /// Return a pointer to the underlying storage. 602   /// Return a pointer to the underlying storage.
HITCBC 603   4 void* data() noexcept 603   4 void* data() noexcept
604   { 604   {
HITCBC 605   4 return &value_; 605   4 return &value_;
606   } 606   }
607   607  
608   /// Return a pointer to the underlying storage. 608   /// Return a pointer to the underlying storage.
HITCBC 609   2 void const* data() const noexcept 609   2 void const* data() const noexcept
610   { 610   {
HITCBC 611   2 return &value_; 611   2 return &value_;
612   } 612   }
613   613  
614   /// Return the size of the underlying storage. 614   /// Return the size of the underlying storage.
HITCBC 615   8 std::size_t size() const noexcept 615   8 std::size_t size() const noexcept
616   { 616   {
HITCBC 617   8 return sizeof(value_); 617   8 return sizeof(value_);
618   } 618   }
619   619  
620   /// No-op resize. 620   /// No-op resize.
621   void resize(std::size_t) noexcept {} 621   void resize(std::size_t) noexcept {}
622   }; 622   };
623   623  
624   /** Join an IPv6 multicast group (IPV6_JOIN_GROUP). 624   /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
625   625  
626   @par Example 626   @par Example
627   @par !example join_group_v6 627   @par !example join_group_v6
628   */ 628   */
629   class join_group_v6 629   class join_group_v6
630   { 630   {
631   struct ipv6_mreq value_{}; 631   struct ipv6_mreq value_{};
632   632  
633   public: 633   public:
634   /// Construct with default values. 634   /// Construct with default values.
HITCBC 635   4 join_group_v6() = default; 635   4 join_group_v6() = default;
636   636  
637   /** Construct with a group and optional interface index. 637   /** Construct with a group and optional interface index.
638   638  
639   @param group The multicast group address to join. 639   @param group The multicast group address to join.
640   @param if_index The interface index (0 = kernel chooses). 640   @param if_index The interface index (0 = kernel chooses).
641   */ 641   */
HITCBC 642   6 join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept 642   6 join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
HITCBC 643   6 { 643   6 {
HITCBC 644   6 auto gb = group.to_bytes(); 644   6 auto gb = group.to_bytes();
HITCBC 645   6 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16); 645   6 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
HITCBC 646   6 value_.ipv6mr_interface = if_index; 646   6 value_.ipv6mr_interface = if_index;
HITCBC 647   6 } 647   6 }
648   648  
649   /// Return the protocol level for `setsockopt`/`getsockopt`. 649   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 650   8 static constexpr int level() noexcept 650   8 static constexpr int level() noexcept
651   { 651   {
HITCBC 652   8 return IPPROTO_IPV6; 652   8 return IPPROTO_IPV6;
653   } 653   }
654   654  
655   /// Return the option name for `setsockopt`/`getsockopt`. 655   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 656   8 static constexpr int name() noexcept 656   8 static constexpr int name() noexcept
657   { 657   {
HITCBC 658   8 return IPV6_JOIN_GROUP; 658   8 return IPV6_JOIN_GROUP;
659   } 659   }
660   660  
661   /// Return a pointer to the underlying storage. 661   /// Return a pointer to the underlying storage.
HITCBC 662   6 void* data() noexcept 662   6 void* data() noexcept
663   { 663   {
HITCBC 664   6 return &value_; 664   6 return &value_;
665   } 665   }
666   666  
667   /// Return a pointer to the underlying storage. 667   /// Return a pointer to the underlying storage.
HITCBC 668   2 void const* data() const noexcept 668   2 void const* data() const noexcept
669   { 669   {
HITCBC 670   2 return &value_; 670   2 return &value_;
671   } 671   }
672   672  
673   /// Return the size of the underlying storage. 673   /// Return the size of the underlying storage.
HITCBC 674   12 std::size_t size() const noexcept 674   12 std::size_t size() const noexcept
675   { 675   {
HITCBC 676   12 return sizeof(value_); 676   12 return sizeof(value_);
677   } 677   }
678   678  
679   /// No-op resize. 679   /// No-op resize.
680   void resize(std::size_t) noexcept {} 680   void resize(std::size_t) noexcept {}
681   }; 681   };
682   682  
683   /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP). 683   /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
684   684  
685   @par Example 685   @par Example
686   @par !example leave_group_v6 686   @par !example leave_group_v6
687   */ 687   */
688   class leave_group_v6 688   class leave_group_v6
689   { 689   {
690   struct ipv6_mreq value_{}; 690   struct ipv6_mreq value_{};
691   691  
692   public: 692   public:
693   /// Construct with default values. 693   /// Construct with default values.
HITCBC 694   4 leave_group_v6() = default; 694   4 leave_group_v6() = default;
695   695  
696   /** Construct with a group and optional interface index. 696   /** Construct with a group and optional interface index.
697   697  
698   @param group The multicast group address to leave. 698   @param group The multicast group address to leave.
699   @param if_index The interface index (0 = kernel chooses). 699   @param if_index The interface index (0 = kernel chooses).
700   */ 700   */
HITCBC 701   6 leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept 701   6 leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
HITCBC 702   6 { 702   6 {
HITCBC 703   6 auto gb = group.to_bytes(); 703   6 auto gb = group.to_bytes();
HITCBC 704   6 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16); 704   6 std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
HITCBC 705   6 value_.ipv6mr_interface = if_index; 705   6 value_.ipv6mr_interface = if_index;
HITCBC 706   6 } 706   6 }
707   707  
708   /// Return the protocol level for `setsockopt`/`getsockopt`. 708   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 709   8 static constexpr int level() noexcept 709   8 static constexpr int level() noexcept
710   { 710   {
HITCBC 711   8 return IPPROTO_IPV6; 711   8 return IPPROTO_IPV6;
712   } 712   }
713   713  
714   /// Return the option name for `setsockopt`/`getsockopt`. 714   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 715   8 static constexpr int name() noexcept 715   8 static constexpr int name() noexcept
716   { 716   {
HITCBC 717   8 return IPV6_LEAVE_GROUP; 717   8 return IPV6_LEAVE_GROUP;
718   } 718   }
719   719  
720   /// Return a pointer to the underlying storage. 720   /// Return a pointer to the underlying storage.
HITCBC 721   6 void* data() noexcept 721   6 void* data() noexcept
722   { 722   {
HITCBC 723   6 return &value_; 723   6 return &value_;
724   } 724   }
725   725  
726   /// Return a pointer to the underlying storage. 726   /// Return a pointer to the underlying storage.
HITCBC 727   2 void const* data() const noexcept 727   2 void const* data() const noexcept
728   { 728   {
HITCBC 729   2 return &value_; 729   2 return &value_;
730   } 730   }
731   731  
732   /// Return the size of the underlying storage. 732   /// Return the size of the underlying storage.
HITCBC 733   12 std::size_t size() const noexcept 733   12 std::size_t size() const noexcept
734   { 734   {
HITCBC 735   12 return sizeof(value_); 735   12 return sizeof(value_);
736   } 736   }
737   737  
738   /// No-op resize. 738   /// No-op resize.
739   void resize(std::size_t) noexcept {} 739   void resize(std::size_t) noexcept {}
740   }; 740   };
741   741  
742   /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF). 742   /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
743   743  
744   Unlike the integer-based `multicast_interface_v6`, this option 744   Unlike the integer-based `multicast_interface_v6`, this option
745   takes an `ipv4_address` identifying the local interface. 745   takes an `ipv4_address` identifying the local interface.
746   746  
747   @par Example 747   @par Example
748   @par !example multicast_interface_v4 748   @par !example multicast_interface_v4
749   */ 749   */
750   class multicast_interface_v4 750   class multicast_interface_v4
751   { 751   {
752   struct in_addr value_{}; 752   struct in_addr value_{};
753   753  
754   public: 754   public:
755   /// Construct with default values (INADDR_ANY). 755   /// Construct with default values (INADDR_ANY).
HITCBC 756   2 multicast_interface_v4() = default; 756   2 multicast_interface_v4() = default;
757   757  
758   /** Construct with an interface address. 758   /** Construct with an interface address.
759   759  
760   @param iface The local interface address. 760   @param iface The local interface address.
761   */ 761   */
HITCBC 762   4 explicit multicast_interface_v4(ipv4_address iface) noexcept 762   4 explicit multicast_interface_v4(ipv4_address iface) noexcept
HITCBC 763   4 { 763   4 {
HITCBC 764   4 auto b = iface.to_bytes(); 764   4 auto b = iface.to_bytes();
HITCBC 765   4 std::memcpy(&value_, b.data(), 4); 765   4 std::memcpy(&value_, b.data(), 4);
HITCBC 766   4 } 766   4 }
767   767  
768   /// Return the protocol level for `setsockopt`/`getsockopt`. 768   /// Return the protocol level for `setsockopt`/`getsockopt`.
HITCBC 769   6 static constexpr int level() noexcept 769   6 static constexpr int level() noexcept
770   { 770   {
HITCBC 771   6 return IPPROTO_IP; 771   6 return IPPROTO_IP;
772   } 772   }
773   773  
774   /// Return the option name for `setsockopt`/`getsockopt`. 774   /// Return the option name for `setsockopt`/`getsockopt`.
HITCBC 775   6 static constexpr int name() noexcept 775   6 static constexpr int name() noexcept
776   { 776   {
HITCBC 777   6 return IP_MULTICAST_IF; 777   6 return IP_MULTICAST_IF;
778   } 778   }
779   779  
780   /// Return a pointer to the underlying storage. 780   /// Return a pointer to the underlying storage.
HITCBC 781   4 void* data() noexcept 781   4 void* data() noexcept
782   { 782   {
HITCBC 783   4 return &value_; 783   4 return &value_;
784   } 784   }
785   785  
786   /// Return a pointer to the underlying storage. 786   /// Return a pointer to the underlying storage.
HITCBC 787   2 void const* data() const noexcept 787   2 void const* data() const noexcept
788   { 788   {
HITCBC 789   2 return &value_; 789   2 return &value_;
790   } 790   }
791   791  
792   /// Return the size of the underlying storage. 792   /// Return the size of the underlying storage.
HITCBC 793   8 std::size_t size() const noexcept 793   8 std::size_t size() const noexcept
794   { 794   {
HITCBC 795   8 return sizeof(value_); 795   8 return sizeof(value_);
796   } 796   }
797   797  
798   /// No-op resize. 798   /// No-op resize.
799   void resize(std::size_t) noexcept {} 799   void resize(std::size_t) noexcept {}
800   }; 800   };
801   801  
802   } // namespace boost::corosio::native_socket_option 802   } // namespace boost::corosio::native_socket_option
803   803  
804   #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP 804   #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP