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