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

Generated by: LCOV version 2.3