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