LCOV - code coverage report
Current view: top level - corosio/native - native_socket_option.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 177 177
Test Date: 2026-09-09 02:31:18 Functions: 100.0 % 129 129

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

Generated by: LCOV version 2.3