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