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

Generated by: LCOV version 2.3