LCOV - code coverage report
Current view: top level - corosio - socket_option.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 97 97
Test Date: 2026-09-28 20:06:38 Functions: 100.0 % 38 38

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

Generated by: LCOV version 2.3