94.34% Lines (50/53) 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   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_ENDPOINT_HPP 10   #ifndef BOOST_COROSIO_ENDPOINT_HPP
11   #define BOOST_COROSIO_ENDPOINT_HPP 11   #define BOOST_COROSIO_ENDPOINT_HPP
12   12  
13   #include <boost/corosio/detail/config.hpp> 13   #include <boost/corosio/detail/config.hpp>
14   #include <boost/corosio/detail/except.hpp> 14   #include <boost/corosio/detail/except.hpp>
15   #include <boost/corosio/ipv4_address.hpp> 15   #include <boost/corosio/ipv4_address.hpp>
16   #include <boost/corosio/ipv6_address.hpp> 16   #include <boost/corosio/ipv6_address.hpp>
17   17  
18   #include <cstdint> 18   #include <cstdint>
19   #include <string_view> 19   #include <string_view>
20   #include <system_error> 20   #include <system_error>
21   21  
22   namespace boost::corosio { 22   namespace boost::corosio {
23   23  
24   /** An IP endpoint (address + port) supporting both IPv4 and IPv6. 24   /** An IP endpoint (address + port) supporting both IPv4 and IPv6.
25   25  
26   This class represents an endpoint for IP communication, 26   This class represents an endpoint for IP communication,
27   consisting of either an IPv4 or IPv6 address and a port number. 27   consisting of either an IPv4 or IPv6 address and a port number.
28   Endpoints are used to specify connection targets and bind addresses. 28   Endpoints are used to specify connection targets and bind addresses.
29   29  
30   The endpoint holds both address types as separate members (not a union), 30   The endpoint holds both address types as separate members (not a union),
31   with a discriminator to track which address type is active. 31   with a discriminator to track which address type is active.
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   @code 38   @code
39   // IPv4 endpoint 39   // IPv4 endpoint
40   endpoint ep4(ipv4_address::loopback(), 8080); 40   endpoint ep4(ipv4_address::loopback(), 8080);
41   41  
42   // IPv6 endpoint 42   // IPv6 endpoint
43   endpoint ep6(ipv6_address::loopback(), 8080); 43   endpoint ep6(ipv6_address::loopback(), 8080);
44   44  
45   // Port only (defaults to IPv4 any address) 45   // Port only (defaults to IPv4 any address)
46   endpoint bind_addr(8080); 46   endpoint bind_addr(8080);
47   47  
48   // Parse from string 48   // Parse from string
49   endpoint ep; 49   endpoint ep;
50   if (auto ec = parse_endpoint("192.168.1.1:8080", ep); !ec) { 50   if (auto ec = parse_endpoint("192.168.1.1:8080", ep); !ec) {
51   // use ep 51   // use ep
52   } 52   }
53   @endcode 53   @endcode
54   */ 54   */
55   class endpoint 55   class endpoint
56   { 56   {
57   ipv4_address v4_address_; 57   ipv4_address v4_address_;
58   ipv6_address v6_address_; 58   ipv6_address v6_address_;
59   std::uint16_t port_ = 0; 59   std::uint16_t port_ = 0;
60   bool is_v4_ = true; 60   bool is_v4_ = true;
61   61  
62   public: 62   public:
63   /** Default constructor. 63   /** Default constructor.
64   64  
65   Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0. 65   Creates an endpoint with the IPv4 any address (0.0.0.0) and port 0.
66   */ 66   */
HITCBC 67   198533 endpoint() noexcept 67   236062 endpoint() noexcept
HITCBC 68   198533 : v4_address_(ipv4_address::any()) 68   236062 : v4_address_(ipv4_address::any())
HITCBC 69   198533 , v6_address_{} 69   236062 , v6_address_{}
HITCBC 70   198533 , port_(0) 70   236062 , port_(0)
HITCBC 71   198533 , is_v4_(true) 71   236062 , is_v4_(true)
72   { 72   {
HITCBC 73   198533 } 73   236062 }
74   74  
75   /** Construct from IPv4 address and port. 75   /** Construct from IPv4 address and port.
76   76  
77   @param addr The IPv4 address. 77   @param addr The IPv4 address.
78   @param p The port number in host byte order. 78   @param p The port number in host byte order.
79   */ 79   */
HITCBC 80   19346 endpoint(ipv4_address addr, std::uint16_t p) noexcept 80   22978 endpoint(ipv4_address addr, std::uint16_t p) noexcept
HITCBC 81   19346 : v4_address_(addr) 81   22978 : v4_address_(addr)
HITCBC 82   19346 , v6_address_{} 82   22978 , v6_address_{}
HITCBC 83   19346 , port_(p) 83   22978 , port_(p)
HITCBC 84   19346 , is_v4_(true) 84   22978 , is_v4_(true)
85   { 85   {
HITCBC 86   19346 } 86   22978 }
87   87  
88   /** Construct from IPv6 address and port. 88   /** Construct from IPv6 address and port.
89   89  
90   @param addr The IPv6 address. 90   @param addr The IPv6 address.
91   @param p The port number in host byte order. 91   @param p The port number in host byte order.
92   */ 92   */
HITCBC 93   105 endpoint(ipv6_address addr, std::uint16_t p) noexcept 93   105 endpoint(ipv6_address addr, std::uint16_t p) noexcept
HITCBC 94   105 : v4_address_(ipv4_address::any()) 94   105 : v4_address_(ipv4_address::any())
HITCBC 95   105 , v6_address_(addr) 95   105 , v6_address_(addr)
HITCBC 96   105 , port_(p) 96   105 , port_(p)
HITCBC 97   105 , is_v4_(false) 97   105 , is_v4_(false)
98   { 98   {
HITCBC 99   105 } 99   105 }
100   100  
101   /** Construct from port only. 101   /** Construct from port only.
102   102  
103   Uses the IPv4 any address (0.0.0.0), which binds to all 103   Uses the IPv4 any address (0.0.0.0), which binds to all
104   available network interfaces. 104   available network interfaces.
105   105  
106   @param p The port number in host byte order. 106   @param p The port number in host byte order.
107   */ 107   */
HITCBC 108   12 explicit endpoint(std::uint16_t p) noexcept 108   12 explicit endpoint(std::uint16_t p) noexcept
HITCBC 109   12 : v4_address_(ipv4_address::any()) 109   12 : v4_address_(ipv4_address::any())
HITCBC 110   12 , v6_address_{} 110   12 , v6_address_{}
HITCBC 111   12 , port_(p) 111   12 , port_(p)
HITCBC 112   12 , is_v4_(true) 112   12 , is_v4_(true)
113   { 113   {
HITCBC 114   12 } 114   12 }
115   115  
116   /** Construct from an endpoint's address with a different port. 116   /** Construct from an endpoint's address with a different port.
117   117  
118   Creates a new endpoint using the address from an existing 118   Creates a new endpoint using the address from an existing
119   endpoint but with a different port number. 119   endpoint but with a different port number.
120   120  
121   @param ep The endpoint whose address to use. 121   @param ep The endpoint whose address to use.
122   @param p The port number in host byte order. 122   @param p The port number in host byte order.
123   */ 123   */
HITCBC 124   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept 124   2 endpoint(endpoint const& ep, std::uint16_t p) noexcept
HITCBC 125   2 : v4_address_(ep.v4_address_) 125   2 : v4_address_(ep.v4_address_)
HITCBC 126   2 , v6_address_(ep.v6_address_) 126   2 , v6_address_(ep.v6_address_)
HITCBC 127   2 , port_(p) 127   2 , port_(p)
HITCBC 128   2 , is_v4_(ep.is_v4_) 128   2 , is_v4_(ep.is_v4_)
129   { 129   {
HITCBC 130   2 } 130   2 }
131   131  
132   /** Construct from a string. 132   /** Construct from a string.
133   133  
134   Parses an endpoint string in one of the following formats: 134   Parses an endpoint string in one of the following formats:
135   @li IPv4 without port: `192.168.1.1` 135   @li IPv4 without port: `192.168.1.1`
136   @li IPv4 with port: `192.168.1.1:8080` 136   @li IPv4 with port: `192.168.1.1:8080`
137   @li IPv6 without port: `::1` or `2001:db8::1` 137   @li IPv6 without port: `::1` or `2001:db8::1`
138   @li IPv6 with port (bracketed): `[::1]:8080` 138   @li IPv6 with port (bracketed): `[::1]:8080`
139   139  
140   @param s The string to parse. 140   @param s The string to parse.
141   141  
142   @throws std::system_error on parse failure. 142   @throws std::system_error on parse failure.
143   */ 143   */
144   explicit endpoint(std::string_view s); 144   explicit endpoint(std::string_view s);
145   145  
146   /** Check if this endpoint uses an IPv4 address. 146   /** Check if this endpoint uses an IPv4 address.
147   147  
148   @return `true` if the endpoint uses IPv4, `false` if IPv6. 148   @return `true` if the endpoint uses IPv4, `false` if IPv6.
149   */ 149   */
HITCBC 150   13009 bool is_v4() const noexcept 150   15429 bool is_v4() const noexcept
151   { 151   {
HITCBC 152   13009 return is_v4_; 152   15429 return is_v4_;
153   } 153   }
154   154  
155   /** Check if this endpoint uses an IPv6 address. 155   /** Check if this endpoint uses an IPv6 address.
156   156  
157   @return `true` if the endpoint uses IPv6, `false` if IPv4. 157   @return `true` if the endpoint uses IPv6, `false` if IPv4.
158   */ 158   */
HITCBC 159   97 bool is_v6() const noexcept 159   97 bool is_v6() const noexcept
160   { 160   {
HITCBC 161   97 return !is_v4_; 161   97 return !is_v4_;
162   } 162   }
163   163  
164   /** Get the IPv4 address. 164   /** Get the IPv4 address.
165   165  
166   @return The IPv4 address. The value is valid even if 166   @return The IPv4 address. The value is valid even if
167   the endpoint is using IPv6 (it will be the default any address). 167   the endpoint is using IPv6 (it will be the default any address).
168   */ 168   */
HITCBC 169   6559 ipv4_address v4_address() const noexcept 169   7769 ipv4_address v4_address() const noexcept
170   { 170   {
HITCBC 171   6559 return v4_address_; 171   7769 return v4_address_;
172   } 172   }
173   173  
174   /** Get the IPv6 address. 174   /** Get the IPv6 address.
175   175  
176   @return The IPv6 address. The value is valid even if 176   @return The IPv6 address. The value is valid even if
177   the endpoint is using IPv4 (it will be the default any address). 177   the endpoint is using IPv4 (it will be the default any address).
178   */ 178   */
HITCBC 179   48 ipv6_address v6_address() const noexcept 179   48 ipv6_address v6_address() const noexcept
180   { 180   {
HITCBC 181   48 return v6_address_; 181   48 return v6_address_;
182   } 182   }
183   183  
184   /** Get the port number. 184   /** Get the port number.
185   185  
186   @return The port number in host byte order. 186   @return The port number in host byte order.
187   */ 187   */
HITCBC 188   6810 std::uint16_t port() const noexcept 188   8020 std::uint16_t port() const noexcept
189   { 189   {
HITCBC 190   6810 return port_; 190   8020 return port_;
191   } 191   }
192   192  
193   /** Compare endpoints for equality. 193   /** Compare endpoints for equality.
194   194  
195   Two endpoints are equal if they have the same address type, 195   Two endpoints are equal if they have the same address type,
196   the same address value, and the same port. 196   the same address value, and the same port.
197   197  
198   @return `true` if both endpoints are equal. 198   @return `true` if both endpoints are equal.
199   */ 199   */
HITCBC 200   60 friend bool operator==(endpoint const& a, endpoint const& b) noexcept 200   60 friend bool operator==(endpoint const& a, endpoint const& b) noexcept
201   { 201   {
HITCBC 202   60 if (a.is_v4_ != b.is_v4_) 202   60 if (a.is_v4_ != b.is_v4_)
MISUBC 203   return false; 203   return false;
HITCBC 204   60 if (a.port_ != b.port_) 204   60 if (a.port_ != b.port_)
MISUBC 205   return false; 205   return false;
HITCBC 206   60 if (a.is_v4_) 206   60 if (a.is_v4_)
HITCBC 207   60 return a.v4_address_ == b.v4_address_; 207   60 return a.v4_address_ == b.v4_address_;
208   else 208   else
MISUBC 209   return a.v6_address_ == b.v6_address_; 209   return a.v6_address_ == b.v6_address_;
210   } 210   }
211   211  
212   /** Compare endpoints for inequality. 212   /** Compare endpoints for inequality.
213   213  
214   @return `true` if endpoints differ. 214   @return `true` if endpoints differ.
215   */ 215   */
216   friend bool operator!=(endpoint const& a, endpoint const& b) noexcept 216   friend bool operator!=(endpoint const& a, endpoint const& b) noexcept
217   { 217   {
218   return !(a == b); 218   return !(a == b);
219   } 219   }
220   }; 220   };
221   221  
222   /** Endpoint format detection result. 222   /** Endpoint format detection result.
223   223  
224   Used internally by parse_endpoint to determine 224   Used internally by parse_endpoint to determine
225   the format of an endpoint string. 225   the format of an endpoint string.
226   */ 226   */
227   enum class endpoint_format 227   enum class endpoint_format
228   { 228   {
229   ipv4_no_port, ///< "192.168.1.1" 229   ipv4_no_port, ///< "192.168.1.1"
230   ipv4_with_port, ///< "192.168.1.1:8080" 230   ipv4_with_port, ///< "192.168.1.1:8080"
231   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8" 231   ipv6_no_port, ///< "::1" or "1:2:3:4:5:6:7:8"
232   ipv6_bracketed ///< "[::1]" or "[::1]:8080" 232   ipv6_bracketed ///< "[::1]" or "[::1]:8080"
233   }; 233   };
234   234  
235   /** Detect the format of an endpoint string. 235   /** Detect the format of an endpoint string.
236   236  
237   This helper function determines the endpoint format 237   This helper function determines the endpoint format
238   based on simple rules: 238   based on simple rules:
239   1. Starts with `[` -> `ipv6_bracketed` 239   1. Starts with `[` -> `ipv6_bracketed`
240   2. Else count `:` characters: 240   2. Else count `:` characters:
241   - 0 colons -> `ipv4_no_port` 241   - 0 colons -> `ipv4_no_port`
242   - 1 colon -> `ipv4_with_port` 242   - 1 colon -> `ipv4_with_port`
243   - 2+ colons -> `ipv6_no_port` 243   - 2+ colons -> `ipv6_no_port`
244   244  
245   @param s The string to analyze. 245   @param s The string to analyze.
246   @return The detected endpoint format. 246   @return The detected endpoint format.
247   */ 247   */
248   BOOST_COROSIO_DECL 248   BOOST_COROSIO_DECL
249   endpoint_format detect_endpoint_format(std::string_view s) noexcept; 249   endpoint_format detect_endpoint_format(std::string_view s) noexcept;
250   250  
251   /** Parse an endpoint from a string. 251   /** Parse an endpoint from a string.
252   252  
253   This function parses an endpoint string in one of 253   This function parses an endpoint string in one of
254   the following formats: 254   the following formats:
255   255  
256   @li IPv4 without port: `192.168.1.1` 256   @li IPv4 without port: `192.168.1.1`
257   @li IPv4 with port: `192.168.1.1:8080` 257   @li IPv4 with port: `192.168.1.1:8080`
258   @li IPv6 without port: `::1` or `2001:db8::1` 258   @li IPv6 without port: `::1` or `2001:db8::1`
259   @li IPv6 with port (bracketed): `[::1]:8080` 259   @li IPv6 with port (bracketed): `[::1]:8080`
260   260  
261   @par Example 261   @par Example
262   @code 262   @code
263   endpoint ep; 263   endpoint ep;
264   if (auto ec = parse_endpoint("192.168.1.1:8080", ep); !ec) { 264   if (auto ec = parse_endpoint("192.168.1.1:8080", ep); !ec) {
265   // ep.is_v4() == true 265   // ep.is_v4() == true
266   // ep.port() == 8080 266   // ep.port() == 8080
267   } 267   }
268   268  
269   if (auto ec = parse_endpoint("[::1]:443", ep); !ec) { 269   if (auto ec = parse_endpoint("[::1]:443", ep); !ec) {
270   // ep.is_v6() == true 270   // ep.is_v6() == true
271   // ep.port() == 443 271   // ep.port() == 443
272   } 272   }
273   @endcode 273   @endcode
274   274  
275   @param s The string to parse. 275   @param s The string to parse.
276   @param ep The endpoint to store the result. 276   @param ep The endpoint to store the result.
277   @return An error code (empty on success). 277   @return An error code (empty on success).
278   */ 278   */
279   [[nodiscard]] BOOST_COROSIO_DECL std::error_code 279   [[nodiscard]] BOOST_COROSIO_DECL std::error_code
280   parse_endpoint(std::string_view s, endpoint& ep) noexcept; 280   parse_endpoint(std::string_view s, endpoint& ep) noexcept;
281   281  
HITCBC 282   24 inline endpoint::endpoint(std::string_view s) 282   24 inline endpoint::endpoint(std::string_view s)
283   { 283   {
HITCBC 284   24 auto ec = parse_endpoint(s, *this); 284   24 auto ec = parse_endpoint(s, *this);
HITCBC 285   24 if (ec) 285   24 if (ec)
HITCBC 286   15 detail::throw_system_error(ec); 286   15 detail::throw_system_error(ec);
HITCBC 287   9 } 287   9 }
288   288  
289   } // namespace boost::corosio 289   } // namespace boost::corosio
290   290  
291   #endif 291   #endif