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   /** An IP endpoint (address + port) supporting both IPv4 and 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   Endpoints are used to specify connection targets and bind addresses.
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   /** Default constructor.
47   47  
48   Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0. 48   Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0.
49   */ 49   */
HITCBC 50   144483 endpoint() noexcept = default; 50   144921 endpoint() noexcept = default;
51   51  
52   /** Construct from an IP address and port. 52   /** Construct from an IP address and port.
53   53  
54   `ipv4_address` and `ipv6_address` arguments convert 54   `ipv4_address` and `ipv6_address` arguments convert
55   implicitly, so both families construct directly: 55   implicitly, so both families construct directly:
56   `endpoint(ipv4_address::loopback(), 80)`. 56   `endpoint(ipv4_address::loopback(), 80)`.
57   57  
58   @param addr The IP address. 58   @param addr The IP address.
59   @param p The port number in host byte order. 59   @param p The port number in host byte order.
60   */ 60   */
HITCBC 61   15269 endpoint(ip_address addr, std::uint16_t p) noexcept : addr_(addr), port_(p) 61   15313 endpoint(ip_address addr, std::uint16_t p) noexcept : addr_(addr), port_(p)
62   { 62   {
HITCBC 63   15269 } 63   15313 }
64   64  
65   /** Construct from port only. 65   /** Construct from port only.
66   66  
67   Uses the IPv4 any address (0.0.0.0), which binds to all 67   Uses the IPv4 any address (0.0.0.0), which binds to all
68   available network interfaces. 68   available network interfaces.
69   69  
70   @param p The port number in host byte order. 70   @param p The port number in host byte order.
71   */ 71   */
HITCBC 72   22 explicit endpoint(std::uint16_t p) noexcept : port_(p) {} 72   22 explicit endpoint(std::uint16_t p) noexcept : port_(p) {}
73   73  
74   /** Construct from an endpoint's address with a different port. 74   /** Construct from an endpoint's address with a different port.
75   75  
76   Creates a new endpoint using the address from an existing 76   Creates a new endpoint using the address from an existing
77   endpoint but with a different port number. 77   endpoint but with a different port number.
78   78  
79   @param ep The endpoint whose address to use. 79   @param ep The endpoint whose address to use.
80   @param p The port number in host byte order. 80   @param p The port number in host byte order.
81   */ 81   */
HITCBC 82   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept 82   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept
HITCBC 83   2 : addr_(ep.addr_) 83   2 : addr_(ep.addr_)
HITCBC 84   2 , port_(p) 84   2 , port_(p)
85   { 85   {
HITCBC 86   2 } 86   2 }
87   87  
88   /** Construct from a string. 88   /** Construct from a string.
89   89  
90   Parses an endpoint string in one of the following formats: 90   Parses an endpoint string in one of the following formats:
91   @li IPv4 without port: `192.168.1.1` 91   @li IPv4 without port: `192.168.1.1`
92   @li IPv4 with port: `192.168.1.1:8080` 92   @li IPv4 with port: `192.168.1.1:8080`
93   @li IPv6 without port: `::1` or `2001:db8::1` 93   @li IPv6 without port: `::1` or `2001:db8::1`
94   @li IPv6 with port (bracketed): `[::1]:8080` 94   @li IPv6 with port (bracketed): `[::1]:8080`
95   95  
96   @param s The string to parse. 96   @param s The string to parse.
97   97  
98   @throws std::system_error on parse failure. 98   @throws std::system_error on parse failure.
99   99  
100   @see make_endpoint for the non-throwing form. 100   @see make_endpoint for the non-throwing form.
101   */ 101   */
102   explicit endpoint(std::string_view s); 102   explicit endpoint(std::string_view s);
103   103  
104   /** Check if this endpoint uses an IPv4 address. 104   /** Check if this endpoint uses an IPv4 address.
105   105  
106   @return `true` if the endpoint uses IPv4, `false` if IPv6. 106   @return `true` if the endpoint uses IPv4, `false` if IPv6.
107   */ 107   */
HITCBC 108   10284 bool is_v4() const noexcept 108   10312 bool is_v4() const noexcept
109   { 109   {
HITCBC 110   10284 return addr_.is_v4(); 110   10312 return addr_.is_v4();
111   } 111   }
112   112  
113   /** Check if this endpoint uses an IPv6 address. 113   /** Check if this endpoint uses an IPv6 address.
114   114  
115   @return `true` if the endpoint uses IPv6, `false` if IPv4. 115   @return `true` if the endpoint uses IPv6, `false` if IPv4.
116   */ 116   */
HITCBC 117   61 bool is_v6() const noexcept 117   61 bool is_v6() const noexcept
118   { 118   {
HITCBC 119   61 return addr_.is_v6(); 119   61 return addr_.is_v6();
120   } 120   }
121   121  
122   /** Return the IP address. 122   /** Return the IP address.
123   123  
124   @return The endpoint's address. 124   @return The endpoint's address.
125   */ 125   */
HITCBC 126   5705 ip_address address() const noexcept 126   5719 ip_address address() const noexcept
127   { 127   {
HITCBC 128   5705 return addr_; 128   5719 return addr_;
129   } 129   }
130   130  
131   /** Return the port number. 131   /** Return the port number.
132   132  
133   @return The port number in host byte order. 133   @return The port number in host byte order.
134   */ 134   */
HITCBC 135   6108 std::uint16_t port() const noexcept 135   6122 std::uint16_t port() const noexcept
136   { 136   {
HITCBC 137   6108 return port_; 137   6122 return port_;
138   } 138   }
139   139  
140   /** Compare endpoints for equality. 140   /** Compare endpoints for equality.
141   141  
142   Two endpoints are equal if they have the same address type, 142   Two endpoints are equal if they have the same address type,
143   the same address value, and the same port. 143   the same address value, and the same port.
144   144  
145   @return `true` if both endpoints are equal. 145   @return `true` if both endpoints are equal.
146   */ 146   */
HITCBC 147   102 friend bool operator==(endpoint const& a, endpoint const& b) noexcept 147   102 friend bool operator==(endpoint const& a, endpoint const& b) noexcept
148   { 148   {
HITCBC 149   102 return a.port_ == b.port_ && a.addr_ == b.addr_; 149   102 return a.port_ == b.port_ && a.addr_ == b.addr_;
150   } 150   }
151   151  
152   /** Order two endpoints. 152   /** Order two endpoints.
153   153  
154   Establishes a strict total ordering consistent with 154   Establishes a strict total ordering consistent with
155   @ref operator==: equal endpoints compare equivalent. 155   @ref operator==: equal endpoints compare equivalent.
156   Endpoints are ordered first by address family (IPv4 156   Endpoints are ordered first by address family (IPv4
157   before IPv6), then by address value, then by port. This 157   before IPv6), then by address value, then by port. This
158   makes `endpoint` usable as a key in ordered containers 158   makes `endpoint` usable as a key in ordered containers
159   such as `std::map` and `std::set`. 159   such as `std::map` and `std::set`.
160   160  
161   @return The relative order of @p a and @p b. 161   @return The relative order of @p a and @p b.
162   */ 162   */
163   friend std::strong_ordering 163   friend std::strong_ordering
HITCBC 164   25 operator<=>(endpoint const& a, endpoint const& b) noexcept 164   25 operator<=>(endpoint const& a, endpoint const& b) noexcept
165   { 165   {
HITCBC 166   25 if (auto c = a.addr_ <=> b.addr_; c != 0) 166   25 if (auto c = a.addr_ <=> b.addr_; c != 0)
HITCBC 167   12 return c; 167   12 return c;
HITCBC 168   13 return a.port_ <=> b.port_; 168   13 return a.port_ <=> b.port_;
169   } 169   }
170   }; 170   };
171   171  
172   /** Endpoint format detection result. 172   /** Endpoint format detection result.
173   173  
174   Used internally by make_endpoint to determine 174   Used internally by make_endpoint to determine
175   the format of an endpoint string. 175   the format of an endpoint string.
176   */ 176   */
177   enum class endpoint_format 177   enum class endpoint_format
178   { 178   {
179   ipv4_no_port, ///< "192.168.1.1" 179   ipv4_no_port, ///< "192.168.1.1"
180   ipv4_with_port, ///< "192.168.1.1:8080" 180   ipv4_with_port, ///< "192.168.1.1:8080"
181   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8" 181   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8"
182   ipv6_bracketed ///< "[::1]" or "[::1]:8080" 182   ipv6_bracketed ///< "[::1]" or "[::1]:8080"
183   }; 183   };
184   184  
185   /** Detect the format of an endpoint string. 185   /** Detect the format of an endpoint string.
186   186  
187   This helper function determines the endpoint format 187   This helper function determines the endpoint format
188   based on simple rules: 188   based on simple rules:
189   1. Starts with `[` -> `ipv6_bracketed` 189   1. Starts with `[` -> `ipv6_bracketed`
190   2. Else count `:` characters: 190   2. Else count `:` characters:
191   - 0 colons -> `ipv4_no_port` 191   - 0 colons -> `ipv4_no_port`
192   - 1 colon -> `ipv4_with_port` 192   - 1 colon -> `ipv4_with_port`
193   - 2+ colons -> `ipv6_no_port` 193   - 2+ colons -> `ipv6_no_port`
194   194  
195   @param s The string to analyze. 195   @param s The string to analyze.
196   @return The detected endpoint format. 196   @return The detected endpoint format.
197   */ 197   */
198   BOOST_COROSIO_DECL 198   BOOST_COROSIO_DECL
199   endpoint_format detect_endpoint_format(std::string_view s) noexcept; 199   endpoint_format detect_endpoint_format(std::string_view s) noexcept;
200   200  
201   /** Create an endpoint from a string. 201   /** Create an endpoint from a string.
202   202  
203   This function parses an endpoint string in one of 203   This function parses an endpoint string in one of
204   the following formats: 204   the following formats:
205   205  
206   @li IPv4 without port: `192.168.1.1` 206   @li IPv4 without port: `192.168.1.1`
207   @li IPv4 with port: `192.168.1.1:8080` 207   @li IPv4 with port: `192.168.1.1:8080`
208   @li IPv6 without port: `::1` or `2001:db8::1` 208   @li IPv6 without port: `::1` or `2001:db8::1`
209   @li IPv6 with port (bracketed): `[::1]:8080` 209   @li IPv6 with port (bracketed): `[::1]:8080`
210   210  
211   @par Example 211   @par Example
212   @par !example make_endpoint 212   @par !example make_endpoint
213   213  
214   @param s The string to parse. 214   @param s The string to parse.
215   @return The error code, empty on success, and the parsed 215   @return The error code, empty on success, and the parsed
216   endpoint — default-constructed on failure. 216   endpoint — default-constructed on failure.
217   */ 217   */
218   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<endpoint> 218   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<endpoint>
219   make_endpoint(std::string_view s) noexcept; 219   make_endpoint(std::string_view s) noexcept;
220   220  
HITCBC 221   27 inline endpoint::endpoint(std::string_view s) 221   27 inline endpoint::endpoint(std::string_view s)
222   { 222   {
HITCBC 223   27 auto [ec, ep] = make_endpoint(s); 223   27 auto [ec, ep] = make_endpoint(s);
HITCBC 224   27 if (ec) 224   27 if (ec)
HITCBC 225   16 detail::throw_system_error(ec); 225   16 detail::throw_system_error(ec);
HITCBC 226   11 *this = ep; 226   11 *this = ep;
HITCBC 227   11 } 227   11 }
228   228  
229   } // namespace boost::corosio 229   } // namespace boost::corosio
230   230  
231   namespace std { 231   namespace std {
232   232  
233   /// Hash support for `boost::corosio::endpoint`. 233   /// Hash support for `boost::corosio::endpoint`.
234   template<> 234   template<>
235   struct hash<boost::corosio::endpoint> 235   struct hash<boost::corosio::endpoint>
236   { 236   {
237   /// Return the hash of `ep`. 237   /// Return the hash of `ep`.
HITCBC 238   12 std::size_t operator()(boost::corosio::endpoint const& ep) const noexcept 238   12 std::size_t operator()(boost::corosio::endpoint const& ep) const noexcept
239   { 239   {
HITCBC 240   12 std::size_t const h1 = hash<boost::corosio::ip_address>()(ep.address()); 240   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()); 241   12 std::size_t const h2 = hash<std::uint16_t>()(ep.port());
HITCBC 242   12 return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); 242   12 return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
243   } 243   }
244   }; 244   };
245   245  
246   } // namespace std 246   } // namespace std
247   247  
248   #endif 248   #endif