LCOV - code coverage report
Current view: top level - corosio - endpoint.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 98.5 % 65 64 1
Test Date: 2026-06-02 18:20:43 Functions: 100.0 % 13 13

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

Generated by: LCOV version 2.3