include/boost/corosio/endpoint.hpp

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