mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Support ipv6 for peer and RPC comms:
Fixes: RIPD-1574 Alias beast address classes to the asio equivalents. Adjust users of address classes accordingly. Fix resolver class so that it can support ipv6 addresses. Make unit tests use ipv6 localhost network. Extend endpoint peer message to support string endpoint representations while also supporting the existing fields (both are optional/repeated types). Expand test for Livecache and Endpoint. Workaround some false positive ipaddr tests on windows (asio bug?) Replaced usage of address::from_string(deprecated) with free function make_address. Identified a remaining use of v4 address type and replaced with the more appropriate IPEndpoint type (rpc_ip cmdline option). Add CLI flag for using ipv4 with unit tests. Release Notes ------------- The optional rpc_port command line flag is deprecated. The rpc_ip parameter now works as documented and accepts ip and port combined.
This commit is contained in:
@@ -216,12 +216,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace test{ extern std::atomic<bool> envUseIPv4; }
|
||||
|
||||
static int runUnitTests(
|
||||
std::string const& pattern,
|
||||
std::string const& argument,
|
||||
bool quiet,
|
||||
bool log,
|
||||
bool child,
|
||||
bool ipv4,
|
||||
std::size_t num_jobs,
|
||||
int argc,
|
||||
char** argv)
|
||||
@@ -229,6 +232,9 @@ static int runUnitTests(
|
||||
using namespace beast::unit_test;
|
||||
using namespace ripple::test;
|
||||
|
||||
if (ipv4)
|
||||
ripple::test::envUseIPv4 = true;
|
||||
|
||||
#if HAS_BOOST_PROCESS
|
||||
if (!child && num_jobs == 1)
|
||||
#endif
|
||||
@@ -365,6 +371,7 @@ int run (int argc, char** argv)
|
||||
"Specify the IP address for RPC command. "
|
||||
"Format: <ip-address>[':'<port-number>]")
|
||||
("rpc_port", po::value <std::uint16_t> (),
|
||||
"DEPRECATED: include with rpc_ip instead. "
|
||||
"Specify the port number for RPC command.")
|
||||
;
|
||||
|
||||
@@ -384,6 +391,7 @@ int run (int argc, char** argv)
|
||||
"argument is handled individually by any suite that accesses it -- "
|
||||
"as such, it typically only make sense to provide this when running "
|
||||
"a single suite.")
|
||||
("unittest-ipv4", "Use IPv4 localhost when running unittests (default is IPv6).")
|
||||
("unittest-log",
|
||||
"Force unit test log message output. Only useful in combination with "
|
||||
"--quiet, in which case log messages will print but suite/case names "
|
||||
@@ -468,6 +476,7 @@ int run (int argc, char** argv)
|
||||
bool (vm.count ("quiet")),
|
||||
bool (vm.count ("unittest-log")),
|
||||
unittestChild,
|
||||
bool (vm.count ("unittest-ipv4")),
|
||||
numJobs,
|
||||
argc,
|
||||
argv);
|
||||
@@ -553,30 +562,25 @@ int run (int argc, char** argv)
|
||||
// happen after the config file is loaded.
|
||||
if (vm.count ("rpc_ip"))
|
||||
{
|
||||
try
|
||||
{
|
||||
config->rpc_ip.emplace (
|
||||
boost::asio::ip::address_v4::from_string(
|
||||
vm["rpc_ip"].as<std::string>()));
|
||||
}
|
||||
catch(std::exception const&)
|
||||
auto res = beast::IP::Endpoint::from_string_checked(
|
||||
vm["rpc_ip"].as<std::string>());
|
||||
if (! res.second)
|
||||
{
|
||||
std::cerr << "Invalid rpc_ip = " <<
|
||||
vm["rpc_ip"].as<std::string>() << std::endl;
|
||||
vm["rpc_ip"].as<std::string>() << "\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Override the RPC destination port number
|
||||
//
|
||||
if (res.first.port() == 0)
|
||||
{
|
||||
std::cerr << "No port specified in rpc_ip.\n";
|
||||
if (vm.count ("rpc_port"))
|
||||
{
|
||||
std::cerr << "WARNING: using deprecated rpc_port param.\n";
|
||||
try
|
||||
{
|
||||
config->rpc_port.emplace (
|
||||
vm["rpc_port"].as<std::uint16_t>());
|
||||
|
||||
if (*config->rpc_port == 0)
|
||||
res.first.at_port(vm["rpc_port"].as<std::uint16_t>());
|
||||
if (res.first.port() == 0)
|
||||
throw std::domain_error("0");
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
@@ -585,6 +589,12 @@ int run (int argc, char** argv)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->rpc_ip = std::move(res.first);
|
||||
}
|
||||
|
||||
if (vm.count ("quorum"))
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <ripple/basics/ResolverAsio.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/beast/net/IPAddressConversion.h>
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/beast/core/WaitableEvent.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <atomic>
|
||||
@@ -259,6 +260,21 @@ public:
|
||||
|
||||
HostAndPort parseName(std::string const& str)
|
||||
{
|
||||
// first attempt to parse as an endpoint (IP addr + port).
|
||||
// If that doesn't succeed, fall back to generic name + port parsing
|
||||
|
||||
auto result {beast::IP::Endpoint::from_string_checked (str)};
|
||||
if (result.second)
|
||||
{
|
||||
return make_pair (
|
||||
result.first.address().to_string(),
|
||||
std::to_string(result.first.port()));
|
||||
}
|
||||
|
||||
// generic name/port parsing, which doesn't work for
|
||||
// IPv6 addresses in particular because it considers a colon
|
||||
// a port separator
|
||||
|
||||
// Attempt to find the first and last non-whitespace
|
||||
auto const find_whitespace = std::bind (
|
||||
&std::isspace <std::string::value_type>,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <ripple/basics/ToString.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <boost/regex.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
@@ -93,24 +93,38 @@ uint64_t uintFromHex (std::string const& strSrc)
|
||||
bool parseUrl (parsedURL& pUrl, std::string const& strUrl)
|
||||
{
|
||||
// scheme://username:password@hostname:port/rest
|
||||
static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^:/]+)(?::(\\d+))?(/.*)?\\s*?\\'");
|
||||
static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^/]+)(/.*)?\\s*?\\'");
|
||||
boost::smatch smMatch;
|
||||
|
||||
bool bMatch = boost::regex_match (strUrl, smMatch, reUrl); // Match status code.
|
||||
|
||||
if (bMatch)
|
||||
{
|
||||
std::string strPort;
|
||||
|
||||
pUrl.scheme = smMatch[1];
|
||||
boost::algorithm::to_lower (pUrl.scheme);
|
||||
pUrl.path = smMatch[3];
|
||||
pUrl.domain = smMatch[2];
|
||||
if (smMatch[3].length ())
|
||||
|
||||
// now consider the domain/port fragment
|
||||
auto colonPos = pUrl.domain.find_last_of(':');
|
||||
if (colonPos != std::string::npos)
|
||||
{
|
||||
// use Endpoint class to see if this thing looks
|
||||
// like an IP addr...
|
||||
auto result {beast::IP::Endpoint::from_string_checked (pUrl.domain)};
|
||||
if (result.second)
|
||||
{
|
||||
pUrl.domain = result.first.address().to_string();
|
||||
pUrl.port = result.first.port();
|
||||
}
|
||||
else // otherwise we are DNS name + port
|
||||
{
|
||||
pUrl.port = beast::lexicalCast <std::uint16_t> (
|
||||
std::string (smMatch[3]));
|
||||
pUrl.domain.substr(colonPos+1));
|
||||
pUrl.domain = pUrl.domain.substr(0, colonPos);
|
||||
}
|
||||
pUrl.path = smMatch[4];
|
||||
}
|
||||
//else, the whole thing is domain, not port
|
||||
}
|
||||
|
||||
return bMatch;
|
||||
|
||||
@@ -217,19 +217,9 @@ private:
|
||||
std::thread m_thread;
|
||||
|
||||
static boost::asio::ip::udp::endpoint to_endpoint (
|
||||
IP::Endpoint const &address)
|
||||
IP::Endpoint const &ep)
|
||||
{
|
||||
if (address.is_v4 ())
|
||||
{
|
||||
return boost::asio::ip::udp::endpoint (
|
||||
boost::asio::ip::address_v4 (
|
||||
address.to_v4().value), address.port ());
|
||||
}
|
||||
|
||||
// VFALCO TODO IPv6 support
|
||||
assert(false);
|
||||
return boost::asio::ip::udp::endpoint (
|
||||
boost::asio::ip::address_v6 (), 0);
|
||||
return boost::asio::ip::udp::endpoint (ep.address(), ep.port());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/uhash.h>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
@@ -37,213 +38,22 @@
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
/** A version-independent IP address.
|
||||
This object can represent either an IPv4 or IPv6 address.
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
public:
|
||||
/** Create an unspecified IPv4 address. */
|
||||
Address ()
|
||||
: m_type (ipv4)
|
||||
{
|
||||
}
|
||||
using Address = boost::asio::ip::address;
|
||||
|
||||
/** Create an IPv4 address. */
|
||||
Address (AddressV4 const& addr)
|
||||
: m_type (ipv4)
|
||||
, m_v4 (addr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Create an IPv6 address. */
|
||||
Address (AddressV6 const& addr)
|
||||
: m_type (ipv6)
|
||||
, m_v6 (addr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Assign a copy from another address in any format. */
|
||||
/** @{ */
|
||||
Address&
|
||||
operator= (AddressV4 const& addr)
|
||||
{
|
||||
m_type = ipv4;
|
||||
m_v6 = AddressV6();
|
||||
m_v4 = addr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Address&
|
||||
operator= (AddressV6 const& addr)
|
||||
{
|
||||
m_type = ipv6;
|
||||
m_v4 = AddressV4();
|
||||
m_v6 = addr;
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Create an Address from a string.
|
||||
@return A pair with the address, and bool set to `true` on success.
|
||||
*/
|
||||
static
|
||||
std::pair <Address, bool>
|
||||
from_string (std::string const& s);
|
||||
|
||||
/** Returns a string representing the address. */
|
||||
/** Returns the address represented as a string. */
|
||||
inline
|
||||
std::string
|
||||
to_string () const
|
||||
to_string (Address const& addr)
|
||||
{
|
||||
return (is_v4 ())
|
||||
? IP::to_string (to_v4())
|
||||
: IP::to_string (to_v6());
|
||||
return addr.to_string ();
|
||||
}
|
||||
|
||||
/** Returns `true` if this address represents an IPv4 address. */
|
||||
bool
|
||||
is_v4 () const noexcept
|
||||
{
|
||||
return m_type == ipv4;
|
||||
}
|
||||
|
||||
/** Returns `true` if this address represents an IPv6 address. */
|
||||
bool
|
||||
is_v6() const noexcept
|
||||
{
|
||||
return m_type == ipv6;
|
||||
}
|
||||
|
||||
/** Returns the IPv4 address.
|
||||
Precondition:
|
||||
is_v4() == `true`
|
||||
*/
|
||||
AddressV4 const&
|
||||
to_v4 () const
|
||||
{
|
||||
if (!is_v4 ())
|
||||
throw std::bad_cast();
|
||||
return m_v4;
|
||||
}
|
||||
|
||||
/** Returns the IPv6 address.
|
||||
Precondition:
|
||||
is_v6() == `true`
|
||||
*/
|
||||
AddressV6 const&
|
||||
to_v6 () const
|
||||
{
|
||||
if (!is_v6 ())
|
||||
throw std::bad_cast();
|
||||
return m_v6;
|
||||
}
|
||||
|
||||
/** Returns `true` if this address represents 0.0.0.0 */
|
||||
bool
|
||||
is_any () const
|
||||
{
|
||||
return is_v4 () ? m_v4 == IP::AddressV4::any ()
|
||||
: false; // m_v6 == IP::AddressV6::any();
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend
|
||||
void
|
||||
hash_append(Hasher& h, Address const& addr) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
if (addr.is_v4 ())
|
||||
hash_append(h, addr.to_v4 ());
|
||||
else if (addr.is_v6 ())
|
||||
hash_append(h, addr.to_v6 ());
|
||||
else
|
||||
assert (false);
|
||||
}
|
||||
|
||||
/** Arithmetic comparison. */
|
||||
/** @{ */
|
||||
friend
|
||||
bool
|
||||
operator== (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
if (lhs.is_v4 ())
|
||||
{
|
||||
if (rhs.is_v4 ())
|
||||
return lhs.to_v4() == rhs.to_v4();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.is_v6 ())
|
||||
return lhs.to_v6() == rhs.to_v6();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator< (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
if (lhs.m_type < rhs.m_type)
|
||||
return true;
|
||||
if (lhs.is_v4 ())
|
||||
return lhs.to_v4() < rhs.to_v4();
|
||||
return lhs.to_v6() < rhs.to_v6();
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator!= (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator> (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator<= (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
return ! (lhs > rhs);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator>= (Address const& lhs, Address const& rhs)
|
||||
{
|
||||
return ! (rhs > lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
enum Type
|
||||
{
|
||||
ipv4,
|
||||
ipv6
|
||||
};
|
||||
|
||||
Type m_type;
|
||||
AddressV4 m_v4;
|
||||
AddressV6 m_v6;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Properties
|
||||
|
||||
/** Returns `true` if this is a loopback address. */
|
||||
inline
|
||||
bool
|
||||
is_loopback (Address const& addr)
|
||||
{
|
||||
return (addr.is_v4 ())
|
||||
? is_loopback (addr.to_v4 ())
|
||||
: is_loopback (addr.to_v6 ());
|
||||
return addr.is_loopback();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is unspecified. */
|
||||
@@ -251,9 +61,7 @@ inline
|
||||
bool
|
||||
is_unspecified (Address const& addr)
|
||||
{
|
||||
return (addr.is_v4 ())
|
||||
? is_unspecified (addr.to_v4 ())
|
||||
: is_unspecified (addr.to_v6 ());
|
||||
return addr.is_unspecified();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is a multicast address. */
|
||||
@@ -261,9 +69,7 @@ inline
|
||||
bool
|
||||
is_multicast (Address const& addr)
|
||||
{
|
||||
return (addr.is_v4 ())
|
||||
? is_multicast (addr.to_v4 ())
|
||||
: is_multicast (addr.to_v6 ());
|
||||
return addr.is_multicast();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
@@ -286,51 +92,24 @@ is_public (Address const& addr)
|
||||
: is_public (addr.to_v6 ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns the address represented as a string. */
|
||||
inline std::string to_string (Address const& addr)
|
||||
{
|
||||
return addr.to_string ();
|
||||
}
|
||||
|
||||
/** Output stream conversion. */
|
||||
template <typename OutputStream>
|
||||
OutputStream&
|
||||
operator<< (OutputStream& os, Address const& addr)
|
||||
{
|
||||
return os << to_string (addr);
|
||||
}
|
||||
|
||||
/** Input stream conversion. */
|
||||
inline
|
||||
std::istream&
|
||||
operator>> (std::istream& is, Address& addr)
|
||||
{
|
||||
// VFALCO TODO Support ipv6!
|
||||
AddressV4 addrv4;
|
||||
is >> addrv4;
|
||||
addr = Address (addrv4);
|
||||
return is;
|
||||
}
|
||||
|
||||
inline
|
||||
std::pair <Address, bool>
|
||||
Address::from_string (std::string const& s)
|
||||
{
|
||||
std::stringstream is (s);
|
||||
Address addr;
|
||||
is >> addr;
|
||||
if (! is.fail() && is.rdbuf()->in_avail() == 0)
|
||||
return std::make_pair (addr, true);
|
||||
return std::make_pair (Address (), false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
if (addr.is_v4 ())
|
||||
hash_append(h, addr.to_v4().to_bytes());
|
||||
else if (addr.is_v6 ())
|
||||
hash_append(h, addr.to_v6().to_bytes());
|
||||
else
|
||||
assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash <beast::IP::Address>
|
||||
|
||||
@@ -21,141 +21,17 @@
|
||||
#define BEAST_NET_IPADDRESSV4_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
/** Represents a version 4 IP address. */
|
||||
struct AddressV4
|
||||
{
|
||||
/** Default constructor represents the 'any' address. */
|
||||
AddressV4 ();
|
||||
|
||||
/** Construct from a 32-bit unsigned.
|
||||
@note Octets are formed in order from the MSB to the LSB.
|
||||
*/
|
||||
explicit AddressV4 (std::uint32_t value_);
|
||||
|
||||
/** Construct from four individual octets..
|
||||
@note The resulting address is a.b.c.d
|
||||
*/
|
||||
AddressV4 (std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d);
|
||||
|
||||
/** Create an address from an IPv4 address string in dotted decimal form.
|
||||
@return A pair with the address, and bool set to `true` on success.
|
||||
*/
|
||||
static std::pair <AddressV4, bool> from_string (std::string const& s);
|
||||
|
||||
/** Returns an address that represents 'any' address. */
|
||||
static AddressV4 any ()
|
||||
{ return AddressV4(); }
|
||||
|
||||
/** Returns an address that represents the loopback address. */
|
||||
static AddressV4 loopback ()
|
||||
{ return AddressV4 (0x7f000001); }
|
||||
|
||||
/** Returns an address that represents the broadcast address. */
|
||||
static AddressV4 broadcast ()
|
||||
{ return AddressV4 (0xffffffff); }
|
||||
|
||||
/** Returns the broadcast address for the specified address. */
|
||||
static AddressV4 broadcast (AddressV4 const& address);
|
||||
|
||||
/** Returns the broadcast address corresponding to the address and mask. */
|
||||
static AddressV4 broadcast (
|
||||
AddressV4 const& address, AddressV4 const& mask);
|
||||
|
||||
/** Returns `true` if this is a broadcast address. */
|
||||
bool is_broadcast () const
|
||||
{ return *this == broadcast (*this); }
|
||||
|
||||
/** Returns the address class for the given address.
|
||||
@note Class 'D' represents multicast addresses (224.*.*.*).
|
||||
*/
|
||||
static char get_class (AddressV4 const& address);
|
||||
|
||||
/** Returns the netmask for the address class or address. */
|
||||
/** @{ */
|
||||
static AddressV4 netmask (char address_class);
|
||||
static AddressV4 netmask (AddressV4 const& v);
|
||||
/** @} */
|
||||
|
||||
/** Arithmetic comparison. */
|
||||
/** @{ */
|
||||
friend bool operator== (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return lhs.value == rhs.value; }
|
||||
friend bool operator< (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return lhs.value < rhs.value; }
|
||||
|
||||
friend bool operator!= (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return ! (lhs == rhs); }
|
||||
friend bool operator> (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return rhs < lhs; }
|
||||
friend bool operator<= (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return ! (lhs > rhs); }
|
||||
friend bool operator>= (AddressV4 const& lhs, AddressV4 const& rhs)
|
||||
{ return ! (rhs > lhs); }
|
||||
/** @} */
|
||||
|
||||
/** Array indexing for reading and writing indiviual octets. */
|
||||
/** @{ */
|
||||
template <bool IsConst>
|
||||
class Proxy
|
||||
{
|
||||
public:
|
||||
using Pointer = typename std::conditional <
|
||||
IsConst, std::uint32_t const*, std::uint32_t*>::type;
|
||||
|
||||
Proxy (int shift, Pointer value)
|
||||
: m_shift (shift)
|
||||
, m_value (value)
|
||||
{
|
||||
}
|
||||
|
||||
operator std::uint8_t() const
|
||||
{
|
||||
return ((*m_value)>>m_shift) & 0xff;
|
||||
}
|
||||
|
||||
template <typename IntegralType>
|
||||
Proxy& operator= (IntegralType v)
|
||||
{
|
||||
(*m_value) =
|
||||
( (*m_value) & (~((0xff)<<m_shift)) )
|
||||
| ((v&0xff) << m_shift);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_shift;
|
||||
Pointer m_value;
|
||||
};
|
||||
|
||||
Proxy <true> operator[] (std::size_t index) const;
|
||||
Proxy <false> operator[] (std::size_t index);
|
||||
/** @} */
|
||||
|
||||
/** The value as a 32 bit unsigned. */
|
||||
std::uint32_t value;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns `true` if this is a loopback address. */
|
||||
bool is_loopback (AddressV4 const& addr);
|
||||
|
||||
/** Returns `true` if the address is unspecified. */
|
||||
bool is_unspecified (AddressV4 const& addr);
|
||||
|
||||
/** Returns `true` if the address is a multicast address. */
|
||||
bool is_multicast (AddressV4 const& addr);
|
||||
using AddressV4 = boost::asio::ip::address_v4;
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
bool is_private (AddressV4 const& addr);
|
||||
@@ -163,42 +39,12 @@ bool is_private (AddressV4 const& addr);
|
||||
/** Returns `true` if the address is a public routable address. */
|
||||
bool is_public (AddressV4 const& addr);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns the address represented as a string. */
|
||||
std::string to_string (AddressV4 const& addr);
|
||||
|
||||
/** Output stream conversion. */
|
||||
template <typename OutputStream>
|
||||
OutputStream& operator<< (OutputStream& os, AddressV4 const& addr)
|
||||
{ return os << to_string (addr); }
|
||||
|
||||
/** Input stream conversion. */
|
||||
std::istream& operator>> (std::istream& is, AddressV4& addr);
|
||||
/** Returns the address class for the given address.
|
||||
@note Class 'D' represents multicast addresses (224.*.*.*).
|
||||
*/
|
||||
char get_class (AddressV4 const& address);
|
||||
|
||||
}
|
||||
|
||||
template <class HashAlgorithm>
|
||||
struct is_contiguously_hashable<IP::AddressV4, HashAlgorithm>
|
||||
: public std::integral_constant<bool, sizeof(IP::AddressV4) == sizeof(std::uint32_t)>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
/** std::hash support. */
|
||||
template <>
|
||||
struct hash <beast::IP::AddressV4>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t operator() (beast::IP::AddressV4 const& addr) const
|
||||
{ return addr.value; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,45 +26,12 @@
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
/** Represents a version 4 IP address. */
|
||||
struct AddressV6
|
||||
{
|
||||
explicit AddressV6() = default;
|
||||
|
||||
// VFALCO TODO
|
||||
|
||||
/** Arithmetic comparison. */
|
||||
/** @{ */
|
||||
friend bool operator== (AddressV6 const&, AddressV6 const&)
|
||||
{ assert(false); return false; }
|
||||
friend bool operator< (AddressV6 const&, AddressV6 const&)
|
||||
{ assert(false); return false; }
|
||||
|
||||
friend bool operator!= (AddressV6 const& lhs, AddressV6 const& rhs)
|
||||
{ return ! (lhs == rhs); }
|
||||
friend bool operator> (AddressV6 const& lhs, AddressV6 const& rhs)
|
||||
{ return rhs < lhs; }
|
||||
friend bool operator<= (AddressV6 const& lhs, AddressV6 const& rhs)
|
||||
{ return ! (lhs > rhs); }
|
||||
friend bool operator>= (AddressV6 const& lhs, AddressV6 const& rhs)
|
||||
{ return ! (rhs > lhs); }
|
||||
/** @} */
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns `true` if this is a loopback address. */
|
||||
bool is_loopback (AddressV6 const& addr);
|
||||
|
||||
/** Returns `true` if the address is unspecified. */
|
||||
bool is_unspecified (AddressV6 const& addr);
|
||||
|
||||
/** Returns `true` if the address is a multicast address. */
|
||||
bool is_multicast (AddressV6 const& addr);
|
||||
using AddressV6 = boost::asio::ip::address_v6;
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
bool is_private (AddressV6 const& addr);
|
||||
@@ -72,41 +39,7 @@ bool is_private (AddressV6 const& addr);
|
||||
/** Returns `true` if the address is a public routable address. */
|
||||
bool is_public (AddressV6 const& addr);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher&, AddressV6 const&)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/** Returns the address represented as a string. */
|
||||
std::string to_string (AddressV6 const& addr);
|
||||
|
||||
/** Output stream conversion. */
|
||||
template <typename OutputStream>
|
||||
OutputStream& operator<< (OutputStream& os, AddressV6 const& addr)
|
||||
{ return os << to_string (addr); }
|
||||
|
||||
/** Input stream conversion. */
|
||||
std::istream& operator>> (std::istream& is, AddressV6& addr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
/** std::hash support. */
|
||||
template <>
|
||||
struct hash <beast::IP::AddressV6>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t operator() (beast::IP::AddressV6 const& addr) const
|
||||
{ assert(false); return 0; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
*/
|
||||
static std::pair <Endpoint, bool> from_string_checked (std::string const& s);
|
||||
static Endpoint from_string (std::string const& s);
|
||||
static Endpoint from_string_altform (std::string const& s);
|
||||
|
||||
/** Returns a string representing the endpoint. */
|
||||
std::string to_string () const;
|
||||
@@ -71,9 +70,9 @@ public:
|
||||
{ return m_addr.is_v4(); }
|
||||
bool is_v6 () const
|
||||
{ return m_addr.is_v6(); }
|
||||
AddressV4 const& to_v4 () const
|
||||
AddressV4 const to_v4 () const
|
||||
{ return m_addr.to_v4 (); }
|
||||
AddressV6 const& to_v6 () const
|
||||
AddressV6 const to_v6 () const
|
||||
{ return m_addr.to_v6 (); }
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NET_DETAIL_PARSE_H_INCLUDED
|
||||
#define BEAST_NET_DETAIL_PARSE_H_INCLUDED
|
||||
|
||||
#include <ios>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** Require and consume the specified character from the input.
|
||||
@return `true` if the character matched.
|
||||
*/
|
||||
template <typename InputStream>
|
||||
bool expect(InputStream& is, char v)
|
||||
{
|
||||
char c;
|
||||
if (is.get(c) && v == c)
|
||||
return true;
|
||||
is.unget();
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Require and consume whitespace from the input.
|
||||
@return `true` if the character matched.
|
||||
*/
|
||||
template <typename InputStream>
|
||||
bool expect_whitespace (InputStream& is)
|
||||
{
|
||||
char c;
|
||||
if (is.get(c) && isspace(static_cast<unsigned char>(c)))
|
||||
return true;
|
||||
is.unget();
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Used to disambiguate 8-bit integers from characters. */
|
||||
template <typename IntType>
|
||||
struct integer_holder
|
||||
{
|
||||
IntType* pi;
|
||||
explicit integer_holder (IntType& i)
|
||||
: pi (&i)
|
||||
{
|
||||
}
|
||||
template <typename OtherIntType>
|
||||
IntType& operator= (OtherIntType o) const
|
||||
{
|
||||
*pi = o;
|
||||
return *pi;
|
||||
}
|
||||
};
|
||||
|
||||
/** Parse 8-bit unsigned integer. */
|
||||
template <typename InputStream>
|
||||
InputStream& operator>> (InputStream& is, integer_holder <std::uint8_t> const& i)
|
||||
{
|
||||
std::uint16_t v;
|
||||
is >> v;
|
||||
if (! (v>=0 && v<=255))
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
i = std::uint8_t(v);
|
||||
return is;
|
||||
}
|
||||
|
||||
/** Free function for template argument deduction. */
|
||||
template <typename IntType>
|
||||
integer_holder <IntType> integer (IntType& i)
|
||||
{
|
||||
return integer_holder <IntType> (i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -24,43 +24,22 @@ namespace IP {
|
||||
|
||||
Endpoint from_asio (boost::asio::ip::address const& address)
|
||||
{
|
||||
if (address.is_v4 ())
|
||||
{
|
||||
boost::asio::ip::address_v4::bytes_type const bytes (
|
||||
address.to_v4().to_bytes());
|
||||
return Endpoint (AddressV4 (
|
||||
bytes [0], bytes [1], bytes [2], bytes [3]));
|
||||
}
|
||||
|
||||
// VFALCO TODO IPv6 support
|
||||
assert(false);
|
||||
return Endpoint();
|
||||
return Endpoint {address};
|
||||
}
|
||||
|
||||
Endpoint from_asio (boost::asio::ip::tcp::endpoint const& endpoint)
|
||||
{
|
||||
return from_asio (endpoint.address()).at_port (endpoint.port());
|
||||
return Endpoint {endpoint.address(), endpoint.port()};
|
||||
}
|
||||
|
||||
boost::asio::ip::address to_asio_address (Endpoint const& endpoint)
|
||||
{
|
||||
if (endpoint.address().is_v4())
|
||||
{
|
||||
return boost::asio::ip::address (
|
||||
boost::asio::ip::address_v4 (
|
||||
endpoint.address().to_v4().value));
|
||||
}
|
||||
|
||||
// VFALCO TODO IPv6 support
|
||||
assert(false);
|
||||
return boost::asio::ip::address (
|
||||
boost::asio::ip::address_v6 ());
|
||||
return endpoint.address();
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::endpoint to_asio_endpoint (Endpoint const& endpoint)
|
||||
{
|
||||
return boost::asio::ip::tcp::endpoint (
|
||||
to_asio_address (endpoint), endpoint.port());
|
||||
return boost::asio::ip::tcp::endpoint {endpoint.address(), endpoint.port()};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#endif
|
||||
|
||||
#include <ripple/beast/net/IPAddressV4.h>
|
||||
#include <ripple/beast/net/detail/Parse.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
@@ -29,154 +28,26 @@
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
AddressV4::AddressV4 ()
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
AddressV4::AddressV4 (std::uint32_t value_)
|
||||
: value (value_)
|
||||
{
|
||||
}
|
||||
|
||||
AddressV4::AddressV4 (std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d)
|
||||
: value ((a<<24)|(b<<16)|(c<<8)|d)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair <AddressV4, bool> AddressV4::from_string (std::string const& s)
|
||||
{
|
||||
std::stringstream is (s);
|
||||
AddressV4 addr;
|
||||
is >> addr;
|
||||
if (! is.fail() && is.rdbuf()->in_avail() == 0)
|
||||
return std::make_pair (addr, true);
|
||||
return std::make_pair (AddressV4 (), false);
|
||||
}
|
||||
|
||||
AddressV4 AddressV4::broadcast (AddressV4 const& address)
|
||||
{
|
||||
return broadcast (address, netmask (address));
|
||||
}
|
||||
|
||||
AddressV4 AddressV4::broadcast (
|
||||
AddressV4 const& address, AddressV4 const& mask)
|
||||
{
|
||||
return AddressV4 (address.value | (mask.value ^ 0xffffffff));
|
||||
}
|
||||
|
||||
char AddressV4::get_class (AddressV4 const& addr)
|
||||
{
|
||||
static char const* table = "AAAABBCD";
|
||||
return table [(addr.value & 0xE0000000) >> 29];
|
||||
}
|
||||
|
||||
AddressV4 AddressV4::netmask (char address_class)
|
||||
{
|
||||
switch (address_class)
|
||||
{
|
||||
case 'A': return AddressV4 (0xff000000);
|
||||
case 'B': return AddressV4 (0xffff0000);
|
||||
case 'C': return AddressV4 (0xffffff00);
|
||||
case 'D':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return AddressV4 (0xffffffff);
|
||||
}
|
||||
|
||||
AddressV4 AddressV4::netmask (AddressV4 const& addr)
|
||||
{
|
||||
return netmask (get_class (addr));
|
||||
}
|
||||
|
||||
AddressV4::Proxy <true> AddressV4::operator[] (std::size_t index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
default:
|
||||
throw std::out_of_range ("bad array index");
|
||||
case 0: return Proxy <true> (24, &value);
|
||||
case 1: return Proxy <true> (16, &value);
|
||||
case 2: return Proxy <true> ( 8, &value);
|
||||
case 3: return Proxy <true> ( 0, &value);
|
||||
};
|
||||
};
|
||||
|
||||
AddressV4::Proxy <false> AddressV4::operator[] (std::size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
default:
|
||||
throw std::out_of_range ("bad array index");
|
||||
case 0: return Proxy <false> (24, &value);
|
||||
case 1: return Proxy <false> (16, &value);
|
||||
case 2: return Proxy <false> ( 8, &value);
|
||||
case 3: return Proxy <false> ( 0, &value);
|
||||
};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool is_loopback (AddressV4 const& addr)
|
||||
{
|
||||
return (addr.value & 0xff000000) == 0x7f000000;
|
||||
}
|
||||
|
||||
bool is_unspecified (AddressV4 const& addr)
|
||||
{
|
||||
return addr.value == 0;
|
||||
}
|
||||
|
||||
bool is_multicast (AddressV4 const& addr)
|
||||
{
|
||||
return (addr.value & 0xf0000000) == 0xe0000000;
|
||||
}
|
||||
|
||||
bool is_private (AddressV4 const& addr)
|
||||
{
|
||||
return
|
||||
((addr.value & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.#
|
||||
((addr.value & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.#
|
||||
((addr.value & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.#
|
||||
is_loopback (addr);
|
||||
((addr.to_ulong() & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.#
|
||||
((addr.to_ulong() & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.#
|
||||
((addr.to_ulong() & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.#
|
||||
addr.is_loopback();
|
||||
}
|
||||
|
||||
bool is_public (AddressV4 const& addr)
|
||||
{
|
||||
return
|
||||
! is_private (addr) &&
|
||||
! is_multicast (addr);
|
||||
! addr.is_multicast();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string to_string (AddressV4 const& addr)
|
||||
char get_class (AddressV4 const& addr)
|
||||
{
|
||||
std::string s;
|
||||
s.reserve (15);
|
||||
s =
|
||||
std::to_string (addr[0]) + "." +
|
||||
std::to_string (addr[1]) + "." +
|
||||
std::to_string (addr[2]) + "." +
|
||||
std::to_string (addr[3]);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::istream& operator>> (std::istream& is, AddressV4& addr)
|
||||
{
|
||||
std::uint8_t octet [4];
|
||||
is >> IP::detail::integer (octet [0]);
|
||||
for (int i = 1; i < 4; ++i)
|
||||
{
|
||||
if (!is || !IP::detail::expect(is, '.'))
|
||||
return is;
|
||||
is >> IP::detail::integer (octet [i]);
|
||||
if (!is)
|
||||
return is;
|
||||
}
|
||||
addr = AddressV4 (octet[0], octet[1], octet[2], octet[3]);
|
||||
return is;
|
||||
static char const* table = "AAAABBCD";
|
||||
return table [(addr.to_ulong() & 0xE0000000) >> 29];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,62 +21,25 @@
|
||||
#endif
|
||||
|
||||
#include <ripple/beast/net/IPAddressV6.h>
|
||||
#include <ripple/beast/net/IPAddressV4.h>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool is_loopback (AddressV6 const&)
|
||||
bool is_private (AddressV6 const& addr)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return false;
|
||||
return ((addr.to_bytes()[0] & 0xfd) || // TODO fc00::/8 too ?
|
||||
(addr.is_v4_mapped() && is_private(addr.to_v4())) );
|
||||
}
|
||||
|
||||
bool is_unspecified (AddressV6 const&)
|
||||
bool is_public (AddressV6 const& addr)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return false;
|
||||
// TODO is this correct?
|
||||
return
|
||||
! is_private (addr) &&
|
||||
! addr.is_multicast();
|
||||
}
|
||||
|
||||
bool is_multicast (AddressV6 const&)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_private (AddressV6 const&)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_public (AddressV6 const&)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string to_string (AddressV6 const&)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::istream& operator>> (std::istream& is, AddressV6&)
|
||||
{
|
||||
// VFALCO TODO
|
||||
assert(false);
|
||||
return is;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#endif
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/beast/net/detail/Parse.h>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
@@ -44,7 +43,7 @@ std::pair <Endpoint, bool> Endpoint::from_string_checked (std::string const& s)
|
||||
is >> endpoint;
|
||||
if (! is.fail() && is.rdbuf()->in_avail() == 0)
|
||||
return std::make_pair (endpoint, true);
|
||||
return std::make_pair (Endpoint (), false);
|
||||
return std::make_pair (Endpoint {}, false);
|
||||
}
|
||||
|
||||
Endpoint Endpoint::from_string (std::string const& s)
|
||||
@@ -53,69 +52,26 @@ Endpoint Endpoint::from_string (std::string const& s)
|
||||
from_string_checked (s));
|
||||
if (result.second)
|
||||
return result.first;
|
||||
return Endpoint();
|
||||
}
|
||||
|
||||
// VFALCO NOTE This is a hack to support legacy data format
|
||||
//
|
||||
Endpoint Endpoint::from_string_altform (std::string const& s)
|
||||
{
|
||||
// Accept the regular form if it parses
|
||||
{
|
||||
Endpoint ep (Endpoint::from_string (s));
|
||||
if (! is_unspecified (ep))
|
||||
return ep;
|
||||
}
|
||||
|
||||
// Now try the alt form
|
||||
std::stringstream is (s);
|
||||
|
||||
AddressV4 v4;
|
||||
is >> v4;
|
||||
if (! is.fail())
|
||||
{
|
||||
Endpoint ep (v4);
|
||||
|
||||
if (is.rdbuf()->in_avail()>0)
|
||||
{
|
||||
if (! IP::detail::expect_whitespace (is))
|
||||
return Endpoint();
|
||||
|
||||
while (is.rdbuf()->in_avail()>0)
|
||||
{
|
||||
char c;
|
||||
is.get(c);
|
||||
if (!isspace (static_cast<unsigned char>(c)))
|
||||
{
|
||||
is.unget();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Port port;
|
||||
is >> port;
|
||||
if (is.fail())
|
||||
return Endpoint();
|
||||
|
||||
return ep.at_port (port);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just an address with no port
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
|
||||
// Could be V6 here...
|
||||
|
||||
return Endpoint();
|
||||
return Endpoint {};
|
||||
}
|
||||
|
||||
std::string Endpoint::to_string () const
|
||||
{
|
||||
std::string s (address ().to_string ());
|
||||
if (port() != 0)
|
||||
s = s + ":" + std::to_string (port());
|
||||
std::string s;
|
||||
s.reserve(
|
||||
(address().is_v6() ? INET6_ADDRSTRLEN-1 : 15) +
|
||||
(port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0)));
|
||||
|
||||
if (port() != 0 && address().is_v6())
|
||||
s += '[';
|
||||
s += address ().to_string();
|
||||
if (port())
|
||||
{
|
||||
if (address().is_v6())
|
||||
s += ']';
|
||||
s += ":" + std::to_string (port());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -138,34 +94,88 @@ bool operator< (Endpoint const& lhs, Endpoint const& rhs)
|
||||
|
||||
std::istream& operator>> (std::istream& is, Endpoint& endpoint)
|
||||
{
|
||||
// VFALCO TODO Support ipv6!
|
||||
std::string addrStr;
|
||||
// valid addresses only need INET6_ADDRSTRLEN-1 chars, but allow the extra
|
||||
// char to check for invalid lengths
|
||||
addrStr.reserve(INET6_ADDRSTRLEN);
|
||||
char i {0};
|
||||
char readTo {0};
|
||||
is.get(i);
|
||||
if (i == '[') // we are an IPv6 endpoint
|
||||
readTo = ']';
|
||||
else
|
||||
addrStr+=i;
|
||||
|
||||
Address addr;
|
||||
is >> addr;
|
||||
if (is.fail())
|
||||
return is;
|
||||
while (is && is.rdbuf()->in_avail() > 0 && is.get(i))
|
||||
{
|
||||
// NOTE: There is a legacy data format
|
||||
// that allowed space to be used as address / port separator
|
||||
// so we continue to honor that here by assuming we are at the end
|
||||
// of the address portion if we hit a space (or the separator
|
||||
// we were expecting to see)
|
||||
if (isspace(static_cast<unsigned char>(i)) || (readTo && i == readTo))
|
||||
break;
|
||||
|
||||
if (is.rdbuf()->in_avail()>0)
|
||||
if ((i == '.') ||
|
||||
(i >= '0' && i <= ':') ||
|
||||
(i >= 'a' && i <= 'f') ||
|
||||
(i >= 'A' && i <= 'F'))
|
||||
{
|
||||
char c;
|
||||
is.get(c);
|
||||
if (c != ':')
|
||||
addrStr+=i;
|
||||
|
||||
// don't exceed a reasonable length...
|
||||
if ( addrStr.size() == INET6_ADDRSTRLEN ||
|
||||
(readTo && readTo == ':' && addrStr.size() > 15))
|
||||
{
|
||||
is.unget();
|
||||
endpoint = Endpoint (addr);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
if (! readTo && (i == '.' || i == ':'))
|
||||
{
|
||||
// if we see a dot first, must be IPv4
|
||||
// otherwise must be non-bracketed IPv6
|
||||
readTo = (i == '.') ? ':' : ' ';
|
||||
}
|
||||
}
|
||||
else // invalid char
|
||||
{
|
||||
is.unget();
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
if (readTo == ']' && is.rdbuf()->in_avail() > 0)
|
||||
{
|
||||
is.get(i);
|
||||
if (! (isspace(static_cast<unsigned char>(i)) || i == ':'))
|
||||
{
|
||||
is.unget();
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto addr = Address::from_string(addrStr, ec);
|
||||
if (ec)
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
if (is.rdbuf()->in_avail() > 0)
|
||||
{
|
||||
Port port;
|
||||
is >> port;
|
||||
if (is.fail())
|
||||
return is;
|
||||
|
||||
endpoint = Endpoint (addr, port);
|
||||
return is;
|
||||
}
|
||||
|
||||
else
|
||||
endpoint = Endpoint (addr);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/asio/ip/tcp.hpp> // VFALCO FIX: This include should not be here
|
||||
#include <boost/filesystem.hpp> // VFALCO FIX: This include should not be here
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
@@ -174,8 +173,7 @@ public:
|
||||
std::size_t WORKERS = 0;
|
||||
|
||||
// These override the command line client settings
|
||||
boost::optional<boost::asio::ip::address_v4> rpc_ip;
|
||||
boost::optional<std::uint16_t> rpc_port;
|
||||
boost::optional<beast::IP::Endpoint> rpc_ip;
|
||||
|
||||
std::unordered_set<uint256, beast::uhash<>> features;
|
||||
|
||||
|
||||
@@ -1355,9 +1355,10 @@ rpcClient(std::vector<std::string> const& args,
|
||||
}
|
||||
|
||||
if (config.rpc_ip)
|
||||
setup.client.ip = config.rpc_ip->to_string();
|
||||
if (config.rpc_port)
|
||||
setup.client.port = *config.rpc_port;
|
||||
{
|
||||
setup.client.ip = config.rpc_ip->address().to_string();
|
||||
setup.client.port = config.rpc_ip->port();
|
||||
}
|
||||
|
||||
Json::Value jvParams (Json::arrayValue);
|
||||
|
||||
|
||||
@@ -1048,11 +1048,9 @@ setup_Overlay (BasicConfig const& config)
|
||||
set (ip, "public_ip", section);
|
||||
if (! ip.empty ())
|
||||
{
|
||||
bool valid;
|
||||
std::tie (setup.public_ip, valid) =
|
||||
beast::IP::Address::from_string (ip);
|
||||
if (! valid || ! setup.public_ip.is_v4() ||
|
||||
is_private (setup.public_ip))
|
||||
boost::system::error_code ec;
|
||||
setup.public_ip = beast::IP::Address::from_string (ip, ec);
|
||||
if (ec || beast::IP::is_private (setup.public_ip))
|
||||
Throw<std::runtime_error> ("Configured public IP is invalid");
|
||||
}
|
||||
return setup;
|
||||
|
||||
@@ -1019,8 +1019,43 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMEndpoints> const& m)
|
||||
|
||||
std::vector <PeerFinder::Endpoint> endpoints;
|
||||
|
||||
endpoints.reserve (m->endpoints().size());
|
||||
if (m->endpoints_v2().size())
|
||||
{
|
||||
endpoints.reserve (m->endpoints_v2().size());
|
||||
for (auto const& tm : m->endpoints_v2 ())
|
||||
{
|
||||
// these endpoint strings support ipv4 and ipv6
|
||||
auto result = beast::IP::Endpoint::from_string_checked(tm.endpoint());
|
||||
if (! result.second)
|
||||
{
|
||||
JLOG(p_journal_.error()) <<
|
||||
"failed to parse incoming endpoint: {" <<
|
||||
tm.endpoint() << "}";
|
||||
continue;
|
||||
}
|
||||
|
||||
// If hops == 0, this Endpoint describes the peer we are connected
|
||||
// to -- in that case, we take the remote address seen on the
|
||||
// socket and store that in the IP::Endpoint. If this is the first
|
||||
// time, then we'll verify that their listener can receive incoming
|
||||
// by performing a connectivity test. if hops > 0, then we just
|
||||
// take the address/port we were given
|
||||
|
||||
endpoints.emplace_back(
|
||||
tm.hops() > 0 ?
|
||||
result.first :
|
||||
remote_address_.at_port(result.first.port()),
|
||||
tm.hops());
|
||||
JLOG(p_journal_.trace()) <<
|
||||
"got v2 EP: " << endpoints.back().address <<
|
||||
", hops = " << endpoints.back().hops;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this branch can be removed once the entire network is operating with
|
||||
// endpoint_v2() items (strings)
|
||||
endpoints.reserve (m->endpoints().size());
|
||||
for (int i = 0; i < m->endpoints ().size (); ++i)
|
||||
{
|
||||
PeerFinder::Endpoint endpoint;
|
||||
@@ -1048,8 +1083,11 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMEndpoints> const& m)
|
||||
endpoint.address = remote_address_.at_port (
|
||||
tm.ipv4().ipv4port ());
|
||||
}
|
||||
|
||||
endpoints.push_back (endpoint);
|
||||
JLOG(p_journal_.trace()) <<
|
||||
"got v1 EP: " << endpoints.back().address <<
|
||||
", hops = " << endpoints.back().hops;
|
||||
}
|
||||
}
|
||||
|
||||
if (! endpoints.empty())
|
||||
|
||||
@@ -514,16 +514,24 @@ PeerImp::sendEndpoints (FwdIt first, FwdIt last)
|
||||
for (;first != last; ++first)
|
||||
{
|
||||
auto const& ep = *first;
|
||||
// eventually remove endpoints and just keep endpoints_v2
|
||||
// (once we are sure the entire network understands endpoints_v2)
|
||||
protocol::TMEndpoint& tme (*tm.add_endpoints());
|
||||
if (ep.address.is_v4())
|
||||
tme.mutable_ipv4()->set_ipv4(
|
||||
beast::toNetworkByteOrder (ep.address.to_v4().value));
|
||||
beast::toNetworkByteOrder<std::uint32_t> (
|
||||
ep.address.to_v4().to_ulong()));
|
||||
else
|
||||
tme.mutable_ipv4()->set_ipv4(0);
|
||||
tme.mutable_ipv4()->set_ipv4port (ep.address.port());
|
||||
tme.set_hops (ep.hops);
|
||||
|
||||
// add v2 endpoints (strings)
|
||||
auto& tme2 (*tm.add_endpoints_v2());
|
||||
tme2.set_endpoint(ep.address.to_string());
|
||||
tme2.set_hops (ep.hops);
|
||||
}
|
||||
tm.set_version (1);
|
||||
tm.set_version (2);
|
||||
|
||||
send (std::make_shared <Message> (tm, protocol::mtENDPOINTS));
|
||||
}
|
||||
|
||||
@@ -114,19 +114,14 @@ buildHello (
|
||||
TokenType::NodePublic,
|
||||
app.nodeIdentity().first));
|
||||
h.set_nodeproof (sig.data(), sig.size());
|
||||
// h.set_ipv4port (portNumber); // ignored now
|
||||
h.set_testnet (false);
|
||||
|
||||
if (remote.is_v4())
|
||||
{
|
||||
auto addr = remote.to_v4 ();
|
||||
if (is_public (addr))
|
||||
if (beast::IP::is_public (remote))
|
||||
{
|
||||
// Connection is to a public IP
|
||||
h.set_remote_ip (addr.value);
|
||||
if (public_ip != beast::IP::Address())
|
||||
h.set_local_ip (public_ip.to_v4().value);
|
||||
}
|
||||
h.set_remote_ip_str (remote.to_string());
|
||||
if (! public_ip.is_unspecified())
|
||||
h.set_local_ip_str (public_ip.to_string());
|
||||
}
|
||||
|
||||
// We always advertise ourselves as private in the HELLO message. This
|
||||
@@ -174,13 +169,11 @@ appendHello (boost::beast::http::fields& h,
|
||||
h.insert ("Previous-Ledger", boost::beast::detail::base64_encode (
|
||||
hello.ledgerprevious()));
|
||||
|
||||
if (hello.has_local_ip())
|
||||
h.insert ("Local-IP", beast::IP::to_string (
|
||||
beast::IP::AddressV4(hello.local_ip())));
|
||||
if (hello.has_local_ip_str())
|
||||
h.insert ("Local-IP", hello.local_ip_str());
|
||||
|
||||
if (hello.has_remote_ip())
|
||||
h.insert ("Remote-IP", beast::IP::to_string (
|
||||
beast::IP::AddressV4(hello.remote_ip())));
|
||||
h.insert ("Remote-IP", hello.remote_ip_str());
|
||||
}
|
||||
|
||||
std::vector<ProtocolVersion>
|
||||
@@ -306,14 +299,16 @@ parseHello (bool request, boost::beast::http::fields const& h, beast::Journal jo
|
||||
auto const iter = h.find ("Local-IP");
|
||||
if (iter != h.end())
|
||||
{
|
||||
bool valid;
|
||||
beast::IP::Address address;
|
||||
std::tie (address, valid) =
|
||||
beast::IP::Address::from_string (iter->value().to_string());
|
||||
if (!valid)
|
||||
boost::system::error_code ec;
|
||||
auto address =
|
||||
beast::IP::Address::from_string (iter->value().to_string(), ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(journal.warn()) << "invalid Local-IP: "
|
||||
<< iter->value().to_string();
|
||||
return boost::none;
|
||||
if (address.is_v4())
|
||||
hello.set_local_ip(address.to_v4().value);
|
||||
}
|
||||
hello.set_local_ip_str(address.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,14 +316,16 @@ parseHello (bool request, boost::beast::http::fields const& h, beast::Journal jo
|
||||
auto const iter = h.find ("Remote-IP");
|
||||
if (iter != h.end())
|
||||
{
|
||||
bool valid;
|
||||
beast::IP::Address address;
|
||||
std::tie (address, valid) =
|
||||
beast::IP::Address::from_string (iter->value().to_string());
|
||||
if (!valid)
|
||||
boost::system::error_code ec;
|
||||
auto address =
|
||||
beast::IP::Address::from_string (iter->value().to_string(), ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(journal.warn()) << "invalid Remote-IP: "
|
||||
<< iter->value().to_string();
|
||||
return boost::none;
|
||||
if (address.is_v4())
|
||||
hello.set_remote_ip(address.to_v4().value);
|
||||
}
|
||||
hello.set_remote_ip_str(address.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,34 +409,51 @@ verifyHello (protocol::TMHello const& h,
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
if (h.has_local_ip () &&
|
||||
is_public (remote) &&
|
||||
remote.is_v4 () &&
|
||||
(remote.to_v4().value != h.local_ip ()))
|
||||
if (h.has_local_ip_str () &&
|
||||
is_public (remote))
|
||||
{
|
||||
// Remote asked us to confirm connection is from
|
||||
// correct IP
|
||||
JLOG(journal.info()) <<
|
||||
"Hello: Disconnect: Peer IP is " <<
|
||||
beast::IP::to_string (remote.to_v4())
|
||||
<< " not " <<
|
||||
beast::IP::to_string (beast::IP::AddressV4 (h.local_ip()));
|
||||
boost::system::error_code ec;
|
||||
auto local_ip =
|
||||
beast::IP::Address::from_string (h.local_ip_str(), ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(journal.warn()) << "invalid local-ip: " << h.local_ip_str();
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
if (h.has_remote_ip() && is_public (remote) &&
|
||||
(public_ip != beast::IP::Address()) &&
|
||||
(h.remote_ip() != public_ip.to_v4().value))
|
||||
if (remote.address() != local_ip)
|
||||
{
|
||||
// We know our public IP and peer reports connection
|
||||
// from some other IP
|
||||
// Remote asked us to confirm connection is from correct IP
|
||||
JLOG(journal.info()) <<
|
||||
"Hello: Disconnect: Our IP is " <<
|
||||
beast::IP::to_string (public_ip.to_v4())
|
||||
<< " not " <<
|
||||
beast::IP::to_string (beast::IP::AddressV4 (h.remote_ip()));
|
||||
"Hello: Disconnect: Peer IP is " << remote.address().to_string()
|
||||
<< " not " << local_ip.to_string();
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
if (h.has_remote_ip_str () &&
|
||||
is_public (remote) &&
|
||||
(! beast::IP::is_unspecified(public_ip)))
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto remote_ip =
|
||||
beast::IP::Address::from_string (h.remote_ip_str(), ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(journal.warn()) << "invalid remote-ip: " << h.remote_ip_str();
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
if (remote_ip != public_ip)
|
||||
{
|
||||
// We know our public IP and peer reports connection from some
|
||||
// other IP
|
||||
JLOG(journal.info()) <<
|
||||
"Hello: Disconnect: Our IP is " << public_ip.to_string()
|
||||
<< " not " << remote_ip.to_string();
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@@ -618,8 +618,15 @@ public:
|
||||
{
|
||||
Endpoint ep;
|
||||
ep.hops = 0;
|
||||
// we use the unspecified (0) address here because the value is
|
||||
// irrelevant to recipients. When peers receive an endpoint
|
||||
// with 0 hops, they use the socket remote_addr instead of the
|
||||
// value in the message. Furthermore, since the address value
|
||||
// is ignored, the type/version (ipv4 vs ipv6) doesn't matter
|
||||
// either. ipv6 has a slightly more compact string
|
||||
// representation of 0, so use that for self entries.
|
||||
ep.address = beast::IP::Endpoint (
|
||||
beast::IP::AddressV4 ()).at_port (
|
||||
beast::IP::AddressV6 ()).at_port (
|
||||
config_.listeningPort);
|
||||
for (auto& t : targets)
|
||||
t.insert (ep);
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
{
|
||||
beast::IP::Endpoint ep (beast::IP::Endpoint::from_string (m_strings [i]));
|
||||
if (is_unspecified (ep))
|
||||
ep = beast::IP::Endpoint::from_string_altform (m_strings [i]);
|
||||
ep = beast::IP::Endpoint::from_string (m_strings [i]);
|
||||
if (! is_unspecified (ep))
|
||||
results.addresses.push_back (ep);
|
||||
}
|
||||
|
||||
@@ -89,15 +89,17 @@ message TMHello
|
||||
required bytes nodeProof = 4;
|
||||
optional string fullVersion = 5;
|
||||
optional uint64 netTime = 6;
|
||||
optional uint32 ipv4Port = 7;
|
||||
optional uint32 ipv4Port = 7; // NOT USED
|
||||
optional uint32 ledgerIndex = 8;
|
||||
optional bytes ledgerClosed = 9; // our last closed ledger
|
||||
optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger
|
||||
optional bool nodePrivate = 11; // Request to not forward IP.
|
||||
optional TMProofWork proofOfWork = 12; // request/provide proof of work
|
||||
optional bool testNet = 13; // Running as testnet.
|
||||
optional uint32 local_ip = 14; // our public IP
|
||||
optional uint32 remote_ip = 15; // IP we see connection from
|
||||
optional uint32 local_ip = 14; // NOT USED -- our public IP
|
||||
optional uint32 remote_ip = 15; // NOT USED -- IP we see connection from
|
||||
optional string local_ip_str = 16; // our public IP
|
||||
optional string remote_ip_str = 17; // IP we see connection from
|
||||
}
|
||||
|
||||
// The status of a node in our cluster
|
||||
@@ -234,6 +236,7 @@ message TMIPv4Endpoint
|
||||
required uint32 ipv4Port = 2;
|
||||
}
|
||||
|
||||
// this message is obsolete/no longer procesed
|
||||
message TMPeers
|
||||
{
|
||||
repeated TMIPv4Endpoint nodes = 1;
|
||||
@@ -254,6 +257,15 @@ message TMEndpoints
|
||||
required uint32 version = 1;
|
||||
|
||||
repeated TMEndpoint endpoints = 2;
|
||||
|
||||
// An update to the Endpoint type that uses a string
|
||||
// to represent endpoints, thus allowing ipv6 or ipv4 addresses
|
||||
message TMEndpointv2
|
||||
{
|
||||
required string endpoint = 1;
|
||||
required uint32 hops = 2;
|
||||
}
|
||||
repeated TMEndpointv2 endpoints_v2 = 3;
|
||||
};
|
||||
|
||||
message TMIndexedObject
|
||||
|
||||
@@ -41,7 +41,7 @@ ipAllowed (beast::IP::Address const& remoteIp,
|
||||
std::vector<beast::IP::Address> const& adminIp)
|
||||
{
|
||||
return std::find_if (adminIp.begin (), adminIp.end (),
|
||||
[&remoteIp](beast::IP::Address const& ip) { return ip.is_any () ||
|
||||
[&remoteIp](beast::IP::Address const& ip) { return ip.is_unspecified () ||
|
||||
ip == remoteIp; }) != adminIp.end ();
|
||||
}
|
||||
|
||||
|
||||
@@ -1041,10 +1041,11 @@ setup_Client (ServerHandler::Setup& setup)
|
||||
return;
|
||||
setup.client.secure =
|
||||
iter->protocol.count("https") > 0;
|
||||
setup.client.ip = iter->ip.to_string();
|
||||
setup.client.ip =
|
||||
beast::IP::is_unspecified(iter->ip) ?
|
||||
// VFALCO HACK! to make localhost work
|
||||
if (setup.client.ip == "0.0.0.0")
|
||||
setup.client.ip = "127.0.0.1";
|
||||
(iter->ip.is_v6() ? "::1" : "127.0.0.1") :
|
||||
iter->ip.to_string();
|
||||
setup.client.port = iter->port;
|
||||
setup.client.user = iter->user;
|
||||
setup.client.password = iter->password;
|
||||
|
||||
@@ -95,7 +95,7 @@ populate (Section const& section, std::string const& field, std::ostream& log,
|
||||
{
|
||||
if (! allowAllIps)
|
||||
{
|
||||
log << "0.0.0.0 not allowed'" <<
|
||||
log << addr.first.address() << " not allowed'" <<
|
||||
"' for key '" << field << "' in [" <<
|
||||
section.name () << "]";
|
||||
Throw<std::exception> ();
|
||||
@@ -108,8 +108,8 @@ populate (Section const& section, std::string const& field, std::ostream& log,
|
||||
|
||||
if (has_any && ! ips->empty ())
|
||||
{
|
||||
log << "IP specified along with 0.0.0.0 '" << ip <<
|
||||
"' for key '" << field << "' in [" <<
|
||||
log << "IP specified along with " << addr.first.address() <<
|
||||
" '" << ip << "' for key '" << field << "' in [" <<
|
||||
section.name () << "]";
|
||||
Throw<std::exception> ();
|
||||
}
|
||||
|
||||
@@ -172,21 +172,12 @@ private:
|
||||
while (list2.size () < listSize)
|
||||
list2.push_back (randomValidator());
|
||||
|
||||
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
|
||||
// Use ports of 0 to allow OS selection
|
||||
endpoint_type ep1{address_type::from_string("127.0.0.1"), 0};
|
||||
endpoint_type ep2{address_type::from_string("127.0.0.1"), 0};
|
||||
|
||||
auto const sequence = 1;
|
||||
auto const version = 1;
|
||||
NetClock::time_point const expiration =
|
||||
env.timeKeeper().now() + 3600s;
|
||||
|
||||
TrustedPublisherServer server1(
|
||||
ep1,
|
||||
env.app().getIOService(),
|
||||
pubSigningKeys1,
|
||||
manifest1,
|
||||
@@ -196,7 +187,6 @@ private:
|
||||
list1);
|
||||
|
||||
TrustedPublisherServer server2(
|
||||
ep2,
|
||||
env.app().getIOService(),
|
||||
pubSigningKeys2,
|
||||
manifest2,
|
||||
@@ -205,14 +195,13 @@ private:
|
||||
version,
|
||||
list2);
|
||||
|
||||
std::uint16_t const port1 = server1.local_endpoint().port();
|
||||
std::uint16_t const port2 = server2.local_endpoint().port();
|
||||
|
||||
std::stringstream url1, url2;
|
||||
url1 << "http://" << server1.local_endpoint() << "/validators";
|
||||
url2 << "http://" << server2.local_endpoint() << "/validators";
|
||||
|
||||
{
|
||||
// fetch single site
|
||||
std::vector<std::string> cfgSites(
|
||||
{"http://127.0.0.1:" + std::to_string(port1) + "/validators"});
|
||||
std::vector<std::string> cfgSites({ url1.str() });
|
||||
|
||||
auto sites = std::make_unique<ValidatorSite> (
|
||||
env.app().getIOService(), env.app().validators(), journal);
|
||||
@@ -229,9 +218,7 @@ private:
|
||||
}
|
||||
{
|
||||
// fetch multiple sites
|
||||
std::vector<std::string> cfgSites({
|
||||
"http://127.0.0.1:" + std::to_string(port1) + "/validators",
|
||||
"http://127.0.0.1:" + std::to_string(port2) + "/validators"});
|
||||
std::vector<std::string> cfgSites({ url1.str(), url2.str() });
|
||||
|
||||
auto sites = std::make_unique<ValidatorSite> (
|
||||
env.app().getIOService(), env.app().validators(), journal);
|
||||
|
||||
@@ -77,6 +77,9 @@ public:
|
||||
BEAST_EXPECT(parseUrl (pUrl, "Mixed://domain/path"));
|
||||
BEAST_EXPECT(pUrl.scheme == "mixed");
|
||||
BEAST_EXPECT(pUrl.path == "/path");
|
||||
BEAST_EXPECT(parseUrl (pUrl, "scheme://[::1]:123/path"));
|
||||
BEAST_EXPECT(*pUrl.port == 123);
|
||||
BEAST_EXPECT(pUrl.domain == "::1");
|
||||
}
|
||||
|
||||
void testToString ()
|
||||
|
||||
64
src/test/beast/IPEndpointCommon.h
Normal file
64
src/test/beast/IPEndpointCommon.h
Normal file
@@ -0,0 +1,64 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2017 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/basics/random.h>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
inline Endpoint randomEP (bool v4 = true)
|
||||
{
|
||||
using namespace ripple;
|
||||
auto dv4 = []() -> AddressV4::bytes_type {
|
||||
return {{
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX))
|
||||
}};
|
||||
};
|
||||
auto dv6 = []() -> AddressV6::bytes_type {
|
||||
return {{
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX))
|
||||
}};
|
||||
};
|
||||
return Endpoint {
|
||||
v4 ? Address { AddressV4 {dv4()} } : Address{ AddressV6 {dv6()} },
|
||||
rand_int<std::uint16_t>(1, UINT16_MAX)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@
|
||||
#endif
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/beast/net/detail/Parse.h>
|
||||
|
||||
#include <ripple/beast/unit_test.h>
|
||||
|
||||
#include <ripple/basics/random.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <test/beast/IPEndpointCommon.h>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace beast {
|
||||
@@ -37,91 +39,111 @@ namespace IP {
|
||||
class IPEndpoint_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void shouldParseV4 (std::string const& s, std::uint32_t value)
|
||||
void shouldParseAddrV4 (
|
||||
std::string const& s,
|
||||
std::uint32_t value,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
std::pair <AddressV4, bool> const result (
|
||||
AddressV4::from_string (s));
|
||||
|
||||
if (BEAST_EXPECT(result.second))
|
||||
{
|
||||
if (BEAST_EXPECT(result.first.value == value))
|
||||
{
|
||||
BEAST_EXPECT(to_string (result.first) == s);
|
||||
}
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
Address const result {Address::from_string (s, ec)};
|
||||
if (! BEAST_EXPECTS(! ec, ec.message()))
|
||||
return;
|
||||
if (! BEAST_EXPECTS(result.is_v4(), s + " not v4"))
|
||||
return;
|
||||
if (! BEAST_EXPECTS(result.to_v4().to_ulong() == value,
|
||||
s + " value mismatch"))
|
||||
return;
|
||||
BEAST_EXPECTS(result.to_string () == (normal.empty() ? s : normal),
|
||||
s + " as string");
|
||||
}
|
||||
|
||||
void failParseV4 (std::string const& s)
|
||||
void failParseAddr (std::string const& s)
|
||||
{
|
||||
unexpected (AddressV4::from_string (s).second);
|
||||
boost::system::error_code ec;
|
||||
auto a = Address::from_string (s, ec);
|
||||
BEAST_EXPECTS(ec, s + " parses as " + a.to_string());
|
||||
}
|
||||
|
||||
void testAddressV4 ()
|
||||
{
|
||||
testcase ("AddressV4");
|
||||
|
||||
BEAST_EXPECT(AddressV4().value == 0);
|
||||
BEAST_EXPECT(is_unspecified (AddressV4()));
|
||||
BEAST_EXPECT(AddressV4(0x01020304).value == 0x01020304);
|
||||
BEAST_EXPECT(AddressV4(1, 2, 3, 4).value == 0x01020304);
|
||||
BEAST_EXPECT(AddressV4{}.to_ulong() == 0);
|
||||
BEAST_EXPECT(is_unspecified (AddressV4{}));
|
||||
BEAST_EXPECT(AddressV4{0x01020304}.to_ulong() == 0x01020304);
|
||||
AddressV4::bytes_type d = {{1,2,3,4}};
|
||||
BEAST_EXPECT(AddressV4{d}.to_ulong() == 0x01020304);
|
||||
|
||||
unexpected (is_unspecified (AddressV4(1, 2, 3, 4)));
|
||||
unexpected (is_unspecified (AddressV4{d}));
|
||||
|
||||
AddressV4 const v1 (1);
|
||||
BEAST_EXPECT(AddressV4(v1).value == 1);
|
||||
AddressV4 const v1 {1};
|
||||
BEAST_EXPECT(AddressV4{v1}.to_ulong() == 1);
|
||||
|
||||
{
|
||||
AddressV4 v;
|
||||
v = v1;
|
||||
BEAST_EXPECT(v.value == v1.value);
|
||||
BEAST_EXPECT(v.to_ulong() == v1.to_ulong());
|
||||
}
|
||||
|
||||
{
|
||||
AddressV4 v;
|
||||
v [0] = 1;
|
||||
v [1] = 2;
|
||||
v [2] = 3;
|
||||
v [3] = 4;
|
||||
BEAST_EXPECT(v.value == 0x01020304);
|
||||
auto d = v.to_bytes();
|
||||
d[0] = 1;
|
||||
d[1] = 2;
|
||||
d[2] = 3;
|
||||
d[3] = 4;
|
||||
v = AddressV4{d};
|
||||
BEAST_EXPECT(v.to_ulong() == 0x01020304);
|
||||
}
|
||||
|
||||
BEAST_EXPECT(to_string (AddressV4(0x01020304)) == "1.2.3.4");
|
||||
BEAST_EXPECT(AddressV4(0x01020304).to_string() == "1.2.3.4");
|
||||
|
||||
shouldParseV4 ("1.2.3.4", 0x01020304);
|
||||
shouldParseV4 ("255.255.255.255", 0xffffffff);
|
||||
shouldParseV4 ("0.0.0.0", 0);
|
||||
shouldParseAddrV4 ("1.2.3.4", 0x01020304);
|
||||
shouldParseAddrV4 ("255.255.255.255", 0xffffffff);
|
||||
shouldParseAddrV4 ("0.0.0.0", 0);
|
||||
|
||||
failParseV4 (".");
|
||||
failParseV4 ("..");
|
||||
failParseV4 ("...");
|
||||
failParseV4 ("....");
|
||||
failParseV4 ("1");
|
||||
failParseV4 ("1.");
|
||||
failParseV4 ("1.2");
|
||||
failParseV4 ("1.2.");
|
||||
failParseV4 ("1.2.3");
|
||||
failParseV4 ("1.2.3.");
|
||||
failParseV4 ("256.0.0.0");
|
||||
failParseV4 ("-1.2.3.4");
|
||||
failParseAddr (".");
|
||||
failParseAddr ("..");
|
||||
failParseAddr ("...");
|
||||
failParseAddr ("....");
|
||||
#if BOOST_OS_WINDOWS
|
||||
// WINDOWS bug in asio - I don't think these should parse
|
||||
// at all, and in-fact they do not on mac/linux
|
||||
shouldParseAddrV4 ("1", 0x00000001, "0.0.0.1");
|
||||
shouldParseAddrV4 ("1.2", 0x01000002, "1.0.0.2");
|
||||
shouldParseAddrV4 ("1.2.3", 0x01020003, "1.2.0.3");
|
||||
#else
|
||||
failParseAddr ("1");
|
||||
failParseAddr ("1.2");
|
||||
failParseAddr ("1.2.3");
|
||||
#endif
|
||||
failParseAddr ("1.");
|
||||
failParseAddr ("1.2.");
|
||||
failParseAddr ("1.2.3.");
|
||||
failParseAddr ("256.0.0.0");
|
||||
failParseAddr ("-1.2.3.4");
|
||||
}
|
||||
|
||||
void testAddressV4Proxy ()
|
||||
{
|
||||
testcase ("AddressV4::Proxy");
|
||||
testcase ("AddressV4::Bytes");
|
||||
|
||||
AddressV4 v4 (10, 0, 0, 1);
|
||||
BEAST_EXPECT(v4[0]==10);
|
||||
BEAST_EXPECT(v4[1]==0);
|
||||
BEAST_EXPECT(v4[2]==0);
|
||||
BEAST_EXPECT(v4[3]==1);
|
||||
AddressV4::bytes_type d1 = {{10,0,0,1}};
|
||||
AddressV4 v4 {d1};
|
||||
BEAST_EXPECT(v4.to_bytes()[0]==10);
|
||||
BEAST_EXPECT(v4.to_bytes()[1]==0);
|
||||
BEAST_EXPECT(v4.to_bytes()[2]==0);
|
||||
BEAST_EXPECT(v4.to_bytes()[3]==1);
|
||||
|
||||
BEAST_EXPECT((~((0xff)<<16)) == 0xff00ffff);
|
||||
|
||||
v4[1] = 10;
|
||||
BEAST_EXPECT(v4[0]==10);
|
||||
BEAST_EXPECT(v4[1]==10);
|
||||
BEAST_EXPECT(v4[2]==0);
|
||||
BEAST_EXPECT(v4[3]==1);
|
||||
auto d2 = v4.to_bytes();
|
||||
d2[1] = 10;
|
||||
v4 = AddressV4{d2};
|
||||
BEAST_EXPECT(v4.to_bytes()[0]==10);
|
||||
BEAST_EXPECT(v4.to_bytes()[1]==10);
|
||||
BEAST_EXPECT(v4.to_bytes()[2]==0);
|
||||
BEAST_EXPECT(v4.to_bytes()[3]==1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -130,76 +152,160 @@ public:
|
||||
{
|
||||
testcase ("Address");
|
||||
|
||||
std::pair <Address, bool> result (
|
||||
Address::from_string ("1.2.3.4"));
|
||||
BEAST_EXPECT(result.second);
|
||||
if (BEAST_EXPECT(result.first.is_v4 ()))
|
||||
BEAST_EXPECT(result.first.to_v4() == AddressV4 (1, 2, 3, 4));
|
||||
boost::system::error_code ec;
|
||||
Address result {Address::from_string ("1.2.3.4", ec)};
|
||||
AddressV4::bytes_type d = {{1,2,3,4}};
|
||||
BEAST_EXPECT(! ec);
|
||||
BEAST_EXPECT(
|
||||
result.is_v4 () &&
|
||||
result.to_v4() == AddressV4{d});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void shouldParseEPV4 (
|
||||
std::string const& s,
|
||||
AddressV4::bytes_type const& value,
|
||||
std::uint16_t p,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
auto result {Endpoint::from_string_checked (s)};
|
||||
if (! BEAST_EXPECT(result.second))
|
||||
return;
|
||||
if (! BEAST_EXPECT(result.first.address().is_v4 ()))
|
||||
return;
|
||||
if (! BEAST_EXPECT(result.first.address().to_v4() == AddressV4 {value}))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(result.first.port() == p);
|
||||
BEAST_EXPECT(to_string (result.first) == (normal.empty() ? s : normal));
|
||||
}
|
||||
|
||||
void shouldParseEPV6 (
|
||||
std::string const& s,
|
||||
AddressV6::bytes_type const& value,
|
||||
std::uint16_t p,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
auto result {Endpoint::from_string_checked (s)};
|
||||
if (! BEAST_EXPECT(result.second))
|
||||
return;
|
||||
if (! BEAST_EXPECT(result.first.address().is_v6 ()))
|
||||
return;
|
||||
if (! BEAST_EXPECT(result.first.address().to_v6() == AddressV6 {value}))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(result.first.port() == p);
|
||||
BEAST_EXPECT(to_string (result.first) == (normal.empty() ? s : normal));
|
||||
}
|
||||
|
||||
void failParseEP (std::string s)
|
||||
{
|
||||
auto a1 = Endpoint::from_string(s);
|
||||
BEAST_EXPECTS(is_unspecified (a1), s + " parses as " + a1.to_string());
|
||||
|
||||
auto a2 = Endpoint::from_string(s);
|
||||
BEAST_EXPECTS(is_unspecified (a2), s + " parses as " + a2.to_string());
|
||||
|
||||
boost::replace_last(s, ":", " ");
|
||||
auto a3 = Endpoint::from_string(s);
|
||||
BEAST_EXPECTS(is_unspecified (a3), s + " parses as " + a3.to_string());
|
||||
}
|
||||
|
||||
void testEndpoint ()
|
||||
{
|
||||
testcase ("Endpoint");
|
||||
|
||||
{
|
||||
std::pair <Endpoint, bool> result (
|
||||
Endpoint::from_string_checked ("1.2.3.4"));
|
||||
BEAST_EXPECT(result.second);
|
||||
if (BEAST_EXPECT(result.first.address().is_v4 ()))
|
||||
{
|
||||
BEAST_EXPECT(result.first.address().to_v4() ==
|
||||
AddressV4 (1, 2, 3, 4));
|
||||
BEAST_EXPECT(result.first.port() == 0);
|
||||
BEAST_EXPECT(to_string (result.first) == "1.2.3.4");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::pair <Endpoint, bool> result (
|
||||
Endpoint::from_string_checked ("1.2.3.4:5"));
|
||||
BEAST_EXPECT(result.second);
|
||||
if (BEAST_EXPECT(result.first.address().is_v4 ()))
|
||||
{
|
||||
BEAST_EXPECT(result.first.address().to_v4() ==
|
||||
AddressV4 (1, 2, 3, 4));
|
||||
BEAST_EXPECT(result.first.port() == 5);
|
||||
BEAST_EXPECT(to_string (result.first) == "1.2.3.4:5");
|
||||
}
|
||||
}
|
||||
shouldParseEPV4("1.2.3.4", {{1,2,3,4}}, 0);
|
||||
shouldParseEPV4("1.2.3.4:5", {{1,2,3,4}}, 5);
|
||||
shouldParseEPV4("1.2.3.4 5", {{1,2,3,4}}, 5, "1.2.3.4:5");
|
||||
shouldParseEPV6(
|
||||
"2001:db8:a0b:12f0::1",
|
||||
{{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
0);
|
||||
shouldParseEPV6(
|
||||
"[2001:db8:a0b:12f0::1]:8",
|
||||
{{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
8);
|
||||
shouldParseEPV6(
|
||||
"[2001:2002:2003:2004:2005:2006:2007:2008]:65535",
|
||||
{{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
|
||||
65535);
|
||||
shouldParseEPV6(
|
||||
"2001:2002:2003:2004:2005:2006:2007:2008 65535",
|
||||
{{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
|
||||
65535,
|
||||
"[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
|
||||
|
||||
Endpoint ep;
|
||||
|
||||
ep = Endpoint (AddressV4 (127,0,0,1), 80);
|
||||
AddressV4::bytes_type d = {{127,0,0,1}};
|
||||
ep = Endpoint (AddressV4 {d}, 80);
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(! is_public (ep));
|
||||
BEAST_EXPECT( is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT( is_loopback (ep));
|
||||
BEAST_EXPECT(to_string (ep) == "127.0.0.1:80");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d}), 80);
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(! is_public (ep));
|
||||
BEAST_EXPECT( is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep)); //mapped loopback is not a loopback
|
||||
BEAST_EXPECTS(to_string (ep) == "[::ffff:127.0.0.1]:80", to_string (ep));
|
||||
|
||||
ep = Endpoint (AddressV4 (10,0,0,1));
|
||||
BEAST_EXPECT(AddressV4::get_class (ep.to_v4()) == 'A');
|
||||
d = {{10,0,0,1}};
|
||||
ep = Endpoint (AddressV4 {d});
|
||||
BEAST_EXPECT(get_class (ep.to_v4()) == 'A');
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(! is_public (ep));
|
||||
BEAST_EXPECT( is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep));
|
||||
BEAST_EXPECT(to_string (ep) == "10.0.0.1");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d}));
|
||||
BEAST_EXPECT(get_class (ep.to_v6().to_v4()) == 'A');
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(! is_public (ep));
|
||||
BEAST_EXPECT( is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep));
|
||||
BEAST_EXPECTS(to_string (ep) == "::ffff:10.0.0.1", to_string(ep));
|
||||
|
||||
ep = Endpoint (AddressV4 (166,78,151,147));
|
||||
d = {{166,78,151,147}};
|
||||
ep = Endpoint (AddressV4 {d});
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT( is_public (ep));
|
||||
BEAST_EXPECT(! is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep));
|
||||
BEAST_EXPECT(to_string (ep) == "166.78.151.147");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d}));
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT( is_public (ep));
|
||||
BEAST_EXPECT(! is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep));
|
||||
BEAST_EXPECTS(to_string (ep) == "::ffff:166.78.151.147", to_string(ep));
|
||||
|
||||
// a private IPv6
|
||||
AddressV6::bytes_type d2 = {{253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}};
|
||||
ep = Endpoint (AddressV6 {d2});
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(! is_public (ep));
|
||||
BEAST_EXPECT( is_private (ep));
|
||||
BEAST_EXPECT(! is_multicast (ep));
|
||||
BEAST_EXPECT(! is_loopback (ep));
|
||||
BEAST_EXPECTS(to_string (ep) == "fd00::1", to_string(ep));
|
||||
|
||||
{
|
||||
ep = Endpoint::from_string ("192.0.2.112");
|
||||
BEAST_EXPECT(! is_unspecified (ep));
|
||||
BEAST_EXPECT(ep == Endpoint::from_string_altform ("192.0.2.112"));
|
||||
BEAST_EXPECT(ep == Endpoint::from_string ("192.0.2.112"));
|
||||
|
||||
auto const ep1 = Endpoint::from_string ("192.0.2.112:2016");
|
||||
BEAST_EXPECT(! is_unspecified (ep1));
|
||||
@@ -207,21 +313,21 @@ public:
|
||||
BEAST_EXPECT(ep1.port() == 2016);
|
||||
|
||||
auto const ep2 =
|
||||
Endpoint::from_string_altform ("192.0.2.112:2016");
|
||||
Endpoint::from_string ("192.0.2.112:2016");
|
||||
BEAST_EXPECT(! is_unspecified (ep2));
|
||||
BEAST_EXPECT(ep.address() == ep2.address());
|
||||
BEAST_EXPECT(ep2.port() == 2016);
|
||||
BEAST_EXPECT(ep1 == ep2);
|
||||
|
||||
auto const ep3 =
|
||||
Endpoint::from_string_altform ("192.0.2.112 2016");
|
||||
Endpoint::from_string ("192.0.2.112 2016");
|
||||
BEAST_EXPECT(! is_unspecified (ep3));
|
||||
BEAST_EXPECT(ep.address() == ep3.address());
|
||||
BEAST_EXPECT(ep3.port() == 2016);
|
||||
BEAST_EXPECT(ep2 == ep3);
|
||||
|
||||
auto const ep4 =
|
||||
Endpoint::from_string_altform ("192.0.2.112 2016");
|
||||
Endpoint::from_string ("192.0.2.112 2016");
|
||||
BEAST_EXPECT(! is_unspecified (ep4));
|
||||
BEAST_EXPECT(ep.address() == ep4.address());
|
||||
BEAST_EXPECT(ep4.port() == 2016);
|
||||
@@ -232,87 +338,79 @@ public:
|
||||
BEAST_EXPECT(to_string(ep1) == to_string(ep4));
|
||||
}
|
||||
|
||||
{
|
||||
ep = Endpoint::from_string("[::]:2017");
|
||||
BEAST_EXPECT(is_unspecified (ep));
|
||||
BEAST_EXPECT(ep.port() == 2017);
|
||||
BEAST_EXPECT(ep.address() == AddressV6{});
|
||||
}
|
||||
|
||||
// Failures:
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string ("192.0.2.112:port")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform ("192.0.2.112:port")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform ("192.0.2.112 port")));
|
||||
failParseEP ("192.0.2.112:port");
|
||||
failParseEP ("ip:port");
|
||||
failParseEP ("");
|
||||
failParseEP ("1.2.3.256");
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string ("ip:port")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform ("ip:port")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform ("ip port")));
|
||||
#if BOOST_OS_WINDOWS
|
||||
// windows asio bugs...false positives
|
||||
shouldParseEPV4 ("255", {{0,0,0,255}}, 0, "0.0.0.255");
|
||||
shouldParseEPV4 ("512", {{0,0,2,0}}, 0, "0.0.2.0");
|
||||
shouldParseEPV4 ("1.2.3:80", {{1,2,0,3}}, 80, "1.2.0.3:80");
|
||||
#else
|
||||
failParseEP ("255");
|
||||
failParseEP ("512");
|
||||
failParseEP ("1.2.3:80");
|
||||
#endif
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("")));
|
||||
failParseEP ("1.2.3.4:65536");
|
||||
failParseEP ("1.2.3.4:89119");
|
||||
failParseEP ("1.2.3:89119");
|
||||
failParseEP ("[::1]:89119");
|
||||
failParseEP ("[::az]:1");
|
||||
failParseEP ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
|
||||
failParseEP ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
|
||||
failParseEP ("abcdef:12345");
|
||||
failParseEP ("[abcdef]:12345");
|
||||
failParseEP ("foo.org 12345");
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("255")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("255")));
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("512")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("512")));
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("1.2.3.256")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3.256")));
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("1.2.3:80")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3:80")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3 80")));
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("1.2.3.4:65536")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3:65536")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3 65536")));
|
||||
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string("1.2.3.4:89119")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3:89119")));
|
||||
BEAST_EXPECT(is_unspecified (
|
||||
Endpoint::from_string_altform("1.2.3 89119")));
|
||||
// test with hashed container
|
||||
std::unordered_set<Endpoint> eps;
|
||||
constexpr auto items {100};
|
||||
float max_lf {0};
|
||||
for (auto i = 0; i < items; ++i)
|
||||
{
|
||||
eps.insert(randomEP(ripple::rand_int(0,1) == 1));
|
||||
max_lf = std::max(max_lf, eps.load_factor());
|
||||
}
|
||||
BEAST_EXPECT(eps.bucket_count() >= items);
|
||||
BEAST_EXPECT(max_lf > 0.90);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
bool parse (char const* text, T& t)
|
||||
bool parse (std::string const& text, T& t)
|
||||
{
|
||||
std::string input (text);
|
||||
std::istringstream stream (input);
|
||||
std::istringstream stream {text};
|
||||
stream >> t;
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void shouldPass (char const* text)
|
||||
void shouldPass (std::string const& text, std::string const& normal="")
|
||||
{
|
||||
using namespace std::literals;
|
||||
T t;
|
||||
BEAST_EXPECT(parse (text, t));
|
||||
BEAST_EXPECT(to_string (t) == std::string (text));
|
||||
BEAST_EXPECTS(to_string (t) == (normal.empty() ? text : normal),
|
||||
"string mismatch for "s + text);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void shouldFail (char const* text)
|
||||
void shouldFail (std::string const& text)
|
||||
{
|
||||
T t;
|
||||
unexpected (parse (text, t));
|
||||
unexpected (parse (text, t), text + " should not parse");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -325,14 +423,30 @@ public:
|
||||
shouldPass <T> ("168.127.149.132");
|
||||
shouldPass <T> ("168.127.149.132:80");
|
||||
shouldPass <T> ("168.127.149.132:54321");
|
||||
shouldPass <T> ("2001:db8:a0b:12f0::1");
|
||||
shouldPass <T> ("[2001:db8:a0b:12f0::1]:8");
|
||||
shouldPass <T> ("2001:db8:a0b:12f0::1 8", "[2001:db8:a0b:12f0::1]:8");
|
||||
shouldPass <T> ("[::1]:8");
|
||||
shouldPass <T> ("[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
|
||||
|
||||
shouldFail <T> ("");
|
||||
shouldFail <T> ("255");
|
||||
shouldFail <T> ("512");
|
||||
shouldFail <T> ("1.2.3.256");
|
||||
shouldFail <T> ("");
|
||||
#if BOOST_OS_WINDOWS
|
||||
// windows asio bugs...false positives
|
||||
shouldPass <T> ("512", "0.0.2.0");
|
||||
shouldPass <T> ("255", "0.0.0.255");
|
||||
shouldPass <T> ("1.2.3:80", "1.2.0.3:80");
|
||||
#else
|
||||
shouldFail <T> ("512");
|
||||
shouldFail <T> ("255");
|
||||
shouldFail <T> ("1.2.3:80");
|
||||
#endif
|
||||
shouldFail <T> ("1.2.3:65536");
|
||||
shouldFail <T> ("1.2.3:72131");
|
||||
shouldFail <T> ("[::1]:89119");
|
||||
shouldFail <T> ("[::az]:1");
|
||||
shouldFail <T> ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
|
||||
shouldFail <T> ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
|
||||
}
|
||||
|
||||
void run () override
|
||||
@@ -341,7 +455,6 @@ public:
|
||||
testAddressV4Proxy();
|
||||
testAddress ();
|
||||
testEndpoint ();
|
||||
|
||||
testParse <Endpoint> ("Parse Endpoint");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <ripple/protocol/Sign.h>
|
||||
#include <ripple/basics/strHex.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/beast/core/detail/base64.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
@@ -55,7 +56,6 @@ public:
|
||||
};
|
||||
|
||||
TrustedPublisherServer(
|
||||
endpoint_type const& ep,
|
||||
boost::asio::io_service& ios,
|
||||
std::pair<PublicKey, SecretKey> keys,
|
||||
std::string const& manifest,
|
||||
@@ -65,6 +65,9 @@ public:
|
||||
std::vector<Validator> const& validators)
|
||||
: sock_(ios), acceptor_(ios)
|
||||
{
|
||||
endpoint_type const& ep {
|
||||
beast::IP::Address::from_string (ripple::test::getEnvLocalhostAddr()),
|
||||
0}; // 0 means let OS pick the port based on what's available
|
||||
std::string data = "{\"sequence\":" + std::to_string(sequence) +
|
||||
",\"expiration\":" +
|
||||
std::to_string(expiration.time_since_epoch().count()) +
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
extern std::atomic<bool> envUseIPv4;
|
||||
|
||||
inline
|
||||
const char *
|
||||
getEnvLocalhostAddr()
|
||||
{
|
||||
return envUseIPv4 ? "127.0.0.1" : "::1";
|
||||
}
|
||||
|
||||
/// @brief initializes a config object for use with jtx::Env
|
||||
///
|
||||
/// @param config the configuration object to be initialized
|
||||
|
||||
@@ -49,9 +49,9 @@ class JSONRPCClient : public AbstractClient
|
||||
parse_Port(pp, cfg[name], log);
|
||||
if(pp.protocol.count("http") == 0)
|
||||
continue;
|
||||
using boost::asio::ip::address_v4;
|
||||
if(*pp.ip == address_v4{0x00000000})
|
||||
*pp.ip = address_v4{0x7f000001};
|
||||
using namespace boost::asio::ip;
|
||||
if(pp.ip && pp.ip->is_unspecified())
|
||||
*pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()};
|
||||
return { *pp.ip, *pp.port };
|
||||
}
|
||||
Throw<std::runtime_error>("Missing HTTP port");
|
||||
|
||||
@@ -64,9 +64,9 @@ class WSClientImpl : public WSClient
|
||||
parse_Port(pp, cfg[name], log);
|
||||
if(pp.protocol.count(ps) == 0)
|
||||
continue;
|
||||
using boost::asio::ip::address_v4;
|
||||
if(*pp.ip == address_v4{0x00000000})
|
||||
*pp.ip = address_v4{0x7f000001};
|
||||
using namespace boost::asio::ip;
|
||||
if(pp.ip && pp.ip->is_unspecified())
|
||||
*pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()};
|
||||
return { *pp.ip, *pp.port };
|
||||
}
|
||||
Throw<std::runtime_error>("Missing WebSocket port");
|
||||
|
||||
@@ -30,6 +30,8 @@ void incPorts()
|
||||
port_base += 3;
|
||||
}
|
||||
|
||||
std::atomic<bool> envUseIPv4 {false};
|
||||
|
||||
void
|
||||
setupConfigForUnitTests (Config& cfg)
|
||||
{
|
||||
@@ -43,19 +45,21 @@ setupConfigForUnitTests (Config& cfg)
|
||||
cfg.legacy("database_path", "");
|
||||
cfg.setupControl(true, true, true);
|
||||
cfg["server"].append("port_peer");
|
||||
cfg["port_peer"].set("ip", "127.0.0.1");
|
||||
cfg["port_peer"].set("ip", getEnvLocalhostAddr());
|
||||
cfg["port_peer"].set("port", port_peer);
|
||||
cfg["port_peer"].set("protocol", "peer");
|
||||
|
||||
cfg["server"].append("port_rpc");
|
||||
cfg["port_rpc"].set("ip", "127.0.0.1");
|
||||
cfg["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
cfg["port_rpc"].set("admin", getEnvLocalhostAddr());
|
||||
cfg["port_rpc"].set("port", port_rpc);
|
||||
cfg["port_rpc"].set("protocol", "http,ws2");
|
||||
cfg["port_rpc"].set("admin", "127.0.0.1");
|
||||
|
||||
cfg["server"].append("port_ws");
|
||||
cfg["port_ws"].set("ip", "127.0.0.1");
|
||||
cfg["port_ws"].set("ip", getEnvLocalhostAddr());
|
||||
cfg["port_ws"].set("admin", getEnvLocalhostAddr());
|
||||
cfg["port_ws"].set("port", port_ws);
|
||||
cfg["port_ws"].set("protocol", "ws");
|
||||
cfg["port_ws"].set("admin", "127.0.0.1");
|
||||
}
|
||||
|
||||
namespace jtx {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <ripple/basics/make_SSLContext.h>
|
||||
#include <ripple/beast/core/CurrentThreadName.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
@@ -183,7 +184,8 @@ private:
|
||||
, server_(server)
|
||||
, test_(server_.test_)
|
||||
, acceptor_(test_.io_service_,
|
||||
endpoint_type(address_type::from_string("127.0.0.1"), 0))
|
||||
endpoint_type(beast::IP::Address::from_string(
|
||||
test::getEnvLocalhostAddr()), 0))
|
||||
, socket_(test_.io_service_)
|
||||
, strand_(socket_.get_io_service())
|
||||
{
|
||||
|
||||
@@ -21,10 +21,18 @@
|
||||
#include <ripple/peerfinder/impl/Livecache.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/beast/clock/manual_clock.h>
|
||||
#include <test/beast/IPEndpointCommon.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace PeerFinder {
|
||||
|
||||
bool operator== (Endpoint const& a, Endpoint const& b)
|
||||
{
|
||||
return (a.hops == b.hops &&
|
||||
a.address == b.address);
|
||||
}
|
||||
|
||||
class Livecache_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
@@ -32,38 +40,178 @@ public:
|
||||
|
||||
// Add the address as an endpoint
|
||||
template <class C>
|
||||
void add (std::uint32_t index, std::uint16_t port, C& c)
|
||||
inline void add (beast::IP::Endpoint ep, C& c, int hops = 0)
|
||||
{
|
||||
Endpoint ep;
|
||||
ep.hops = 0;
|
||||
ep.address = beast::IP::Endpoint (
|
||||
beast::IP::AddressV4 (index), port);
|
||||
c.insert (ep);
|
||||
Endpoint cep {ep, hops};
|
||||
c.insert (cep);
|
||||
}
|
||||
|
||||
void testFetch ()
|
||||
void testBasicInsert ()
|
||||
{
|
||||
testcase ("Basic Insert");
|
||||
Livecache <> c (m_clock, beast::Journal());
|
||||
BEAST_EXPECT(c.empty());
|
||||
|
||||
for (auto i = 0; i < 10; ++i)
|
||||
add(beast::IP::randomEP(true), c);
|
||||
|
||||
BEAST_EXPECT(! c.empty());
|
||||
BEAST_EXPECT(c.size() == 10);
|
||||
|
||||
for (auto i = 0; i < 10; ++i)
|
||||
add(beast::IP::randomEP(false), c);
|
||||
|
||||
BEAST_EXPECT(! c.empty());
|
||||
BEAST_EXPECT(c.size() == 20);
|
||||
}
|
||||
|
||||
void testInsertUpdate ()
|
||||
{
|
||||
testcase ("Insert/Update");
|
||||
Livecache <> c (m_clock, beast::Journal());
|
||||
|
||||
add (1, 1, c);
|
||||
add (2, 1, c);
|
||||
add (3, 1, c);
|
||||
add (4, 1, c);
|
||||
add (4, 2, c);
|
||||
add (4, 3, c);
|
||||
add (5, 1, c);
|
||||
add (6, 1, c);
|
||||
add (6, 2, c);
|
||||
add (7, 1, c);
|
||||
auto ep1 = Endpoint {beast::IP::randomEP(), 2};
|
||||
c.insert(ep1);
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// third position list will contain the entry
|
||||
BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2);
|
||||
|
||||
// VFALCO TODO!
|
||||
auto ep2 = Endpoint {ep1.address, 4};
|
||||
// this will not change the entry has higher hops
|
||||
c.insert(ep2);
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// still in third position list
|
||||
BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2);
|
||||
|
||||
pass();
|
||||
auto ep3 = Endpoint {ep1.address, 2};
|
||||
// this will not change the entry has the same hops as existing
|
||||
c.insert(ep3);
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// still in third position list
|
||||
BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2);
|
||||
|
||||
auto ep4 = Endpoint {ep1.address, 1};
|
||||
c.insert(ep4);
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// now at second position list
|
||||
BEAST_EXPECT((c.hops.begin()+1)->begin()->hops == 1);
|
||||
}
|
||||
|
||||
void testExpire ()
|
||||
{
|
||||
testcase ("Expire");
|
||||
using namespace std::chrono_literals;
|
||||
Livecache <> c (m_clock, beast::Journal());
|
||||
|
||||
auto ep1 = Endpoint {beast::IP::randomEP(), 1};
|
||||
c.insert(ep1);
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
c.expire();
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// verify that advancing to 1 sec before expiration
|
||||
// leaves our entry intact
|
||||
m_clock.advance(Tuning::liveCacheSecondsToLive - 1s);
|
||||
c.expire();
|
||||
BEAST_EXPECT(c.size() == 1);
|
||||
// now advance to the point of expiration
|
||||
m_clock.advance(1s);
|
||||
c.expire();
|
||||
BEAST_EXPECT(c.empty());
|
||||
}
|
||||
|
||||
void testHistogram ()
|
||||
{
|
||||
testcase ("Histogram");
|
||||
constexpr auto num_eps = 40;
|
||||
Livecache <> c (m_clock, beast::Journal());
|
||||
for (auto i = 0; i < num_eps; ++i)
|
||||
add(
|
||||
beast::IP::randomEP(true),
|
||||
c,
|
||||
ripple::rand_int(0, static_cast<int>(Tuning::maxHops + 1)));
|
||||
auto h = c.hops.histogram();
|
||||
if(! BEAST_EXPECT(! h.empty()))
|
||||
return;
|
||||
std::vector <std::string> v;
|
||||
boost::split (v, h, boost::algorithm::is_any_of (","));
|
||||
auto sum = 0;
|
||||
for (auto const& n : v)
|
||||
{
|
||||
auto val = boost::lexical_cast<int>(boost::trim_copy(n));
|
||||
sum += val;
|
||||
BEAST_EXPECT(val >= 0);
|
||||
}
|
||||
BEAST_EXPECT(sum == num_eps);
|
||||
}
|
||||
|
||||
|
||||
void testShuffle ()
|
||||
{
|
||||
testcase ("Shuffle");
|
||||
Livecache <> c (m_clock, beast::Journal());
|
||||
for (auto i = 0; i < 100; ++i)
|
||||
add(
|
||||
beast::IP::randomEP(true),
|
||||
c,
|
||||
ripple::rand_int(0, static_cast<int>(Tuning::maxHops + 1)));
|
||||
|
||||
using at_hop = std::vector <ripple::PeerFinder::Endpoint>;
|
||||
using all_hops = std::array <at_hop, 1 + Tuning::maxHops + 1>;
|
||||
|
||||
auto cmp_EP = [](Endpoint const& a, Endpoint const& b) {
|
||||
return (b.hops < a.hops || (b.hops == a.hops && b.address < a.address));
|
||||
};
|
||||
all_hops before;
|
||||
all_hops before_sorted;
|
||||
for (auto i = std::make_pair(0, c.hops.begin());
|
||||
i.second != c.hops.end(); ++i.first, ++i.second)
|
||||
{
|
||||
std::copy ((*i.second).begin(), (*i.second).end(),
|
||||
std::back_inserter (before[i.first]));
|
||||
std::copy ((*i.second).begin(), (*i.second).end(),
|
||||
std::back_inserter (before_sorted[i.first]));
|
||||
std::sort(
|
||||
before_sorted[i.first].begin(),
|
||||
before_sorted[i.first].end(),
|
||||
cmp_EP);
|
||||
}
|
||||
|
||||
c.hops.shuffle();
|
||||
|
||||
all_hops after;
|
||||
all_hops after_sorted;
|
||||
for (auto i = std::make_pair(0, c.hops.begin());
|
||||
i.second != c.hops.end(); ++i.first, ++i.second)
|
||||
{
|
||||
std::copy ((*i.second).begin(), (*i.second).end(),
|
||||
std::back_inserter (after[i.first]));
|
||||
std::copy ((*i.second).begin(), (*i.second).end(),
|
||||
std::back_inserter (after_sorted[i.first]));
|
||||
std::sort(
|
||||
after_sorted[i.first].begin(),
|
||||
after_sorted[i.first].end(),
|
||||
cmp_EP);
|
||||
}
|
||||
|
||||
// each hop bucket should contain the same items
|
||||
// before and after sort, albeit in different order
|
||||
bool all_match = true;
|
||||
for (auto i = 0; i < before.size(); ++i)
|
||||
{
|
||||
BEAST_EXPECT(before[i].size() == after[i].size());
|
||||
all_match = all_match && (before[i] == after[i]);
|
||||
BEAST_EXPECT(before_sorted[i] == after_sorted[i]);
|
||||
}
|
||||
BEAST_EXPECT(! all_match);
|
||||
}
|
||||
|
||||
void run () override
|
||||
{
|
||||
testFetch ();
|
||||
testBasicInsert ();
|
||||
testInsertUpdate ();
|
||||
testExpire ();
|
||||
testHistogram ();
|
||||
testShuffle ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -63,15 +63,16 @@ public:
|
||||
|
||||
void createGossip (Gossip& gossip)
|
||||
{
|
||||
int const v (10 + rand_int(9));
|
||||
int const n (10 + rand_int(9));
|
||||
std::uint8_t const v (10 + rand_int(9));
|
||||
std::uint8_t const n (10 + rand_int(9));
|
||||
gossip.items.reserve (n);
|
||||
for (int i = 0; i < n; ++i)
|
||||
for (std::uint8_t i = 0; i < n; ++i)
|
||||
{
|
||||
Gossip::Item item;
|
||||
item.balance = 100 + rand_int(499);
|
||||
item.address = beast::IP::Endpoint (
|
||||
beast::IP::AddressV4 (192, 0, 2, v + i));
|
||||
beast::IP::AddressV4::bytes_type d =
|
||||
{{192,0,2,static_cast<std::uint8_t>(v + i)}};
|
||||
item.address = beast::IP::Endpoint { beast::IP::AddressV4 {d} };
|
||||
gossip.items.push_back (item);
|
||||
}
|
||||
}
|
||||
@@ -193,8 +194,8 @@ public:
|
||||
Gossip g;
|
||||
Gossip::Item item;
|
||||
item.balance = 100;
|
||||
item.address = beast::IP::Endpoint (
|
||||
beast::IP::AddressV4 (192, 0, 2, 1));
|
||||
beast::IP::AddressV4::bytes_type d = {{192, 0, 2, 1}};
|
||||
item.address = beast::IP::Endpoint { beast::IP::AddressV4 {d} };
|
||||
g.items.push_back (item);
|
||||
|
||||
logic.importConsumers ("g", g);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <ripple/beast/utility/temp_dir.h>
|
||||
#include <ripple/resource/ResourceManager.h>
|
||||
@@ -265,7 +266,7 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite
|
||||
using namespace std::chrono;
|
||||
using namespace beast::IP;
|
||||
auto c = env.app().getResourceManager()
|
||||
.newInboundEndpoint (Endpoint::from_string ("127.0.0.1"));
|
||||
.newInboundEndpoint (Endpoint::from_string (test::getEnvLocalhostAddr()));
|
||||
if (dropThreshold - c.balance() <= 20)
|
||||
{
|
||||
using clock_type = beast::abstract_clock <steady_clock>;
|
||||
|
||||
@@ -178,8 +178,6 @@ public:
|
||||
testDynamicUNL()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
|
||||
auto toStr = [](PublicKey const& publicKey) {
|
||||
return toBase58(TokenType::NodePublic, publicKey);
|
||||
@@ -208,7 +206,9 @@ public:
|
||||
// Publisher list site unavailable
|
||||
{
|
||||
// Publisher site information
|
||||
std::string siteURI = "http://127.0.0.1:1234/validators";
|
||||
using namespace std::string_literals;
|
||||
std::string siteURI =
|
||||
"http://"s + getEnvLocalhostAddr() + ":1234/validators";
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
@@ -271,9 +271,6 @@ public:
|
||||
{
|
||||
NetClock::time_point const expiration{3600s};
|
||||
|
||||
// 0 port means to use OS port selection
|
||||
endpoint_type ep{address_type::from_string("127.0.0.1"), 0};
|
||||
|
||||
// Manage single thread io_service for server
|
||||
struct Worker : BasicApp
|
||||
{
|
||||
@@ -282,7 +279,6 @@ public:
|
||||
Worker w;
|
||||
|
||||
TrustedPublisherServer server(
|
||||
ep,
|
||||
w.get_io_service(),
|
||||
publisherSigningKeys,
|
||||
manifest,
|
||||
@@ -291,9 +287,9 @@ public:
|
||||
1,
|
||||
validators);
|
||||
|
||||
endpoint_type const & local_ep = server.local_endpoint();
|
||||
std::string siteURI = "http://127.0.0.1:" +
|
||||
std::to_string(local_ep.port()) + "/validators";
|
||||
std::stringstream uri;
|
||||
uri << "http://" << server.local_endpoint() << "/validators";
|
||||
auto siteURI = uri.str();
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
|
||||
@@ -73,10 +73,10 @@ class ServerStatus_test :
|
||||
// which requires an http endpoint to talk to. In the connection
|
||||
// failure test, this endpoint should never be used
|
||||
(*p)["server"].append("port_alt");
|
||||
(*p)["port_alt"].set("ip", "127.0.0.1");
|
||||
(*p)["port_alt"].set("ip", getEnvLocalhostAddr());
|
||||
(*p)["port_alt"].set("port", "8099");
|
||||
(*p)["port_alt"].set("protocol", "http");
|
||||
(*p)["port_alt"].set("admin", "127.0.0.1");
|
||||
(*p)["port_alt"].set("admin", getEnvLocalhostAddr());
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
@@ -283,7 +283,7 @@ public:
|
||||
thread.get_io_service(), journal);
|
||||
std::vector<Port> serverPort(1);
|
||||
serverPort.back().ip =
|
||||
boost::asio::ip::address::from_string ("127.0.0.1"),
|
||||
beast::IP::Address::from_string (getEnvLocalhostAddr()),
|
||||
serverPort.back().port = 0;
|
||||
serverPort.back().protocol.insert("http");
|
||||
auto eps = s->ports (serverPort);
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
thread.get_io_service(), {});
|
||||
std::vector<Port> serverPort(1);
|
||||
serverPort.back().ip =
|
||||
boost::asio::ip::address::from_string ("127.0.0.1"),
|
||||
beast::IP::Address::from_string (getEnvLocalhostAddr()),
|
||||
serverPort.back().port = 0;
|
||||
serverPort.back().protocol.insert("http");
|
||||
s->ports (serverPort);
|
||||
@@ -441,7 +441,7 @@ public:
|
||||
Env env {*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
(*cfg).deprecatedClearSection("port_rpc");
|
||||
(*cfg)["port_rpc"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
@@ -455,7 +455,7 @@ public:
|
||||
Env env {*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
(*cfg).deprecatedClearSection("port_rpc");
|
||||
(*cfg)["port_rpc"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
(*cfg)["port_rpc"].set("port", "0");
|
||||
return cfg;
|
||||
}),
|
||||
@@ -470,7 +470,7 @@ public:
|
||||
Env env {*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
(*cfg).deprecatedClearSection("port_rpc");
|
||||
(*cfg)["port_rpc"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
(*cfg)["port_rpc"].set("port", "8081");
|
||||
(*cfg)["port_rpc"].set("protocol", "");
|
||||
return cfg;
|
||||
@@ -495,17 +495,17 @@ public:
|
||||
ConfigSection::importNodeDatabase ());
|
||||
cfg->legacy("database_path", "");
|
||||
cfg->setupControl(true, true, true);
|
||||
(*cfg)["port_peer"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_peer"].set("ip", getEnvLocalhostAddr());
|
||||
(*cfg)["port_peer"].set("port", "8080");
|
||||
(*cfg)["port_peer"].set("protocol", "peer");
|
||||
(*cfg)["port_rpc"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
(*cfg)["port_rpc"].set("port", "8081");
|
||||
(*cfg)["port_rpc"].set("protocol", "http,ws2");
|
||||
(*cfg)["port_rpc"].set("admin", "127.0.0.1");
|
||||
(*cfg)["port_ws"].set("ip", "127.0.0.1");
|
||||
(*cfg)["port_rpc"].set("admin", getEnvLocalhostAddr());
|
||||
(*cfg)["port_ws"].set("ip", getEnvLocalhostAddr());
|
||||
(*cfg)["port_ws"].set("port", "8082");
|
||||
(*cfg)["port_ws"].set("protocol", "ws");
|
||||
(*cfg)["port_ws"].set("admin", "127.0.0.1");
|
||||
(*cfg)["port_ws"].set("admin", getEnvLocalhostAddr());
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
|
||||
Reference in New Issue
Block a user