Files
xahaud/src/ripple/beast/net/impl/IPEndpoint.cpp
2022-02-07 10:33:02 -08:00

183 lines
4.9 KiB
C++

//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#include <ripple/beast/net/IPEndpoint.h>
#include <boost/algorithm/string.hpp>
namespace beast {
namespace IP {
Endpoint::Endpoint() : m_port(0)
{
}
Endpoint::Endpoint(Address const& addr, Port port) : m_addr(addr), m_port(port)
{
}
std::optional<Endpoint>
Endpoint::from_string_checked(std::string const& s)
{
if (s.size() <= 64)
{
std::stringstream is(boost::trim_copy(s));
Endpoint endpoint;
is >> endpoint;
if (!is.fail() && is.rdbuf()->in_avail() == 0)
return endpoint;
}
return {};
}
Endpoint
Endpoint::from_string(std::string const& s)
{
if (std::optional<Endpoint> const result = from_string_checked(s))
return *result;
return Endpoint{};
}
std::string
Endpoint::to_string() const
{
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;
}
bool
operator==(Endpoint const& lhs, Endpoint const& rhs)
{
return lhs.address() == rhs.address() && lhs.port() == rhs.port();
}
bool
operator<(Endpoint const& lhs, Endpoint const& rhs)
{
if (lhs.address() < rhs.address())
return true;
if (lhs.address() > rhs.address())
return false;
return lhs.port() < rhs.port();
}
//------------------------------------------------------------------------------
std::istream&
operator>>(std::istream& is, Endpoint& endpoint)
{
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;
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 ((i == '.') || (i >= '0' && i <= ':') || (i >= 'a' && i <= 'f') ||
(i >= 'A' && i <= 'F'))
{
addrStr += i;
// don't exceed a reasonable length...
if (addrStr.size() == INET6_ADDRSTRLEN ||
(readTo && readTo == ':' && addrStr.size() > 15))
{
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);
}
else
endpoint = Endpoint(addr);
return is;
}
} // namespace IP
} // namespace beast