rippled
IPEndpoint_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of Beast: https://github.com/vinniefalco/Beast
4  Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 // MODULES: ../impl/IPEndpoint.cpp ../impl/IPAddressV4.cpp
21 // ../impl/IPAddressV6.cpp
22 
23 #include <ripple/basics/random.h>
24 #include <ripple/beast/net/IPEndpoint.h>
25 #include <ripple/beast/unit_test.h>
26 #include <boost/algorithm/string.hpp>
27 #include <boost/asio/ip/address.hpp>
28 #include <boost/predef.h>
29 #include <test/beast/IPEndpointCommon.h>
30 #include <typeinfo>
31 
32 namespace beast {
33 namespace IP {
34 
35 //------------------------------------------------------------------------------
36 
37 class IPEndpoint_test : public unit_test::suite
38 {
39 public:
40  void
42  std::string const& s,
43  std::uint32_t value,
44  std::string const& normal = "")
45  {
46  boost::system::error_code ec;
47  Address const result{Address::from_string(s, ec)};
48  if (!BEAST_EXPECTS(!ec, ec.message()))
49  return;
50  if (!BEAST_EXPECTS(result.is_v4(), s + " not v4"))
51  return;
52  if (!BEAST_EXPECTS(
53  result.to_v4().to_ulong() == value, s + " value mismatch"))
54  return;
55  BEAST_EXPECTS(
56  result.to_string() == (normal.empty() ? s : normal),
57  s + " as string");
58  }
59 
60  void
62  {
63  boost::system::error_code ec;
64  auto a = Address::from_string(s, ec);
65  BEAST_EXPECTS(ec, s + " parses as " + a.to_string());
66  }
67 
68  void
70  {
71  testcase("AddressV4");
72 
73  BEAST_EXPECT(AddressV4{}.to_ulong() == 0);
74  BEAST_EXPECT(is_unspecified(AddressV4{}));
75  BEAST_EXPECT(AddressV4{0x01020304}.to_ulong() == 0x01020304);
76 
77  {
78  AddressV4::bytes_type d = {{1, 2, 3, 4}};
79  BEAST_EXPECT(AddressV4{d}.to_ulong() == 0x01020304);
80 
81  unexpected(is_unspecified(AddressV4{d}));
82  }
83 
84  AddressV4 const v1{1};
85  BEAST_EXPECT(AddressV4{v1}.to_ulong() == 1);
86 
87  {
88  AddressV4 v;
89  v = v1;
90  BEAST_EXPECT(v.to_ulong() == v1.to_ulong());
91  }
92 
93  {
94  AddressV4 v;
95  auto d = v.to_bytes();
96  d[0] = 1;
97  d[1] = 2;
98  d[2] = 3;
99  d[3] = 4;
100  v = AddressV4{d};
101  BEAST_EXPECT(v.to_ulong() == 0x01020304);
102  }
103 
104  BEAST_EXPECT(AddressV4(0x01020304).to_string() == "1.2.3.4");
105 
106  shouldParseAddrV4("1.2.3.4", 0x01020304);
107  shouldParseAddrV4("255.255.255.255", 0xffffffff);
108  shouldParseAddrV4("0.0.0.0", 0);
109 
110  failParseAddr(".");
111  failParseAddr("..");
112  failParseAddr("...");
113  failParseAddr("....");
114 #if BOOST_OS_WINDOWS
115  // WINDOWS bug in asio - I don't think these should parse
116  // at all, and in-fact they do not on mac/linux
117  shouldParseAddrV4("1", 0x00000001, "0.0.0.1");
118  shouldParseAddrV4("1.2", 0x01000002, "1.0.0.2");
119  shouldParseAddrV4("1.2.3", 0x01020003, "1.2.0.3");
120 #else
121  failParseAddr("1");
122  failParseAddr("1.2");
123  failParseAddr("1.2.3");
124 #endif
125  failParseAddr("1.");
126  failParseAddr("1.2.");
127  failParseAddr("1.2.3.");
128  failParseAddr("256.0.0.0");
129  failParseAddr("-1.2.3.4");
130  }
131 
132  void
134  {
135  testcase("AddressV4::Bytes");
136 
137  AddressV4::bytes_type d1 = {{10, 0, 0, 1}};
138  AddressV4 v4{d1};
139  BEAST_EXPECT(v4.to_bytes()[0] == 10);
140  BEAST_EXPECT(v4.to_bytes()[1] == 0);
141  BEAST_EXPECT(v4.to_bytes()[2] == 0);
142  BEAST_EXPECT(v4.to_bytes()[3] == 1);
143 
144  BEAST_EXPECT((~((0xff) << 16)) == 0xff00ffff);
145 
146  auto d2 = v4.to_bytes();
147  d2[1] = 10;
148  v4 = AddressV4{d2};
149  BEAST_EXPECT(v4.to_bytes()[0] == 10);
150  BEAST_EXPECT(v4.to_bytes()[1] == 10);
151  BEAST_EXPECT(v4.to_bytes()[2] == 0);
152  BEAST_EXPECT(v4.to_bytes()[3] == 1);
153  }
154 
155  //--------------------------------------------------------------------------
156 
157  void
159  {
160  testcase("Address");
161 
162  boost::system::error_code ec;
163  Address result{Address::from_string("1.2.3.4", ec)};
164  AddressV4::bytes_type d = {{1, 2, 3, 4}};
165  BEAST_EXPECT(!ec);
166  BEAST_EXPECT(result.is_v4() && result.to_v4() == AddressV4{d});
167  }
168 
169  //--------------------------------------------------------------------------
170 
171  void
173  std::string const& s,
174  AddressV4::bytes_type const& value,
175  std::uint16_t p,
176  std::string const& normal = "")
177  {
178  auto const result = Endpoint::from_string_checked(s);
179  if (!BEAST_EXPECT(result))
180  return;
181  if (!BEAST_EXPECT(result->address().is_v4()))
182  return;
183  if (!BEAST_EXPECT(result->address().to_v4() == AddressV4{value}))
184  return;
185 
186  BEAST_EXPECT(result->port() == p);
187  BEAST_EXPECT(to_string(*result) == (normal.empty() ? s : normal));
188  }
189 
190  void
192  std::string const& s,
193  AddressV6::bytes_type const& value,
194  std::uint16_t p,
195  std::string const& normal = "")
196  {
197  auto result = Endpoint::from_string_checked(s);
198  if (!BEAST_EXPECT(result))
199  return;
200  if (!BEAST_EXPECT(result->address().is_v6()))
201  return;
202  if (!BEAST_EXPECT(result->address().to_v6() == AddressV6{value}))
203  return;
204 
205  BEAST_EXPECT(result->port() == p);
206  BEAST_EXPECT(to_string(*result) == (normal.empty() ? s : normal));
207  }
208 
209  void
211  {
212  auto a1 = Endpoint::from_string(s);
213  BEAST_EXPECTS(is_unspecified(a1), s + " parses as " + a1.to_string());
214 
215  auto a2 = Endpoint::from_string(s);
216  BEAST_EXPECTS(is_unspecified(a2), s + " parses as " + a2.to_string());
217 
218  boost::replace_last(s, ":", " ");
219  auto a3 = Endpoint::from_string(s);
220  BEAST_EXPECTS(is_unspecified(a3), s + " parses as " + a3.to_string());
221  }
222 
223  void
225  {
226  testcase("Endpoint");
227 
228  shouldParseEPV4("1.2.3.4", {{1, 2, 3, 4}}, 0);
229  shouldParseEPV4("1.2.3.4:5", {{1, 2, 3, 4}}, 5);
230  shouldParseEPV4("1.2.3.4 5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
231  // leading, trailing space
232  shouldParseEPV4(" 1.2.3.4:5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
233  shouldParseEPV4("1.2.3.4:5 ", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
234  shouldParseEPV4("1.2.3.4 ", {{1, 2, 3, 4}}, 0, "1.2.3.4");
235  shouldParseEPV4(" 1.2.3.4", {{1, 2, 3, 4}}, 0, "1.2.3.4");
237  "2001:db8:a0b:12f0::1",
238  {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
239  0);
241  "[2001:db8:a0b:12f0::1]:8",
242  {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
243  8);
245  "[2001:2002:2003:2004:2005:2006:2007:2008]:65535",
246  {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
247  65535);
249  "2001:2002:2003:2004:2005:2006:2007:2008 65535",
250  {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
251  65535,
252  "[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
253 
254  Endpoint ep;
255 
256  AddressV4::bytes_type d = {{127, 0, 0, 1}};
257  ep = Endpoint(AddressV4{d}, 80);
258  BEAST_EXPECT(!is_unspecified(ep));
259  BEAST_EXPECT(!is_public(ep));
260  BEAST_EXPECT(is_private(ep));
261  BEAST_EXPECT(!is_multicast(ep));
262  BEAST_EXPECT(is_loopback(ep));
263  BEAST_EXPECT(to_string(ep) == "127.0.0.1:80");
264  // same address as v4 mapped in ipv6
265  ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}), 80);
266  BEAST_EXPECT(!is_unspecified(ep));
267  BEAST_EXPECT(!is_public(ep));
268  BEAST_EXPECT(is_private(ep));
269  BEAST_EXPECT(!is_multicast(ep));
270  BEAST_EXPECT(!is_loopback(ep)); // mapped loopback is not a loopback
271  BEAST_EXPECTS(to_string(ep) == "[::ffff:127.0.0.1]:80", to_string(ep));
272 
273  d = {{10, 0, 0, 1}};
274  ep = Endpoint(AddressV4{d});
275  BEAST_EXPECT(get_class(ep.to_v4()) == 'A');
276  BEAST_EXPECT(!is_unspecified(ep));
277  BEAST_EXPECT(!is_public(ep));
278  BEAST_EXPECT(is_private(ep));
279  BEAST_EXPECT(!is_multicast(ep));
280  BEAST_EXPECT(!is_loopback(ep));
281  BEAST_EXPECT(to_string(ep) == "10.0.0.1");
282  // same address as v4 mapped in ipv6
283  ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}));
284  BEAST_EXPECT(get_class(ep.to_v6().to_v4()) == 'A');
285  BEAST_EXPECT(!is_unspecified(ep));
286  BEAST_EXPECT(!is_public(ep));
287  BEAST_EXPECT(is_private(ep));
288  BEAST_EXPECT(!is_multicast(ep));
289  BEAST_EXPECT(!is_loopback(ep));
290  BEAST_EXPECTS(to_string(ep) == "::ffff:10.0.0.1", to_string(ep));
291 
292  d = {{166, 78, 151, 147}};
293  ep = Endpoint(AddressV4{d});
294  BEAST_EXPECT(!is_unspecified(ep));
295  BEAST_EXPECT(is_public(ep));
296  BEAST_EXPECT(!is_private(ep));
297  BEAST_EXPECT(!is_multicast(ep));
298  BEAST_EXPECT(!is_loopback(ep));
299  BEAST_EXPECT(to_string(ep) == "166.78.151.147");
300  // same address as v4 mapped in ipv6
301  ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}));
302  BEAST_EXPECT(!is_unspecified(ep));
303  BEAST_EXPECT(is_public(ep));
304  BEAST_EXPECT(!is_private(ep));
305  BEAST_EXPECT(!is_multicast(ep));
306  BEAST_EXPECT(!is_loopback(ep));
307  BEAST_EXPECTS(to_string(ep) == "::ffff:166.78.151.147", to_string(ep));
308 
309  // a private IPv6
310  AddressV6::bytes_type d2 = {
311  {253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
312  ep = Endpoint(AddressV6{d2});
313  BEAST_EXPECT(!is_unspecified(ep));
314  BEAST_EXPECT(!is_public(ep));
315  BEAST_EXPECT(is_private(ep));
316  BEAST_EXPECT(!is_multicast(ep));
317  BEAST_EXPECT(!is_loopback(ep));
318  BEAST_EXPECTS(to_string(ep) == "fd00::1", to_string(ep));
319 
320  {
321  ep = Endpoint::from_string("192.0.2.112");
322  BEAST_EXPECT(!is_unspecified(ep));
323  BEAST_EXPECT(ep == Endpoint::from_string("192.0.2.112"));
324 
325  auto const ep1 = Endpoint::from_string("192.0.2.112:2016");
326  BEAST_EXPECT(!is_unspecified(ep1));
327  BEAST_EXPECT(ep.address() == ep1.address());
328  BEAST_EXPECT(ep1.port() == 2016);
329 
330  auto const ep2 = Endpoint::from_string("192.0.2.112:2016");
331  BEAST_EXPECT(!is_unspecified(ep2));
332  BEAST_EXPECT(ep.address() == ep2.address());
333  BEAST_EXPECT(ep2.port() == 2016);
334  BEAST_EXPECT(ep1 == ep2);
335 
336  auto const ep3 = Endpoint::from_string("192.0.2.112 2016");
337  BEAST_EXPECT(!is_unspecified(ep3));
338  BEAST_EXPECT(ep.address() == ep3.address());
339  BEAST_EXPECT(ep3.port() == 2016);
340  BEAST_EXPECT(ep2 == ep3);
341 
342  auto const ep4 = Endpoint::from_string("192.0.2.112 2016");
343  BEAST_EXPECT(!is_unspecified(ep4));
344  BEAST_EXPECT(ep.address() == ep4.address());
345  BEAST_EXPECT(ep4.port() == 2016);
346  BEAST_EXPECT(ep3 == ep4);
347 
348  BEAST_EXPECT(to_string(ep1) == to_string(ep2));
349  BEAST_EXPECT(to_string(ep1) == to_string(ep3));
350  BEAST_EXPECT(to_string(ep1) == to_string(ep4));
351  }
352 
353  {
354  ep = Endpoint::from_string("[::]:2017");
355  BEAST_EXPECT(is_unspecified(ep));
356  BEAST_EXPECT(ep.port() == 2017);
357  BEAST_EXPECT(ep.address() == AddressV6{});
358  }
359 
360  // Failures:
361  failParseEP("192.0.2.112:port");
362  failParseEP("ip:port");
363  failParseEP("");
364  failParseEP("1.2.3.256");
365 
366 #if BOOST_OS_WINDOWS
367  // windows asio bugs...false positives
368  shouldParseEPV4("255", {{ 0, 0, 0, 255 }}, 0, "0.0.0.255");
369  shouldParseEPV4("512", {{ 0, 0, 2, 0 }}, 0, "0.0.2.0");
370  shouldParseEPV4("1.2.3:80", {{ 1, 2, 0, 3 }}, 80, "1.2.0.3:80");
371 #else
372  failParseEP("255");
373  failParseEP("512");
374  failParseEP("1.2.3:80");
375 #endif
376 
377  failParseEP("1.2.3.4:65536");
378  failParseEP("1.2.3.4:89119");
379  failParseEP("1.2.3:89119");
380  failParseEP("[::1]:89119");
381  failParseEP("[::az]:1");
382  failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
383  failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
384  failParseEP("abcdef:12345");
385  failParseEP("[abcdef]:12345");
386  failParseEP("foo.org 12345");
387 
388  // test with hashed container
390  constexpr auto items{100};
391  float max_lf{0};
392  for (auto i = 0; i < items; ++i)
393  {
394  eps.insert(randomEP(ripple::rand_int(0, 1) == 1));
395  max_lf = std::max(max_lf, eps.load_factor());
396  }
397  BEAST_EXPECT(eps.bucket_count() >= items);
398  BEAST_EXPECT(max_lf > 0.90);
399  }
400 
401  //--------------------------------------------------------------------------
402 
403  template <typename T>
404  bool
405  parse(std::string const& text, T& t)
406  {
407  std::istringstream stream{text};
408  stream >> t;
409  return !stream.fail();
410  }
411 
412  template <typename T>
413  void
414  shouldPass(std::string const& text, std::string const& normal = "")
415  {
416  using namespace std::literals;
417  T t;
418  BEAST_EXPECT(parse(text, t));
419  BEAST_EXPECTS(
420  to_string(t) == (normal.empty() ? text : normal),
421  "string mismatch for "s + text);
422  }
423 
424  template <typename T>
425  void
426  shouldFail(std::string const& text)
427  {
428  T t;
429  unexpected(parse(text, t), text + " should not parse");
430  }
431 
432  template <typename T>
433  void
434  testParse(char const* name)
435  {
436  testcase(name);
437 
438  shouldPass<T>("0.0.0.0");
439  shouldPass<T>("192.168.0.1");
440  shouldPass<T>("168.127.149.132");
441  shouldPass<T>("168.127.149.132:80");
442  shouldPass<T>("168.127.149.132:54321");
443  shouldPass<T>("2001:db8:a0b:12f0::1");
444  shouldPass<T>("[2001:db8:a0b:12f0::1]:8");
445  shouldPass<T>("2001:db8:a0b:12f0::1 8", "[2001:db8:a0b:12f0::1]:8");
446  shouldPass<T>("[::1]:8");
447  shouldPass<T>("[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
448 
449  shouldFail<T>("1.2.3.256");
450  shouldFail<T>("");
451 #if BOOST_OS_WINDOWS
452  // windows asio bugs...false positives
453  shouldPass<T>("512", "0.0.2.0");
454  shouldPass<T>("255", "0.0.0.255");
455  shouldPass<T>("1.2.3:80", "1.2.0.3:80");
456 #else
457  shouldFail<T>("512");
458  shouldFail<T>("255");
459  shouldFail<T>("1.2.3:80");
460 #endif
461  shouldFail<T>("1.2.3:65536");
462  shouldFail<T>("1.2.3:72131");
463  shouldFail<T>("[::1]:89119");
464  shouldFail<T>("[::az]:1");
465  shouldFail<T>("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
466  shouldFail<T>("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
467  }
468 
469  void
470  run() override
471  {
472  testAddressV4();
474  testAddress();
475  testEndpoint();
476  testParse<Endpoint>("Parse Endpoint");
477  }
478 };
479 
480 BEAST_DEFINE_TESTSUITE(IPEndpoint, net, beast);
481 
482 } // namespace IP
483 } // namespace beast
std::string
STL class.
beast::IP::IPEndpoint_test::shouldFail
void shouldFail(std::string const &text)
Definition: IPEndpoint_test.cpp:426
beast::IP::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(IPEndpoint, net, beast)
beast::IP::IPEndpoint_test::failParseEP
void failParseEP(std::string s)
Definition: IPEndpoint_test.cpp:210
beast::IP::IPEndpoint_test::testAddress
void testAddress()
Definition: IPEndpoint_test.cpp:158
std::unordered_set
STL class.
beast::IP::get_class
char get_class(AddressV4 const &addr)
Returns the address class for the given address.
Definition: IPAddressV4.cpp:47
std::istringstream
STL class.
beast::IP::is_loopback
bool is_loopback(Address const &addr)
Returns true if this is a loopback address.
Definition: IPAddress.h:52
beast::IP::is_multicast
bool is_multicast(Address const &addr)
Returns true if the address is a multicast address.
Definition: IPAddress.h:66
beast::IP::is_private
bool is_private(AddressV4 const &addr)
Returns true if the address is a private unroutable address.
Definition: IPAddressV4.cpp:29
beast::IP::IPEndpoint_test::shouldParseEPV4
void shouldParseEPV4(std::string const &s, AddressV4::bytes_type const &value, std::uint16_t p, std::string const &normal="")
Definition: IPEndpoint_test.cpp:172
beast::IP::IPEndpoint_test::shouldParseEPV6
void shouldParseEPV6(std::string const &s, AddressV6::bytes_type const &value, std::uint16_t p, std::string const &normal="")
Definition: IPEndpoint_test.cpp:191
beast::IP::IPEndpoint_test::testEndpoint
void testEndpoint()
Definition: IPEndpoint_test.cpp:224
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
beast::IP::Address
boost::asio::ip::address Address
Definition: IPAddress.h:41
beast::IP::to_string
std::string to_string(Address const &addr)
Returns the address represented as a string.
Definition: IPAddress.h:45
beast::IP::IPEndpoint_test::failParseAddr
void failParseAddr(std::string const &s)
Definition: IPEndpoint_test.cpp:61
beast::IP::IPEndpoint_test::shouldParseAddrV4
void shouldParseAddrV4(std::string const &s, std::uint32_t value, std::string const &normal="")
Definition: IPEndpoint_test.cpp:41
std::uint32_t
beast::IP::is_public
bool is_public(AddressV4 const &addr)
Returns true if the address is a public routable address.
Definition: IPAddressV4.cpp:41
beast::IP::AddressV6
boost::asio::ip::address_v6 AddressV6
Definition: IPAddressV6.h:34
beast::IP::IPEndpoint_test::shouldPass
void shouldPass(std::string const &text, std::string const &normal="")
Definition: IPEndpoint_test.cpp:414
beast::IP::AddressV4
boost::asio::ip::address_v4 AddressV4
Definition: IPAddressV4.h:34
std::unordered_set::load_factor
T load_factor(T... args)
std::unordered_set::insert
T insert(T... args)
std::unordered_set::bucket_count
T bucket_count(T... args)
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
beast::IP::IPEndpoint_test::run
void run() override
Definition: IPEndpoint_test.cpp:470
beast::IP::IPEndpoint_test::parse
bool parse(std::string const &text, T &t)
Definition: IPEndpoint_test.cpp:405
beast::IP::IPEndpoint_test::testAddressV4
void testAddressV4()
Definition: IPEndpoint_test.cpp:69
typeinfo
beast::IP::randomEP
Endpoint randomEP(bool v4=true)
Definition: IPEndpointCommon.h:27
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:38
std::max
T max(T... args)
beast::IP::IPEndpoint_test
Definition: IPEndpoint_test.cpp:37
beast::IP::IPEndpoint_test::testParse
void testParse(char const *name)
Definition: IPEndpoint_test.cpp:434
beast::IP::is_unspecified
bool is_unspecified(Address const &addr)
Returns true if the address is unspecified.
Definition: IPAddress.h:59
beast::IP::IPEndpoint_test::testAddressV4Proxy
void testAddressV4Proxy()
Definition: IPEndpoint_test.cpp:133
beast::IP::Endpoint::from_string_checked
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:35
beast
Definition: base_uint.h:641