xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
xrpld
overlay
detail
ProtocolVersion.cpp
1
#include <xrpld/overlay/detail/ProtocolVersion.h>
2
3
#include <xrpl/beast/core/LexicalCast.h>
4
#include <xrpl/beast/rfc2616.h>
5
6
#include <boost/beast/core/string_type.hpp>
7
#include <boost/iterator/function_output_iterator.hpp>
8
#include <boost/regex/v5/regbase.hpp>
9
#include <boost/regex/v5/regex.hpp>
10
#include <boost/regex/v5/regex_match.hpp>
11
12
#include <
algorithm
>
13
#include <
cstdint
>
14
#include <
functional
>
15
#include <
iterator
>
16
#include <
optional
>
17
#include <
ranges
>
18
#include <
string
>
19
#include <
string_view
>
20
#include <
vector
>
21
22
namespace
xrpl
{
23
30
31
constexpr
ProtocolVersion
const
kSupportedProtocolList
[]{
32
{2, 2},
33
{2, 3},
34
};
35
36
// There should be at least one protocol we're willing to speak.
37
static_assert
(
38
!std::ranges::empty(
kSupportedProtocolList
),
39
"There must be at least one supported protocol."
);
40
41
// Searching for an adjacent pair where the first element is not less than the
42
// second one proves the list is sorted in strictly ascending order, which in
43
// turn means it holds no duplicates.
44
static_assert
(
45
std::ranges::adjacent_find
(
kSupportedProtocolList
,
std::ranges::greater_equal
{}) ==
46
std::ranges::end(
kSupportedProtocolList
),
47
"The list of supported protocols isn't properly sorted."
);
48
49
std::string
50
to_string
(
ProtocolVersion
const
& p)
51
{
52
return
"XRPL/"
+
std::to_string
(p.
first
) +
"."
+
std::to_string
(p.
second
);
53
}
54
55
std::vector<ProtocolVersion>
56
parseProtocolVersions
(
std::string_view
value)
57
{
58
static
boost::regex
const
kRE(
59
"^"
// start of line
60
"XRPL/"
// The string "XRPL/"
61
"([2-9]|(?:[1-9][0-9]+))"
// a number (greater than 2 with no leading
62
// zeroes)
63
"\\."
// a period
64
"(0|(?:[1-9][0-9]*))"
// a number (no leading zeroes unless exactly
65
// zero)
66
"$"
// The end of the string
67
,
68
boost::regex_constants::optimize);
69
70
std::vector<ProtocolVersion>
result;
71
72
for
(
auto
const
& s :
beast::rfc2616::splitCommas
(value))
73
{
74
boost::smatch m;
75
76
if
(boost::regex_match(s, m, kRE))
77
{
78
std::uint16_t
major = 0;
79
std::uint16_t
minor = 0;
80
if
(!
beast::lexicalCastChecked
(major,
std::string
(m[1])))
81
continue
;
82
83
if
(!
beast::lexicalCastChecked
(minor,
std::string
(m[2])))
84
continue
;
85
86
auto
const
proto =
makeProtocol
(major, minor);
87
88
// This is an extra sanity check: we check that the protocol we just
89
// decoded corresponds to the token we were parsing.
90
if
(
to_string
(proto) == s)
91
result.
push_back
(
makeProtocol
(major, minor));
92
}
93
}
94
95
// We guarantee that the returned list is sorted and contains no duplicates:
96
std::ranges::sort
(result);
97
auto
const
uniq =
std::ranges::unique
(result);
98
result.
erase
(uniq.begin(), uniq.end());
99
100
return
result;
101
}
102
103
std::optional<ProtocolVersion>
104
negotiateProtocolVersion
(
std::vector<ProtocolVersion>
const
& versions)
105
{
106
std::optional<ProtocolVersion>
result;
107
108
// The protocol version we want to negotiate is the largest item in the
109
// intersection of the versions supported by us and the peer. Since the
110
// output of std::set_intersection is sorted, that item is always going
111
// to be the last one. So we get a little clever and avoid the need for
112
// a container:
113
std::function
<void(
ProtocolVersion
const
&)>
const
pickVersion =
114
[&result](
ProtocolVersion
const
& v) { result = v; };
115
116
std::ranges::set_intersection
(
117
versions,
kSupportedProtocolList
, boost::make_function_output_iterator(pickVersion));
118
119
return
result;
120
}
121
122
std::optional<ProtocolVersion>
123
negotiateProtocolVersion
(
std::string_view
versions)
124
{
125
auto
const
them =
parseProtocolVersions
(versions);
126
127
return
negotiateProtocolVersion
(them);
128
}
129
130
std::string
const
&
131
supportedProtocolVersions
()
132
{
133
static
std::string
const
kSupported = []() {
134
std::string
ret;
135
for
(
auto
const
& v :
kSupportedProtocolList
)
136
{
137
if
(!ret.
empty
())
138
ret +=
", "
;
139
ret +=
to_string
(v);
140
}
141
142
return
ret;
143
}();
144
145
return
kSupported;
146
}
147
148
bool
149
isProtocolSupported
(
ProtocolVersion
const
& v)
150
{
151
return
std::end
(
kSupportedProtocolList
) !=
std::ranges::find
(
kSupportedProtocolList
, v);
152
}
153
154
ProtocolVersion
155
newestSupportedProtocolVersion
()
156
{
157
// Scans rather than reading the sorted list's last entry, so it does not
158
// depend on an invariant kept elsewhere.
159
return
*
std::ranges::max_element
(
kSupportedProtocolList
);
160
}
161
162
}
// namespace xrpl
std::ranges::adjacent_find
T adjacent_find(T... args)
algorithm
std::string
std::string_view
cstdint
std::string::empty
T empty(T... args)
std::end
T end(T... args)
std::vector::erase
T erase(T... args)
std::ranges::find
T find(T... args)
std::function
functional
std::ranges::greater_equal
std::uint16_t
iterator
std::ranges::max_element
T max_element(T... args)
beast::rfc2616::splitCommas
Result splitCommas(FwdIt first, FwdIt last)
Definition
rfc2616.h:183
beast::lexicalCastChecked
constexpr bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition
LexicalCast.h:181
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::newestSupportedProtocolVersion
ProtocolVersion newestSupportedProtocolVersion()
The version negotiated with a peer that speaks everything we speak, so also the one that enables ever...
Definition
ProtocolVersion.cpp:155
xrpl::isProtocolSupported
bool isProtocolSupported(ProtocolVersion const &v)
Determine whether we support a specific protocol version.
Definition
ProtocolVersion.cpp:149
xrpl::negotiateProtocolVersion
std::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
Definition
ProtocolVersion.cpp:104
xrpl::to_string
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition
base_uint.h:657
xrpl::kSupportedProtocolList
constexpr ProtocolVersion const kSupportedProtocolList[]
The list of protocol versions we speak and we prefer to use.
Definition
ProtocolVersion.cpp:31
xrpl::makeProtocol
constexpr ProtocolVersion makeProtocol(std::uint16_t major, std::uint16_t minor)
Definition
ProtocolVersion.h:21
xrpl::supportedProtocolVersions
std::string const & supportedProtocolVersions()
The list of all the protocol versions we support.
Definition
ProtocolVersion.cpp:131
xrpl::ProtocolVersion
std::pair< std::uint16_t, std::uint16_t > ProtocolVersion
Represents a particular version of the peer-to-peer protocol.
Definition
ProtocolVersion.h:18
xrpl::parseProtocolVersions
std::vector< ProtocolVersion > parseProtocolVersions(std::string_view value)
Parse a set of protocol versions.
Definition
ProtocolVersion.cpp:56
optional
std::pair::first
T first
std::vector::push_back
T push_back(T... args)
ranges
std::ranges::set_intersection
T set_intersection(T... args)
std::ranges::sort
T sort(T... args)
string
string_view
std::to_string
T to_string(T... args)
std::ranges::unique
T unique(T... args)
vector
Generated by
1.17.0