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