rippled
Loading...
Searching...
No Matches
IPEndpoint.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of Beast: https://github.com/vinniefalco/Beast
4 Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/beast/net/IPAddress.h>
21#include <xrpl/beast/net/IPEndpoint.h>
22
23#include <boost/algorithm/string/trim.hpp>
24#include <boost/asio/ip/address.hpp>
25#include <boost/asio/ip/address_v4.hpp>
26#include <boost/system/detail/error_code.hpp>
27
28#include <cctype>
29#include <ios>
30#include <istream>
31#include <optional>
32#include <sstream>
33#include <string>
34
35namespace beast {
36namespace IP {
37
38Endpoint::Endpoint() : m_port(0)
39{
40}
41
42Endpoint::Endpoint(Address const& addr, Port port) : m_addr(addr), m_port(port)
43{
44}
45
48{
49 if (s.size() <= 64)
50 {
51 std::stringstream is(boost::trim_copy(s));
52 Endpoint endpoint;
53 is >> endpoint;
54 if (!is.fail() && is.rdbuf()->in_avail() == 0)
55 return endpoint;
56 }
57 return {};
58}
59
62{
63 if (std::optional<Endpoint> const result = from_string_checked(s))
64 return *result;
65 return Endpoint{};
66}
67
70{
72 s.reserve(
73 (address().is_v6() ? INET6_ADDRSTRLEN - 1 : 15) +
74 (port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0)));
75
76 if (port() != 0 && address().is_v6())
77 s += '[';
78 s += address().to_string();
79 if (port())
80 {
81 if (address().is_v6())
82 s += ']';
83 s += ":" + std::to_string(port());
84 }
85
86 return s;
87}
88
89bool
90operator==(Endpoint const& lhs, Endpoint const& rhs)
91{
92 return lhs.address() == rhs.address() && lhs.port() == rhs.port();
93}
94
95bool
96operator<(Endpoint const& lhs, Endpoint const& rhs)
97{
98 if (lhs.address() < rhs.address())
99 return true;
100 if (lhs.address() > rhs.address())
101 return false;
102 return lhs.port() < rhs.port();
103}
104
105//------------------------------------------------------------------------------
106
109{
110 std::string addrStr;
111 // valid addresses only need INET6_ADDRSTRLEN-1 chars, but allow the extra
112 // char to check for invalid lengths
113 addrStr.reserve(INET6_ADDRSTRLEN);
114 char i{0};
115 char readTo{0};
116 is.get(i);
117 if (i == '[') // we are an IPv6 endpoint
118 readTo = ']';
119 else
120 addrStr += i;
121
122 while (is && is.rdbuf()->in_avail() > 0 && is.get(i))
123 {
124 // NOTE: There is a legacy data format
125 // that allowed space to be used as address / port separator
126 // so we continue to honor that here by assuming we are at the end
127 // of the address portion if we hit a space (or the separator
128 // we were expecting to see)
129 if (isspace(static_cast<unsigned char>(i)) || (readTo && i == readTo))
130 break;
131
132 if ((i == '.') || (i >= '0' && i <= ':') || (i >= 'a' && i <= 'f') ||
133 (i >= 'A' && i <= 'F'))
134 {
135 addrStr += i;
136
137 // don't exceed a reasonable length...
138 if (addrStr.size() == INET6_ADDRSTRLEN ||
139 (readTo && readTo == ':' && addrStr.size() > 15))
140 {
141 is.setstate(std::ios_base::failbit);
142 return is;
143 }
144
145 if (!readTo && (i == '.' || i == ':'))
146 {
147 // if we see a dot first, must be IPv4
148 // otherwise must be non-bracketed IPv6
149 readTo = (i == '.') ? ':' : ' ';
150 }
151 }
152 else // invalid char
153 {
154 is.unget();
155 is.setstate(std::ios_base::failbit);
156 return is;
157 }
158 }
159
160 if (readTo == ']' && is.rdbuf()->in_avail() > 0)
161 {
162 is.get(i);
163 if (!(isspace(static_cast<unsigned char>(i)) || i == ':'))
164 {
165 is.unget();
166 is.setstate(std::ios_base::failbit);
167 return is;
168 }
169 }
170
171 boost::system::error_code ec;
172 auto addr = boost::asio::ip::make_address(addrStr, ec);
173 if (ec)
174 {
175 is.setstate(std::ios_base::failbit);
176 return is;
177 }
178
179 if (is.rdbuf()->in_avail() > 0)
180 {
181 Port port;
182 is >> port;
183 if (is.fail())
184 return is;
185 endpoint = Endpoint(addr, port);
186 }
187 else
188 endpoint = Endpoint(addr);
189
190 return is;
191}
192
193} // namespace IP
194} // namespace beast
A version-independent IP address and port combination.
Definition IPEndpoint.h:38
Address const & address() const
Returns the address portion of this endpoint.
Definition IPEndpoint.h:75
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Endpoint()
Create an unspecified endpoint.
static Endpoint from_string(std::string const &s)
bool is_v6() const
Definition IPEndpoint.h:88
Port port() const
Returns the port number on the endpoint.
Definition IPEndpoint.h:61
std::string to_string() const
Returns a string representing the endpoint.
T fail(T... args)
T get(T... args)
std::istream & operator>>(std::istream &is, Endpoint &endpoint)
Input stream conversion.
bool operator<(Endpoint const &lhs, Endpoint const &rhs)
boost::asio::ip::address Address
Definition IPAddress.h:39
bool operator==(Endpoint const &lhs, Endpoint const &rhs)
T rdbuf(T... args)
T reserve(T... args)
T setstate(T... args)
T size(T... args)
T to_string(T... args)
T unget(T... args)