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

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
       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_ENDPOINT_HPP
      12                 : #define BOOST_COROSIO_ENDPOINT_HPP
      13                 : 
      14                 : #include <boost/corosio/detail/config.hpp>
      15                 : #include <boost/corosio/detail/except.hpp>
      16                 : #include <boost/corosio/ipv4_address.hpp>
      17                 : #include <boost/corosio/ipv6_address.hpp>
      18                 : 
      19                 : #include <boost/capy/io_result.hpp>
      20                 : 
      21                 : #include <compare>
      22                 : #include <cstdint>
      23                 : #include <string_view>
      24                 : #include <system_error>
      25                 : 
      26                 : namespace boost::corosio {
      27                 : 
      28                 : /** An IP endpoint (address + port) supporting both IPv4 and IPv6.
      29                 : 
      30                 :     This class represents an endpoint for IP communication,
      31                 :     consisting of either an IPv4 or IPv6 address and a port number.
      32                 :     Endpoints are used to specify connection targets and bind addresses.
      33                 : 
      34                 :     The endpoint holds both address types as separate members (not a union),
      35                 :     with a discriminator to track which address type is active.
      36                 : 
      37                 :     @par Thread Safety
      38                 :     Distinct objects: Safe.@n
      39                 :     Shared objects: Safe.
      40                 : 
      41                 :     @par Example
      42                 :     @par !example endpoint
      43                 : */
      44                 : class endpoint
      45                 : {
      46                 :     ipv4_address v4_address_;
      47                 :     ipv6_address v6_address_;
      48                 :     std::uint16_t port_ = 0;
      49                 :     bool is_v4_         = true;
      50                 : 
      51                 : public:
      52                 :     /** Default constructor.
      53                 : 
      54                 :         Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0.
      55                 :     */
      56 HIT      150283 :     endpoint() noexcept
      57          150283 :         : v4_address_(ipv4_address::any())
      58          150283 :         , v6_address_{}
      59          150283 :         , port_(0)
      60          150283 :         , is_v4_(true)
      61                 :     {
      62          150283 :     }
      63                 : 
      64                 :     /** Construct from IPv4 address and port.
      65                 : 
      66                 :         @param addr The IPv4 address.
      67                 :         @param p The port number in host byte order.
      68                 :     */
      69           15176 :     endpoint(ipv4_address addr, std::uint16_t p) noexcept
      70           15176 :         : v4_address_(addr)
      71           15176 :         , v6_address_{}
      72           15176 :         , port_(p)
      73           15176 :         , is_v4_(true)
      74                 :     {
      75           15176 :     }
      76                 : 
      77                 :     /** Construct from IPv6 address and port.
      78                 : 
      79                 :         @param addr The IPv6 address.
      80                 :         @param p The port number in host byte order.
      81                 :     */
      82             154 :     endpoint(ipv6_address addr, std::uint16_t p) noexcept
      83             154 :         : v4_address_(ipv4_address::any())
      84             154 :         , v6_address_(addr)
      85             154 :         , port_(p)
      86             154 :         , is_v4_(false)
      87                 :     {
      88             154 :     }
      89                 : 
      90                 :     /** Construct from port only.
      91                 : 
      92                 :         Uses the IPv4 any address (0.0.0.0), which binds to all
      93                 :         available network interfaces.
      94                 : 
      95                 :         @param p The port number in host byte order.
      96                 :     */
      97              22 :     explicit endpoint(std::uint16_t p) noexcept
      98              22 :         : v4_address_(ipv4_address::any())
      99              22 :         , v6_address_{}
     100              22 :         , port_(p)
     101              22 :         , is_v4_(true)
     102                 :     {
     103              22 :     }
     104                 : 
     105                 :     /** Construct from an endpoint's address with a different port.
     106                 : 
     107                 :         Creates a new endpoint using the address from an existing
     108                 :         endpoint but with a different port number.
     109                 : 
     110                 :         @param ep The endpoint whose address to use.
     111                 :         @param p The port number in host byte order.
     112                 :     */
     113               2 :     endpoint(endpoint const& ep, std::uint16_t p) noexcept
     114               2 :         : v4_address_(ep.v4_address_)
     115               2 :         , v6_address_(ep.v6_address_)
     116               2 :         , port_(p)
     117               2 :         , is_v4_(ep.is_v4_)
     118                 :     {
     119               2 :     }
     120                 : 
     121                 :     /** Construct from a string.
     122                 : 
     123                 :         Parses an endpoint string in one of the following formats:
     124                 :         @li IPv4 without port: `192.168.1.1`
     125                 :         @li IPv4 with port: `192.168.1.1:8080`
     126                 :         @li IPv6 without port: `::1` or `2001:db8::1`
     127                 :         @li IPv6 with port (bracketed): `[::1]:8080`
     128                 : 
     129                 :         @param s The string to parse.
     130                 : 
     131                 :         @throws std::system_error on parse failure.
     132                 : 
     133                 :         @see make_endpoint for the non-throwing form.
     134                 :     */
     135                 :     explicit endpoint(std::string_view s);
     136                 : 
     137                 :     /** Check if this endpoint uses an IPv4 address.
     138                 : 
     139                 :         @return `true` if the endpoint uses IPv4, `false` if IPv6.
     140                 :     */
     141           10357 :     bool is_v4() const noexcept
     142                 :     {
     143           10357 :         return is_v4_;
     144                 :     }
     145                 : 
     146                 :     /** Check if this endpoint uses an IPv6 address.
     147                 : 
     148                 :         @return `true` if the endpoint uses IPv6, `false` if IPv4.
     149                 :     */
     150             255 :     bool is_v6() const noexcept
     151                 :     {
     152             255 :         return !is_v4_;
     153                 :     }
     154                 : 
     155                 :     /** Get the IPv4 address.
     156                 : 
     157                 :         @return The IPv4 address. The value is valid even if
     158                 :         the endpoint is using IPv6 (it will be the default any address).
     159                 :     */
     160            5446 :     ipv4_address v4_address() const noexcept
     161                 :     {
     162            5446 :         return v4_address_;
     163                 :     }
     164                 : 
     165                 :     /** Get the IPv6 address.
     166                 : 
     167                 :         @return The IPv6 address. The value is valid even if
     168                 :         the endpoint is using IPv4 (it will be the default any address).
     169                 :     */
     170              64 :     ipv6_address v6_address() const noexcept
     171                 :     {
     172              64 :         return v6_address_;
     173                 :     }
     174                 : 
     175                 :     /** Get the port number.
     176                 : 
     177                 :         @return The port number in host byte order.
     178                 :     */
     179            6101 :     std::uint16_t port() const noexcept
     180                 :     {
     181            6101 :         return port_;
     182                 :     }
     183                 : 
     184                 :     /** Compare endpoints for equality.
     185                 : 
     186                 :         Two endpoints are equal if they have the same address type,
     187                 :         the same address value, and the same port.
     188                 : 
     189                 :         @return `true` if both endpoints are equal.
     190                 :     */
     191              99 :     friend bool operator==(endpoint const& a, endpoint const& b) noexcept
     192                 :     {
     193              99 :         if (a.is_v4_ != b.is_v4_)
     194               1 :             return false;
     195              98 :         if (a.port_ != b.port_)
     196               3 :             return false;
     197              95 :         if (a.is_v4_)
     198              93 :             return a.v4_address_ == b.v4_address_;
     199                 :         else
     200               2 :             return a.v6_address_ == b.v6_address_;
     201                 :     }
     202                 : 
     203                 :     /** Order two endpoints.
     204                 : 
     205                 :         Establishes a strict total ordering consistent with
     206                 :         @ref operator==: equal endpoints compare equivalent.
     207                 :         Endpoints are ordered first by address family (IPv4
     208                 :         before IPv6), then by address value, then by port. This
     209                 :         makes `endpoint` usable as a key in ordered containers
     210                 :         such as `std::map` and `std::set`.
     211                 : 
     212                 :         @return The relative order of @p a and @p b.
     213                 :     */
     214                 :     friend std::strong_ordering
     215              25 :     operator<=>(endpoint const& a, endpoint const& b) noexcept
     216                 :     {
     217              25 :         if (a.is_v4_ != b.is_v4_)
     218               9 :             return a.is_v4_ ? std::strong_ordering::less
     219               9 :                             : std::strong_ordering::greater;
     220              16 :         if (a.is_v4_)
     221                 :         {
     222              13 :             if (auto c = a.v4_address_.to_uint() <=> b.v4_address_.to_uint();
     223              13 :                 c != 0)
     224               2 :                 return c;
     225                 :         }
     226                 :         else
     227                 :         {
     228               3 :             if (auto c = a.v6_address_.to_bytes() <=> b.v6_address_.to_bytes();
     229               3 :                 c != 0)
     230               1 :                 return c;
     231                 :         }
     232              13 :         return a.port_ <=> b.port_;
     233                 :     }
     234                 : };
     235                 : 
     236                 : /** Endpoint format detection result.
     237                 : 
     238                 :     Used internally by make_endpoint to determine
     239                 :     the format of an endpoint string.
     240                 : */
     241                 : enum class endpoint_format
     242                 : {
     243                 :     ipv4_no_port,   ///< "192.168.1.1"
     244                 :     ipv4_with_port, ///< "192.168.1.1:8080"
     245                 :     ipv6_no_port,   ///< "::1" or "1:2:3:4:5:6:7:8"
     246                 :     ipv6_bracketed  ///< "[::1]" or "[::1]:8080"
     247                 : };
     248                 : 
     249                 : /** Detect the format of an endpoint string.
     250                 : 
     251                 :     This helper function determines the endpoint format
     252                 :     based on simple rules:
     253                 :     1. Starts with `[` -> `ipv6_bracketed`
     254                 :     2. Else count `:` characters:
     255                 :        - 0 colons -> `ipv4_no_port`
     256                 :        - 1 colon -> `ipv4_with_port`
     257                 :        - 2+ colons -> `ipv6_no_port`
     258                 : 
     259                 :     @param s The string to analyze.
     260                 :     @return The detected endpoint format.
     261                 : */
     262                 : BOOST_COROSIO_DECL
     263                 : endpoint_format detect_endpoint_format(std::string_view s) noexcept;
     264                 : 
     265                 : /** Create an endpoint from a string.
     266                 : 
     267                 :     This function parses an endpoint string in one of
     268                 :     the following formats:
     269                 : 
     270                 :     @li IPv4 without port: `192.168.1.1`
     271                 :     @li IPv4 with port: `192.168.1.1:8080`
     272                 :     @li IPv6 without port: `::1` or `2001:db8::1`
     273                 :     @li IPv6 with port (bracketed): `[::1]:8080`
     274                 : 
     275                 :     @par Example
     276                 :     @par !example make_endpoint
     277                 : 
     278                 :     @param s The string to parse.
     279                 :     @return The error code, empty on success, and the parsed
     280                 :         endpoint — default-constructed on failure.
     281                 : */
     282                 : [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<endpoint>
     283                 : make_endpoint(std::string_view s) noexcept;
     284                 : 
     285              25 : inline endpoint::endpoint(std::string_view s)
     286                 : {
     287              25 :     auto [ec, ep] = make_endpoint(s);
     288              25 :     if (ec)
     289              16 :         detail::throw_system_error(ec);
     290               9 :     *this = ep;
     291               9 : }
     292                 : 
     293                 : } // namespace boost::corosio
     294                 : 
     295                 : #endif
        

Generated by: LCOV version 2.3