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