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/system/detail/error_code.hpp>
25
26#include <cctype>
27#include <ios>
28#include <istream>
29#include <optional>
30#include <sstream>
31#include <string>
32
33namespace beast {
34namespace IP {
35
36Endpoint::Endpoint() : m_port(0)
37{
38}
39
40Endpoint::Endpoint(Address const& addr, Port port) : m_addr(addr), m_port(port)
41{
42}
43
46{
47 if (s.size() <= 64)
48 {
49 std::stringstream is(boost::trim_copy(s));
50 Endpoint endpoint;
51 is >> endpoint;
52 if (!is.fail() && is.rdbuf()->in_avail() == 0)
53 return endpoint;
54 }
55 return {};
56}
57
60{
61 if (std::optional<Endpoint> const result = from_string_checked(s))
62 return *result;
63 return Endpoint{};
64}
65
68{
70 s.reserve(
71 (address().is_v6() ? INET6_ADDRSTRLEN - 1 : 15) +
72 (port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0)));
73
74 if (port() != 0 && address().is_v6())
75 s += '[';
76 s += address().to_string();
77 if (port())
78 {
79 if (address().is_v6())
80 s += ']';
81 s += ":" + std::to_string(port());
82 }
83
84 return s;
85}
86
87bool
88operator==(Endpoint const& lhs, Endpoint const& rhs)
89{
90 return lhs.address() == rhs.address() && lhs.port() == rhs.port();
91}
92
93bool
94operator<(Endpoint const& lhs, Endpoint const& rhs)
95{
96 if (lhs.address() < rhs.address())
97 return true;
98 if (lhs.address() > rhs.address())
99 return false;
100 return lhs.port() < rhs.port();
101}
102
103//------------------------------------------------------------------------------
104
107{
108 std::string addrStr;
109 // valid addresses only need INET6_ADDRSTRLEN-1 chars, but allow the extra
110 // char to check for invalid lengths
111 addrStr.reserve(INET6_ADDRSTRLEN);
112 char i{0};
113 char readTo{0};
114 is.get(i);
115 if (i == '[') // we are an IPv6 endpoint
116 readTo = ']';
117 else
118 addrStr += i;
119
120 while (is && is.rdbuf()->in_avail() > 0 && is.get(i))
121 {
122 // NOTE: There is a legacy data format
123 // that allowed space to be used as address / port separator
124 // so we continue to honor that here by assuming we are at the end
125 // of the address portion if we hit a space (or the separator
126 // we were expecting to see)
127 if (isspace(static_cast<unsigned char>(i)) || (readTo && i == readTo))
128 break;
129
130 if ((i == '.') || (i >= '0' && i <= ':') || (i >= 'a' && i <= 'f') ||
131 (i >= 'A' && i <= 'F'))
132 {
133 addrStr += i;
134
135 // don't exceed a reasonable length...
136 if (addrStr.size() == INET6_ADDRSTRLEN ||
137 (readTo && readTo == ':' && addrStr.size() > 15))
138 {
139 is.setstate(std::ios_base::failbit);
140 return is;
141 }
142
143 if (!readTo && (i == '.' || i == ':'))
144 {
145 // if we see a dot first, must be IPv4
146 // otherwise must be non-bracketed IPv6
147 readTo = (i == '.') ? ':' : ' ';
148 }
149 }
150 else // invalid char
151 {
152 is.unget();
153 is.setstate(std::ios_base::failbit);
154 return is;
155 }
156 }
157
158 if (readTo == ']' && is.rdbuf()->in_avail() > 0)
159 {
160 is.get(i);
161 if (!(isspace(static_cast<unsigned char>(i)) || i == ':'))
162 {
163 is.unget();
164 is.setstate(std::ios_base::failbit);
165 return is;
166 }
167 }
168
169 boost::system::error_code ec;
170 auto addr = Address::from_string(addrStr, ec);
171 if (ec)
172 {
173 is.setstate(std::ios_base::failbit);
174 return is;
175 }
176
177 if (is.rdbuf()->in_avail() > 0)
178 {
179 Port port;
180 is >> port;
181 if (is.fail())
182 return is;
183 endpoint = Endpoint(addr, port);
184 }
185 else
186 endpoint = Endpoint(addr);
187
188 return is;
189}
190
191} // namespace IP
192} // namespace beast
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
Address const & address() const
Returns the address portion of this endpoint.
Definition: IPEndpoint.h:76
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:45
Endpoint()
Create an unspecified endpoint.
Definition: IPEndpoint.cpp:36
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:59
bool is_v6() const
Definition: IPEndpoint.h:89
Port port() const
Returns the port number on the endpoint.
Definition: IPEndpoint.h:62
std::string to_string() const
Returns a string representing the endpoint.
Definition: IPEndpoint.cpp:67
T fail(T... args)
T get(T... args)
std::istream & operator>>(std::istream &is, Endpoint &endpoint)
Input stream conversion.
Definition: IPEndpoint.cpp:106
bool operator<(Endpoint const &lhs, Endpoint const &rhs)
Definition: IPEndpoint.cpp:94
boost::asio::ip::address Address
Definition: IPAddress.h:43
bool operator==(Endpoint const &lhs, Endpoint const &rhs)
Definition: IPEndpoint.cpp:88
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)