libfly  6.2.2
C++20 utility library for Linux, macOS, and Windows
endpoint.hpp
1 #pragma once
2 
3 #include "fly/fly.hpp"
4 #include "fly/net/ipv4_address.hpp"
5 #include "fly/net/ipv6_address.hpp"
6 #include "fly/net/socket/concepts.hpp"
7 #include "fly/net/socket/types.hpp"
8 #include "fly/types/string/lexer.hpp"
9 #include "fly/types/string/string.hpp"
10 
11 #include <compare>
12 #include <limits>
13 #include <optional>
14 #include <string>
15 #include <type_traits>
16 
17 namespace fly::net {
18 
26 template <IPAddress IPAddressType>
27 class Endpoint
28 {
29 public:
30  using address_type = IPAddressType;
31 
35  Endpoint() = default;
36 
43  constexpr Endpoint(const IPAddressType &address, port_type port) noexcept;
44 
51  constexpr Endpoint(IPAddressType &&address, port_type port) noexcept;
52 
53  Endpoint(const Endpoint &) = default;
54  Endpoint(Endpoint &&) = default;
55 
56  Endpoint &operator=(const Endpoint &) = default;
57  Endpoint &operator=(Endpoint &&) = default;
58 
62  static constexpr bool is_ipv4();
63 
67  static constexpr bool is_ipv6();
68 
79  static constexpr std::optional<Endpoint> from_string(std::string_view endpoint);
80 
84  constexpr const IPAddressType &address() const;
85 
89  constexpr port_type port() const;
90 
91 #if defined(FLY_MACOS)
96  constexpr bool operator==(const Endpoint &endpoint) const;
97  constexpr bool operator!=(const Endpoint &endpoint) const;
98  constexpr bool operator<(const Endpoint &endpoint) const;
99  constexpr bool operator<=(const Endpoint &endpoint) const;
100  constexpr bool operator>(const Endpoint &endpoint) const;
101  constexpr bool operator>=(const Endpoint &endpoint) const;
102 #else
107  auto operator<=>(const Endpoint &) const = default;
108 #endif
109 
110 private:
111  IPAddressType m_address {};
112  port_type m_port {0};
113 };
114 
115 //==================================================================================================
116 template <IPAddress IPAddressType>
117 constexpr Endpoint<IPAddressType>::Endpoint(const IPAddressType &address, port_type port) noexcept :
118  m_address(address),
119  m_port(port)
120 {
121 }
122 
123 //==================================================================================================
124 template <IPAddress IPAddressType>
125 constexpr Endpoint<IPAddressType>::Endpoint(IPAddressType &&address, port_type port) noexcept :
126  m_address(address),
127  m_port(port)
128 {
129 }
130 
131 //==================================================================================================
132 template <IPAddress IPAddressType>
134 {
135  return std::is_same_v<IPAddressType, IPv4Address>;
136 }
137 
138 //==================================================================================================
139 template <IPAddress IPAddressType>
141 {
142  return std::is_same_v<IPAddressType, IPv6Address>;
143 }
144 
145 //==================================================================================================
146 template <IPAddress IPAddressType>
147 constexpr std::optional<Endpoint<IPAddressType>>
148 Endpoint<IPAddressType>::from_string(std::string_view endpoint)
149 {
150  constexpr const auto s_max16 =
151  static_cast<std::size_t>(std::numeric_limits<std::uint16_t>::max());
152  constexpr const auto s_colon = ':';
153 
154  const std::size_t separator = endpoint.find_last_of(s_colon);
155 
156  if ((separator == std::string_view::npos) || (separator == 0) || (separator == endpoint.size()))
157  {
158  return std::nullopt;
159  }
160 
161  auto address_view = endpoint.substr(0, separator);
162  auto port_view = endpoint.substr(separator + 1);
163 
164  if constexpr (is_ipv6())
165  {
166  constexpr const auto s_left_bracket = '[';
167  constexpr const auto s_right_bracket = ']';
168 
169  if (address_view.starts_with(s_left_bracket) && address_view.ends_with(s_right_bracket))
170  {
171  address_view = address_view.substr(1, address_view.size() - 2);
172  }
173  else
174  {
175  return std::nullopt;
176  }
177  }
178 
179  fly::Lexer lexer(std::move(port_view));
180 
181  auto address = IPAddressType::from_string(std::move(address_view));
182  auto port = lexer.consume_number();
183 
184  if (!address || !port || (*port > s_max16) || lexer.peek())
185  {
186  return std::nullopt;
187  }
188 
189  return Endpoint(*std::move(address), static_cast<port_type>(*port));
190 }
191 
192 //==================================================================================================
193 template <IPAddress IPAddressType>
194 constexpr const IPAddressType &Endpoint<IPAddressType>::address() const
195 {
196  return m_address;
197 }
198 
199 //==================================================================================================
200 template <IPAddress IPAddressType>
201 constexpr port_type Endpoint<IPAddressType>::port() const
202 {
203  return m_port;
204 }
205 
206 #if defined(FLY_MACOS)
207 
208 //==================================================================================================
209 template <IPAddress IPAddressType>
210 constexpr bool Endpoint<IPAddressType>::operator==(const Endpoint<IPAddressType> &endpoint) const
211 {
212  return (m_address == endpoint.m_address) && (m_port == endpoint.m_port);
213 }
214 
215 //==================================================================================================
216 template <IPAddress IPAddressType>
217 constexpr bool Endpoint<IPAddressType>::operator!=(const Endpoint<IPAddressType> &endpoint) const
218 {
219  return !(*this == endpoint);
220 }
221 
222 //==================================================================================================
223 template <IPAddress IPAddressType>
224 constexpr bool Endpoint<IPAddressType>::operator<(const Endpoint<IPAddressType> &endpoint) const
225 {
226  if (m_address < endpoint.m_address)
227  {
228  return true;
229  }
230 
231  return m_port < endpoint.m_port;
232 }
233 
234 //==================================================================================================
235 template <IPAddress IPAddressType>
236 constexpr bool Endpoint<IPAddressType>::operator<=(const Endpoint<IPAddressType> &endpoint) const
237 {
238  return !(endpoint < *this);
239 }
240 
241 //==================================================================================================
242 template <IPAddress IPAddressType>
243 constexpr bool Endpoint<IPAddressType>::operator>(const Endpoint<IPAddressType> &endpoint) const
244 {
245  return !(*this <= endpoint);
246 }
247 
248 //==================================================================================================
249 template <IPAddress IPAddressType>
250 constexpr bool Endpoint<IPAddressType>::operator>=(const Endpoint<IPAddressType> &endpoint) const
251 {
252  return !(*this < endpoint);
253 }
254 
255 #endif
256 
257 } // namespace fly::net
258 
259 //==================================================================================================
260 template <>
261 struct fly::Formatter<fly::net::Endpoint<fly::net::IPv4Address>>
262 {
271  template <typename FormatContext>
272  void format(const fly::net::Endpoint<fly::net::IPv4Address> &endpoint, FormatContext &context)
273  {
274  fly::String::format_to(context.out(), "{}:{}", endpoint.address(), endpoint.port());
275  }
276 };
277 
278 //==================================================================================================
279 template <>
280 struct fly::Formatter<fly::net::Endpoint<fly::net::IPv6Address>>
281 {
290  template <typename FormatContext>
291  void format(const fly::net::Endpoint<fly::net::IPv6Address> &endpoint, FormatContext &context)
292  {
293  fly::String::format_to(context.out(), "[{}]:{}", endpoint.address(), endpoint.port());
294  }
295 };
Definition: lexer.hpp:31
constexpr std::optional< std::uintmax_t > consume_number()
Definition: lexer.hpp:227
constexpr std::optional< CharType > peek(std::size_t offset=0)
Definition: lexer.hpp:190
static void format_to(OutputIterator output, FormatString< ParameterTypes... > &&fmt, ParameterTypes &&...parameters)
Definition: string.hpp:939
Definition: endpoint.hpp:28
static constexpr bool is_ipv4()
Definition: endpoint.hpp:133
auto operator<=>(const Endpoint &) const =default
static constexpr std::optional< Endpoint > from_string(std::string_view endpoint)
Definition: endpoint.hpp:148
static constexpr bool is_ipv6()
Definition: endpoint.hpp:140
constexpr port_type port() const
Definition: endpoint.hpp:201
constexpr const IPAddressType & address() const
Definition: endpoint.hpp:194
void format(const fly::net::Endpoint< fly::net::IPv4Address > &endpoint, FormatContext &context)
Definition: endpoint.hpp:272
void format(const fly::net::Endpoint< fly::net::IPv6Address > &endpoint, FormatContext &context)
Definition: endpoint.hpp:291
Definition: formatters.hpp:42