LCOV - code coverage report
Current view: top level - corosio/native - native_socket_option.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 98.2 % 165 162 3
Test Date: 2026-08-21 20:48:07 Functions: 100.0 % 129 129

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

Generated by: LCOV version 2.3