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-09-08 16:19:01 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          24 :     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              10 :     bool value() const noexcept
      98                 :     {
      99              10 :         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             773 :     static constexpr int level() noexcept
     116                 :     {
     117             773 :         return Level;
     118                 :     }
     119                 : 
     120                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     121             773 :     static constexpr int name() noexcept
     122                 :     {
     123             773 :         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               8 :     void resize(std::size_t s) noexcept
     151                 :     {
     152               8 :         if (s == sizeof(char))
     153 MIS           0 :             value_ = *reinterpret_cast<unsigned char*>(&value_) ? 1 : 0;
     154 HIT           8 :     }
     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               8 :     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               6 :     int value() const noexcept
     197                 :     {
     198               6 :         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               6 :     void resize(std::size_t s) noexcept
     236                 :     {
     237               6 :         if (s == sizeof(char))
     238 MIS           0 :             value_ =
     239               0 :                 static_cast<int>(*reinterpret_cast<unsigned char*>(&value_));
     240 HIT           6 :     }
     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 { return value_ != 0; }
     270                 :     explicit operator bool() const noexcept { return value_ != 0; }
     271                 :     bool operator!() const noexcept { return value_ == 0; }
     272                 : 
     273              22 :     static constexpr int level() noexcept { return Level; }
     274              22 :     static constexpr int name() noexcept { return Name; }
     275                 : 
     276               2 :     void* data() noexcept { return &value_; }
     277               2 :     void const* data() const noexcept { return &value_; }
     278               4 :     std::size_t size() const noexcept { return sizeof(value_); }
     279                 : 
     280               2 :     void resize(std::size_t) noexcept {}
     281                 : };
     282                 : 
     283                 : /** An integer socket option with single-byte storage.
     284                 : 
     285                 :     Same rationale as `byte_boolean`: BSD-derived kernels require
     286                 :     `IP_MULTICAST_TTL` to be set with a one-byte value. Linux accepts
     287                 :     one byte too, so single-byte storage is portable. Values are
     288                 :     truncated to the 0–255 range.
     289                 : 
     290                 :     @tparam Level The protocol level.
     291                 :     @tparam Name The option name.
     292                 : */
     293                 : template<int Level, int Name>
     294                 : class byte_integer
     295                 : {
     296                 :     unsigned char value_ = 0;
     297                 : 
     298                 : public:
     299                 :     byte_integer() = default;
     300                 : 
     301               2 :     explicit byte_integer(int v) noexcept
     302               2 :         : value_(static_cast<unsigned char>(v))
     303               2 :     {}
     304                 : 
     305                 :     byte_integer& operator=(int v) noexcept
     306                 :     {
     307                 :         value_ = static_cast<unsigned char>(v);
     308                 :         return *this;
     309                 :     }
     310                 : 
     311               2 :     int value() const noexcept { return value_; }
     312                 : 
     313              12 :     static constexpr int level() noexcept { return Level; }
     314              12 :     static constexpr int name() noexcept { return Name; }
     315                 : 
     316               2 :     void* data() noexcept { return &value_; }
     317               2 :     void const* data() const noexcept { return &value_; }
     318               4 :     std::size_t size() const noexcept { return sizeof(value_); }
     319                 : 
     320               2 :     void resize(std::size_t) noexcept {}
     321                 : };
     322                 : 
     323                 : /** The SO_LINGER socket option (native variant).
     324                 : 
     325                 :     Controls behavior when closing a socket with unsent data.
     326                 :     When enabled, `close()` blocks until pending data is sent
     327                 :     or the timeout expires.
     328                 : 
     329                 :     This variant stores the platform's `struct linger` directly,
     330                 :     avoiding the opaque-storage indirection of the type-erased
     331                 :     version.
     332                 : 
     333                 :     @par Example
     334                 :     @par !example linger
     335                 : */
     336                 : class linger
     337                 : {
     338                 :     struct ::linger value_{};
     339                 : 
     340                 : public:
     341                 :     /// Construct with default values (disabled, zero timeout).
     342             215 :     linger() = default;
     343                 : 
     344                 :     /** Construct with explicit values.
     345                 : 
     346                 :         @param enabled `true` to enable linger behavior on close.
     347                 :         @param timeout The linger timeout in seconds.
     348                 :     */
     349             203 :     linger(bool enabled, int timeout) noexcept
     350             203 :     {
     351             203 :         value_.l_onoff  = enabled ? 1 : 0;
     352             203 :         value_.l_linger = static_cast<decltype(value_.l_linger)>(timeout);
     353             203 :     }
     354                 : 
     355                 :     /// Return whether linger is enabled.
     356              22 :     bool enabled() const noexcept
     357                 :     {
     358              22 :         return value_.l_onoff != 0;
     359                 :     }
     360                 : 
     361                 :     /// Set whether linger is enabled.
     362               4 :     void enabled(bool v) noexcept
     363                 :     {
     364               4 :         value_.l_onoff = v ? 1 : 0;
     365               4 :     }
     366                 : 
     367                 :     /// Return the linger timeout in seconds.
     368              20 :     int timeout() const noexcept
     369                 :     {
     370              20 :         return static_cast<int>(value_.l_linger);
     371                 :     }
     372                 : 
     373                 :     /// Set the linger timeout in seconds.
     374               4 :     void timeout(int v) noexcept
     375                 :     {
     376               4 :         value_.l_linger = static_cast<decltype(value_.l_linger)>(v);
     377               4 :     }
     378                 : 
     379                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     380             217 :     static constexpr int level() noexcept
     381                 :     {
     382             217 :         return SOL_SOCKET;
     383                 :     }
     384                 : 
     385                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     386             217 :     static constexpr int name() noexcept
     387                 :     {
     388             217 :         return SO_LINGER;
     389                 :     }
     390                 : 
     391                 :     /// Return a pointer to the underlying storage.
     392             241 :     void* data() noexcept
     393                 :     {
     394             241 :         return &value_;
     395                 :     }
     396                 : 
     397                 :     /// Return a pointer to the underlying storage.
     398               2 :     void const* data() const noexcept
     399                 :     {
     400               2 :         return &value_;
     401                 :     }
     402                 : 
     403                 :     /// Return the size of the underlying storage.
     404             456 :     std::size_t size() const noexcept
     405                 :     {
     406             456 :         return sizeof(value_);
     407                 :     }
     408                 : 
     409                 :     /** Normalize after `getsockopt`.
     410                 : 
     411                 :         No-op — `struct linger` is always returned at full size.
     412                 : 
     413                 :         @param s The number of bytes actually written by `getsockopt`.
     414                 :     */
     415                 :     void resize(std::size_t) noexcept {}
     416                 : };
     417                 : 
     418                 : /// Disable Nagle's algorithm (TCP_NODELAY).
     419                 : using no_delay = boolean<IPPROTO_TCP, TCP_NODELAY>;
     420                 : 
     421                 : /// Enable periodic keepalive probes (SO_KEEPALIVE).
     422                 : using keep_alive = boolean<SOL_SOCKET, SO_KEEPALIVE>;
     423                 : 
     424                 : /// Restrict an IPv6 socket to IPv6 only (IPV6_V6ONLY).
     425                 : using v6_only = boolean<IPPROTO_IPV6, IPV6_V6ONLY>;
     426                 : 
     427                 : /// Allow local address reuse (SO_REUSEADDR).
     428                 : using reuse_address = boolean<SOL_SOCKET, SO_REUSEADDR>;
     429                 : 
     430                 : /// Allow sending to broadcast addresses (SO_BROADCAST).
     431                 : using broadcast = boolean<SOL_SOCKET, SO_BROADCAST>;
     432                 : 
     433                 : /// Set the receive buffer size (SO_RCVBUF).
     434                 : using receive_buffer_size = integer<SOL_SOCKET, SO_RCVBUF>;
     435                 : 
     436                 : /// Set the send buffer size (SO_SNDBUF).
     437                 : using send_buffer_size = integer<SOL_SOCKET, SO_SNDBUF>;
     438                 : 
     439                 : #ifdef SO_REUSEPORT
     440                 : /// Allow multiple sockets to bind to the same port (SO_REUSEPORT).
     441                 : using reuse_port = boolean<SOL_SOCKET, SO_REUSEPORT>;
     442                 : #endif
     443                 : 
     444                 : /// Enable loopback of outgoing multicast on IPv4 (IP_MULTICAST_LOOP).
     445                 : using multicast_loop_v4 = byte_boolean<IPPROTO_IP, IP_MULTICAST_LOOP>;
     446                 : 
     447                 : /// Enable loopback of outgoing multicast on IPv6 (IPV6_MULTICAST_LOOP).
     448                 : using multicast_loop_v6 = boolean<IPPROTO_IPV6, IPV6_MULTICAST_LOOP>;
     449                 : 
     450                 : /// Set the multicast TTL for IPv4 (IP_MULTICAST_TTL).
     451                 : using multicast_hops_v4 = byte_integer<IPPROTO_IP, IP_MULTICAST_TTL>;
     452                 : 
     453                 : /// Set the multicast hop limit for IPv6 (IPV6_MULTICAST_HOPS).
     454                 : using multicast_hops_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_HOPS>;
     455                 : 
     456                 : /// Set the outgoing interface for IPv6 multicast (IPV6_MULTICAST_IF).
     457                 : using multicast_interface_v6 = integer<IPPROTO_IPV6, IPV6_MULTICAST_IF>;
     458                 : 
     459                 : /** Join an IPv4 multicast group (IP_ADD_MEMBERSHIP).
     460                 : 
     461                 :     @par Example
     462                 :     @par !example join_group_v4
     463                 : */
     464                 : class join_group_v4
     465                 : {
     466                 :     struct ip_mreq value_{};
     467                 : 
     468                 : public:
     469                 :     /// Construct with default values.
     470               4 :     join_group_v4() = default;
     471                 : 
     472                 :     /** Construct with a group and optional interface address.
     473                 : 
     474                 :         @param group The multicast group address to join.
     475                 :         @param iface The local interface to use (default: any).
     476                 :     */
     477               6 :     join_group_v4(
     478                 :         ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
     479               6 :     {
     480               6 :         auto gb = group.to_bytes();
     481               6 :         auto ib = iface.to_bytes();
     482               6 :         std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
     483               6 :         std::memcpy(&value_.imr_interface, ib.data(), 4);
     484               6 :     }
     485                 : 
     486                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     487               8 :     static constexpr int level() noexcept
     488                 :     {
     489               8 :         return IPPROTO_IP;
     490                 :     }
     491                 : 
     492                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     493               8 :     static constexpr int name() noexcept
     494                 :     {
     495               8 :         return IP_ADD_MEMBERSHIP;
     496                 :     }
     497                 : 
     498                 :     /// Return a pointer to the underlying storage.
     499               6 :     void* data() noexcept
     500                 :     {
     501               6 :         return &value_;
     502                 :     }
     503                 : 
     504                 :     /// Return a pointer to the underlying storage.
     505               2 :     void const* data() const noexcept
     506                 :     {
     507               2 :         return &value_;
     508                 :     }
     509                 : 
     510                 :     /// Return the size of the underlying storage.
     511              12 :     std::size_t size() const noexcept
     512                 :     {
     513              12 :         return sizeof(value_);
     514                 :     }
     515                 : 
     516                 :     /// No-op resize.
     517                 :     void resize(std::size_t) noexcept {}
     518                 : };
     519                 : 
     520                 : /** Leave an IPv4 multicast group (IP_DROP_MEMBERSHIP).
     521                 : 
     522                 :     @par Example
     523                 :     @par !example leave_group_v4
     524                 : */
     525                 : class leave_group_v4
     526                 : {
     527                 :     struct ip_mreq value_{};
     528                 : 
     529                 : public:
     530                 :     /// Construct with default values.
     531               2 :     leave_group_v4() = default;
     532                 : 
     533                 :     /** Construct with a group and optional interface address.
     534                 : 
     535                 :         @param group The multicast group address to leave.
     536                 :         @param iface The local interface (default: any).
     537                 :     */
     538               4 :     leave_group_v4(
     539                 :         ipv4_address group, ipv4_address iface = ipv4_address()) noexcept
     540               4 :     {
     541               4 :         auto gb = group.to_bytes();
     542               4 :         auto ib = iface.to_bytes();
     543               4 :         std::memcpy(&value_.imr_multiaddr, gb.data(), 4);
     544               4 :         std::memcpy(&value_.imr_interface, ib.data(), 4);
     545               4 :     }
     546                 : 
     547                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     548               6 :     static constexpr int level() noexcept
     549                 :     {
     550               6 :         return IPPROTO_IP;
     551                 :     }
     552                 : 
     553                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     554               6 :     static constexpr int name() noexcept
     555                 :     {
     556               6 :         return IP_DROP_MEMBERSHIP;
     557                 :     }
     558                 : 
     559                 :     /// Return a pointer to the underlying storage.
     560               4 :     void* data() noexcept
     561                 :     {
     562               4 :         return &value_;
     563                 :     }
     564                 : 
     565                 :     /// Return a pointer to the underlying storage.
     566               2 :     void const* data() const noexcept
     567                 :     {
     568               2 :         return &value_;
     569                 :     }
     570                 : 
     571                 :     /// Return the size of the underlying storage.
     572               8 :     std::size_t size() const noexcept
     573                 :     {
     574               8 :         return sizeof(value_);
     575                 :     }
     576                 : 
     577                 :     /// No-op resize.
     578                 :     void resize(std::size_t) noexcept {}
     579                 : };
     580                 : 
     581                 : /** Join an IPv6 multicast group (IPV6_JOIN_GROUP).
     582                 : 
     583                 :     @par Example
     584                 :     @par !example join_group_v6
     585                 : */
     586                 : class join_group_v6
     587                 : {
     588                 :     struct ipv6_mreq value_{};
     589                 : 
     590                 : public:
     591                 :     /// Construct with default values.
     592               4 :     join_group_v6() = default;
     593                 : 
     594                 :     /** Construct with a group and optional interface index.
     595                 : 
     596                 :         @param group The multicast group address to join.
     597                 :         @param if_index The interface index (0 = kernel chooses).
     598                 :     */
     599               6 :     join_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
     600               6 :     {
     601               6 :         auto gb = group.to_bytes();
     602               6 :         std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
     603               6 :         value_.ipv6mr_interface = if_index;
     604               6 :     }
     605                 : 
     606                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     607               8 :     static constexpr int level() noexcept
     608                 :     {
     609               8 :         return IPPROTO_IPV6;
     610                 :     }
     611                 : 
     612                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     613               8 :     static constexpr int name() noexcept
     614                 :     {
     615               8 :         return IPV6_JOIN_GROUP;
     616                 :     }
     617                 : 
     618                 :     /// Return a pointer to the underlying storage.
     619               6 :     void* data() noexcept
     620                 :     {
     621               6 :         return &value_;
     622                 :     }
     623                 : 
     624                 :     /// Return a pointer to the underlying storage.
     625               2 :     void const* data() const noexcept
     626                 :     {
     627               2 :         return &value_;
     628                 :     }
     629                 : 
     630                 :     /// Return the size of the underlying storage.
     631              12 :     std::size_t size() const noexcept
     632                 :     {
     633              12 :         return sizeof(value_);
     634                 :     }
     635                 : 
     636                 :     /// No-op resize.
     637                 :     void resize(std::size_t) noexcept {}
     638                 : };
     639                 : 
     640                 : /** Leave an IPv6 multicast group (IPV6_LEAVE_GROUP).
     641                 : 
     642                 :     @par Example
     643                 :     @par !example leave_group_v6
     644                 : */
     645                 : class leave_group_v6
     646                 : {
     647                 :     struct ipv6_mreq value_{};
     648                 : 
     649                 : public:
     650                 :     /// Construct with default values.
     651               4 :     leave_group_v6() = default;
     652                 : 
     653                 :     /** Construct with a group and optional interface index.
     654                 : 
     655                 :         @param group The multicast group address to leave.
     656                 :         @param if_index The interface index (0 = kernel chooses).
     657                 :     */
     658               6 :     leave_group_v6(ipv6_address group, unsigned int if_index = 0) noexcept
     659               6 :     {
     660               6 :         auto gb = group.to_bytes();
     661               6 :         std::memcpy(&value_.ipv6mr_multiaddr, gb.data(), 16);
     662               6 :         value_.ipv6mr_interface = if_index;
     663               6 :     }
     664                 : 
     665                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     666               8 :     static constexpr int level() noexcept
     667                 :     {
     668               8 :         return IPPROTO_IPV6;
     669                 :     }
     670                 : 
     671                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     672               8 :     static constexpr int name() noexcept
     673                 :     {
     674               8 :         return IPV6_LEAVE_GROUP;
     675                 :     }
     676                 : 
     677                 :     /// Return a pointer to the underlying storage.
     678               6 :     void* data() noexcept
     679                 :     {
     680               6 :         return &value_;
     681                 :     }
     682                 : 
     683                 :     /// Return a pointer to the underlying storage.
     684               2 :     void const* data() const noexcept
     685                 :     {
     686               2 :         return &value_;
     687                 :     }
     688                 : 
     689                 :     /// Return the size of the underlying storage.
     690              12 :     std::size_t size() const noexcept
     691                 :     {
     692              12 :         return sizeof(value_);
     693                 :     }
     694                 : 
     695                 :     /// No-op resize.
     696                 :     void resize(std::size_t) noexcept {}
     697                 : };
     698                 : 
     699                 : /** Set the outgoing interface for IPv4 multicast (IP_MULTICAST_IF).
     700                 : 
     701                 :     Unlike the integer-based `multicast_interface_v6`, this option
     702                 :     takes an `ipv4_address` identifying the local interface.
     703                 : 
     704                 :     @par Example
     705                 :     @par !example multicast_interface_v4
     706                 : */
     707                 : class multicast_interface_v4
     708                 : {
     709                 :     struct in_addr value_{};
     710                 : 
     711                 : public:
     712                 :     /// Construct with default values (INADDR_ANY).
     713               2 :     multicast_interface_v4() = default;
     714                 : 
     715                 :     /** Construct with an interface address.
     716                 : 
     717                 :         @param iface The local interface address.
     718                 :     */
     719               4 :     explicit multicast_interface_v4(ipv4_address iface) noexcept
     720               4 :     {
     721               4 :         auto b = iface.to_bytes();
     722               4 :         std::memcpy(&value_, b.data(), 4);
     723               4 :     }
     724                 : 
     725                 :     /// Return the protocol level for `setsockopt`/`getsockopt`.
     726               6 :     static constexpr int level() noexcept
     727                 :     {
     728               6 :         return IPPROTO_IP;
     729                 :     }
     730                 : 
     731                 :     /// Return the option name for `setsockopt`/`getsockopt`.
     732               6 :     static constexpr int name() noexcept
     733                 :     {
     734               6 :         return IP_MULTICAST_IF;
     735                 :     }
     736                 : 
     737                 :     /// Return a pointer to the underlying storage.
     738               4 :     void* data() noexcept
     739                 :     {
     740               4 :         return &value_;
     741                 :     }
     742                 : 
     743                 :     /// Return a pointer to the underlying storage.
     744               2 :     void const* data() const noexcept
     745                 :     {
     746               2 :         return &value_;
     747                 :     }
     748                 : 
     749                 :     /// Return the size of the underlying storage.
     750               8 :     std::size_t size() const noexcept
     751                 :     {
     752               8 :         return sizeof(value_);
     753                 :     }
     754                 : 
     755                 :     /// No-op resize.
     756                 :     void resize(std::size_t) noexcept {}
     757                 : };
     758                 : 
     759                 : } // namespace boost::corosio::native_socket_option
     760                 : 
     761                 : #endif // BOOST_COROSIO_NATIVE_NATIVE_SOCKET_OPTION_HPP
        

Generated by: LCOV version 2.3