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

Generated by: LCOV version 2.3