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