100.00% Lines (32/32) 100.00% Functions (12/12)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/corosio 8   // Official repository: https://github.com/cppalliance/corosio
9   // 9   //
10   10  
11   #ifndef BOOST_COROSIO_ENDPOINT_HPP 11   #ifndef BOOST_COROSIO_ENDPOINT_HPP
12   #define BOOST_COROSIO_ENDPOINT_HPP 12   #define BOOST_COROSIO_ENDPOINT_HPP
13   13  
14   #include <boost/corosio/detail/config.hpp> 14   #include <boost/corosio/detail/config.hpp>
15   #include <boost/corosio/detail/except.hpp> 15   #include <boost/corosio/detail/except.hpp>
16   #include <boost/corosio/ip_address.hpp> 16   #include <boost/corosio/ip_address.hpp>
17   17  
18   #include <boost/capy/io_result.hpp> 18   #include <boost/capy/io_result.hpp>
19   19  
20   #include <compare> 20   #include <compare>
21   #include <cstdint> 21   #include <cstdint>
22   #include <string_view> 22   #include <string_view>
23   #include <system_error> 23   #include <system_error>
24   24  
25   namespace boost::corosio { 25   namespace boost::corosio {
26   26  
27 - /** An IP endpoint (address + port) supporting both IPv4 and IPv6. 27 + /** Pairs an IP address with a port for either IPv4 or IPv6.
28   28  
29   This class represents an endpoint for IP communication, 29   This class represents an endpoint for IP communication,
30   consisting of an IP address of either family and a port number. 30   consisting of an IP address of either family and a port number.
31 - Endpoints are used to specify connection targets and bind addresses. 31 + Use an endpoint to specify a connection target or bind address.
32   32  
33   @par Thread Safety 33   @par Thread Safety
34   Distinct objects: Safe.@n 34   Distinct objects: Safe.@n
35   Shared objects: Safe. 35   Shared objects: Safe.
36   36  
37   @par Example 37   @par Example
38   @par !example endpoint 38   @par !example endpoint
39   */ 39   */
40   class endpoint 40   class endpoint
41   { 41   {
42   ip_address addr_; 42   ip_address addr_;
43   std::uint16_t port_ = 0; 43   std::uint16_t port_ = 0;
44   44  
45   public: 45   public:
46 - /** Default constructor. 46 + /** Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0.
47 -  
48 - Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0.  
49   */ 47   */
HITCBC 50   137949 endpoint() noexcept = default; 48   93759 endpoint() noexcept = default;
51   49  
52   /** Construct from an IP address and port. 50   /** Construct from an IP address and port.
53   51  
54   `ipv4_address` and `ipv6_address` arguments convert 52   `ipv4_address` and `ipv6_address` arguments convert
55   implicitly, so both families construct directly: 53   implicitly, so both families construct directly:
56   `endpoint(ipv4_address::loopback(), 80)`. 54   `endpoint(ipv4_address::loopback(), 80)`.
57   55  
58   @param addr The IP address. 56   @param addr The IP address.
59   @param p The port number in host byte order. 57   @param p The port number in host byte order.
60   */ 58   */
HITCBC 61   14616 endpoint(ip_address addr, std::uint16_t p) noexcept : addr_(addr), port_(p) 59   10197 endpoint(ip_address addr, std::uint16_t p) noexcept : addr_(addr), port_(p)
62   { 60   {
HITCBC 63   14616 } 61   10197 }
64   62  
65   /** Construct from port only. 63   /** Construct from port only.
66   64  
67   Uses the IPv4 any address (0.0.0.0), which binds to all 65   Uses the IPv4 any address (0.0.0.0), which binds to all
68   available network interfaces. 66   available network interfaces.
69   67  
70   @param p The port number in host byte order. 68   @param p The port number in host byte order.
71   */ 69   */
HITCBC 72   22 explicit endpoint(std::uint16_t p) noexcept : port_(p) {} 70   22 explicit endpoint(std::uint16_t p) noexcept : port_(p) {}
73   71  
74   /** Construct from an endpoint's address with a different port. 72   /** Construct from an endpoint's address with a different port.
75   73  
76   Creates a new endpoint using the address from an existing 74   Creates a new endpoint using the address from an existing
77   endpoint but with a different port number. 75   endpoint but with a different port number.
78   76  
79   @param ep The endpoint whose address to use. 77   @param ep The endpoint whose address to use.
80   @param p The port number in host byte order. 78   @param p The port number in host byte order.
81   */ 79   */
HITCBC 82   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept 80   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept
HITCBC 83   2 : addr_(ep.addr_) 81   2 : addr_(ep.addr_)
HITCBC 84   2 , port_(p) 82   2 , port_(p)
85   { 83   {
HITCBC 86   2 } 84   2 }
87   85  
88   /** Construct from a string. 86   /** Construct from a string.
89   87  
90   Parses an endpoint string in one of the following formats: 88   Parses an endpoint string in one of the following formats:
91   @li IPv4 without port: `192.168.1.1` 89   @li IPv4 without port: `192.168.1.1`
92   @li IPv4 with port: `192.168.1.1:8080` 90   @li IPv4 with port: `192.168.1.1:8080`
93   @li IPv6 without port: `::1` or `2001:db8::1` 91   @li IPv6 without port: `::1` or `2001:db8::1`
94   @li IPv6 with port (bracketed): `[::1]:8080` 92   @li IPv6 with port (bracketed): `[::1]:8080`
95   93  
96   @param s The string to parse. 94   @param s The string to parse.
97   95  
98   @throws std::system_error on parse failure. 96   @throws std::system_error on parse failure.
99   97  
100   @see make_endpoint for the non-throwing form. 98   @see make_endpoint for the non-throwing form.
101   */ 99   */
102   explicit endpoint(std::string_view s); 100   explicit endpoint(std::string_view s);
103   101  
104   /** Check if this endpoint uses an IPv4 address. 102   /** Check if this endpoint uses an IPv4 address.
105   103  
106   @return `true` if the endpoint uses IPv4, `false` if IPv6. 104   @return `true` if the endpoint uses IPv4, `false` if IPv6.
107   */ 105   */
HITCBC 108   9846 bool is_v4() const noexcept 106   6900 bool is_v4() const noexcept
109   { 107   {
HITCBC 110   9846 return addr_.is_v4(); 108   6900 return addr_.is_v4();
111   } 109   }
112   110  
113   /** Check if this endpoint uses an IPv6 address. 111   /** Check if this endpoint uses an IPv6 address.
114   112  
115   @return `true` if the endpoint uses IPv6, `false` if IPv4. 113   @return `true` if the endpoint uses IPv6, `false` if IPv4.
116   */ 114   */
HITCBC 117   61 bool is_v6() const noexcept 115   61 bool is_v6() const noexcept
118   { 116   {
HITCBC 119   61 return addr_.is_v6(); 117   61 return addr_.is_v6();
120   } 118   }
121   119  
122   /** Return the IP address. 120   /** Return the IP address.
123   121  
124   @return The endpoint's address. 122   @return The endpoint's address.
125   */ 123   */
HITCBC 126   5486 ip_address address() const noexcept 124   4013 ip_address address() const noexcept
127   { 125   {
HITCBC 128   5486 return addr_; 126   4013 return addr_;
129   } 127   }
130   128  
131   /** Return the port number. 129   /** Return the port number.
132   130  
133   @return The port number in host byte order. 131   @return The port number in host byte order.
134   */ 132   */
HITCBC 135   5889 std::uint16_t port() const noexcept 133   4416 std::uint16_t port() const noexcept
136   { 134   {
HITCBC 137   5889 return port_; 135   4416 return port_;
138   } 136   }
139   137  
140   /** Compare endpoints for equality. 138   /** Compare endpoints for equality.
141   139  
142   Two endpoints are equal if they have the same address type, 140   Two endpoints are equal if they have the same address type,
143   the same address value, and the same port. 141   the same address value, and the same port.
144   142  
145   @return `true` if both endpoints are equal. 143   @return `true` if both endpoints are equal.
146   */ 144   */
HITCBC 147   102 friend bool operator==(endpoint const& a, endpoint const& b) noexcept 145   102 friend bool operator==(endpoint const& a, endpoint const& b) noexcept
148   { 146   {
HITCBC 149   102 return a.port_ == b.port_ && a.addr_ == b.addr_; 147   102 return a.port_ == b.port_ && a.addr_ == b.addr_;
150   } 148   }
151   149  
152   /** Order two endpoints. 150   /** Order two endpoints.
153   151  
154   Establishes a strict total ordering consistent with 152   Establishes a strict total ordering consistent with
155   @ref operator==: equal endpoints compare equivalent. 153   @ref operator==: equal endpoints compare equivalent.
156 - Endpoints are ordered first by address family (IPv4 154 + `operator<=>` orders endpoints first by address family
157 - before IPv6), then by address value, then by port. This 155 + (IPv4 before IPv6), then by address value, then by port. This
158   makes `endpoint` usable as a key in ordered containers 156   makes `endpoint` usable as a key in ordered containers
159   such as `std::map` and `std::set`. 157   such as `std::map` and `std::set`.
160   158  
161   @return The relative order of @p a and @p b. 159   @return The relative order of @p a and @p b.
162   */ 160   */
163   friend std::strong_ordering 161   friend std::strong_ordering
HITCBC 164   25 operator<=>(endpoint const& a, endpoint const& b) noexcept 162   25 operator<=>(endpoint const& a, endpoint const& b) noexcept
165   { 163   {
HITCBC 166   25 if (auto c = a.addr_ <=> b.addr_; c != 0) 164   25 if (auto c = a.addr_ <=> b.addr_; c != 0)
HITCBC 167   12 return c; 165   12 return c;
HITCBC 168   13 return a.port_ <=> b.port_; 166   13 return a.port_ <=> b.port_;
169   } 167   }
170   }; 168   };
171   169  
172 - /** Endpoint format detection result. 170 + /** Identifies which of the four supported endpoint string formats a string is in.
173   171  
174 - Used internally by make_endpoint to determine 172 + Used internally by `make_endpoint` to determine
175   the format of an endpoint string. 173   the format of an endpoint string.
176   */ 174   */
177   enum class endpoint_format 175   enum class endpoint_format
178   { 176   {
179   ipv4_no_port, ///< "192.168.1.1" 177   ipv4_no_port, ///< "192.168.1.1"
180   ipv4_with_port, ///< "192.168.1.1:8080" 178   ipv4_with_port, ///< "192.168.1.1:8080"
181   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8" 179   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8"
182   ipv6_bracketed ///< "[::1]" or "[::1]:8080" 180   ipv6_bracketed ///< "[::1]" or "[::1]:8080"
183   }; 181   };
184   182  
185   /** Detect the format of an endpoint string. 183   /** Detect the format of an endpoint string.
186   184  
187   This helper function determines the endpoint format 185   This helper function determines the endpoint format
188   based on simple rules: 186   based on simple rules:
189   1. Starts with `[` -> `ipv6_bracketed` 187   1. Starts with `[` -> `ipv6_bracketed`
190   2. Else count `:` characters: 188   2. Else count `:` characters:
191   - 0 colons -> `ipv4_no_port` 189   - 0 colons -> `ipv4_no_port`
192   - 1 colon -> `ipv4_with_port` 190   - 1 colon -> `ipv4_with_port`
193   - 2+ colons -> `ipv6_no_port` 191   - 2+ colons -> `ipv6_no_port`
194   192  
195   @param s The string to analyze. 193   @param s The string to analyze.
196   @return The detected endpoint format. 194   @return The detected endpoint format.
197   */ 195   */
198   BOOST_COROSIO_DECL 196   BOOST_COROSIO_DECL
199   endpoint_format detect_endpoint_format(std::string_view s) noexcept; 197   endpoint_format detect_endpoint_format(std::string_view s) noexcept;
200   198  
201   /** Create an endpoint from a string. 199   /** Create an endpoint from a string.
202   200  
203   This function parses an endpoint string in one of 201   This function parses an endpoint string in one of
204   the following formats: 202   the following formats:
205   203  
206   @li IPv4 without port: `192.168.1.1` 204   @li IPv4 without port: `192.168.1.1`
207   @li IPv4 with port: `192.168.1.1:8080` 205   @li IPv4 with port: `192.168.1.1:8080`
208   @li IPv6 without port: `::1` or `2001:db8::1` 206   @li IPv6 without port: `::1` or `2001:db8::1`
209   @li IPv6 with port (bracketed): `[::1]:8080` 207   @li IPv6 with port (bracketed): `[::1]:8080`
210   208  
211   @par Example 209   @par Example
212   @par !example make_endpoint 210   @par !example make_endpoint
213   211  
214   @param s The string to parse. 212   @param s The string to parse.
215   @return The error code, empty on success, and the parsed 213   @return The error code, empty on success, and the parsed
216   endpoint — default-constructed on failure. 214   endpoint — default-constructed on failure.
217   */ 215   */
218   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<endpoint> 216   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<endpoint>
219   make_endpoint(std::string_view s) noexcept; 217   make_endpoint(std::string_view s) noexcept;
220   218  
HITCBC 221   27 inline endpoint::endpoint(std::string_view s) 219   27 inline endpoint::endpoint(std::string_view s)
222   { 220   {
HITCBC 223   27 auto [ec, ep] = make_endpoint(s); 221   27 auto [ec, ep] = make_endpoint(s);
HITCBC 224   27 if (ec) 222   27 if (ec)
HITCBC 225   16 detail::throw_system_error(ec); 223   16 detail::throw_system_error(ec);
HITCBC 226   11 *this = ep; 224   11 *this = ep;
HITCBC 227   11 } 225   11 }
228   226  
229   } // namespace boost::corosio 227   } // namespace boost::corosio
230   228  
231   namespace std { 229   namespace std {
232   230  
233   /// Hash support for `boost::corosio::endpoint`. 231   /// Hash support for `boost::corosio::endpoint`.
234   template<> 232   template<>
235   struct hash<boost::corosio::endpoint> 233   struct hash<boost::corosio::endpoint>
236   { 234   {
237   /// Return the hash of `ep`. 235   /// Return the hash of `ep`.
HITCBC 238   12 std::size_t operator()(boost::corosio::endpoint const& ep) const noexcept 236   12 std::size_t operator()(boost::corosio::endpoint const& ep) const noexcept
239   { 237   {
HITCBC 240   12 std::size_t const h1 = hash<boost::corosio::ip_address>()(ep.address()); 238   12 std::size_t const h1 = hash<boost::corosio::ip_address>()(ep.address());
HITCBC 241   12 std::size_t const h2 = hash<std::uint16_t>()(ep.port()); 239   12 std::size_t const h2 = hash<std::uint16_t>()(ep.port());
HITCBC 242   12 return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); 240   12 return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
243   } 241   }
244   }; 242   };
245   243  
246   } // namespace std 244   } // namespace std
247   245  
248   #endif 246   #endif