rippled
Loading...
Searching...
No Matches
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/iterator/function_output_iterator.hpp>
7#include <boost/regex.hpp>
8
9#include <algorithm>
10#include <functional>
11
12namespace xrpl {
13
20// clang-format off
22{
23 {2, 1},
24 {2, 2}
25};
26// clang-format on
27
28// This ugly construct ensures that supportedProtocolList is sorted in strictly
29// ascending order and doesn't contain any duplicates.
30// FIXME: With C++20 we can use std::is_sorted with an appropriate comparator
31static_assert(
32 []() constexpr -> bool {
33 auto const len =
35
36 // There should be at least one protocol we're willing to speak.
37 if (len == 0)
38 return false;
39
40 // A list with only one entry is, by definition, sorted so we don't
41 // need to check it.
42 if (len != 1)
43 {
44 for (auto i = 0; i != len - 1; ++i)
45 {
47 return false;
48 }
49 }
50
51 return true;
52 }(),
53 "The list of supported protocols isn't properly sorted.");
54
57{
58 return "XRPL/" + std::to_string(p.first) + "." + std::to_string(p.second);
59}
60
62parseProtocolVersions(boost::beast::string_view const& value)
63{
64 static boost::regex re(
65 "^" // start of line
66 "XRPL/" // The string "XRPL/"
67 "([2-9]|(?:[1-9][0-9]+))" // a number (greater than 2 with no leading
68 // zeroes)
69 "\\." // a period
70 "(0|(?:[1-9][0-9]*))" // a number (no leading zeroes unless exactly
71 // zero)
72 "$" // The end of the string
73 ,
74 boost::regex_constants::optimize);
75
77
78 for (auto const& s : beast::rfc2616::split_commas(value))
79 {
80 boost::smatch m;
81
82 if (boost::regex_match(s, m, re))
83 {
84 std::uint16_t major;
85 std::uint16_t minor;
86 if (!beast::lexicalCastChecked(major, std::string(m[1])))
87 continue;
88
89 if (!beast::lexicalCastChecked(minor, std::string(m[2])))
90 continue;
91
92 auto const proto = make_protocol(major, minor);
93
94 // This is an extra sanity check: we check that the protocol we just
95 // decoded corresponds to the token we were parsing.
96 if (to_string(proto) == s)
97 result.push_back(make_protocol(major, minor));
98 }
99 }
100
101 // We guarantee that the returned list is sorted and contains no duplicates:
102 std::sort(result.begin(), result.end());
103 result.erase(std::unique(result.begin(), result.end()), result.end());
104
105 return result;
106}
107
110{
112
113 // The protocol version we want to negotiate is the largest item in the
114 // intersection of the versions supported by us and the peer. Since the
115 // output of std::set_intersection is sorted, that item is always going
116 // to be the last one. So we get a little clever and avoid the need for
117 // a container:
118 std::function<void(ProtocolVersion const&)> pickVersion = [&result](ProtocolVersion const& v) {
119 result = v;
120 };
121
123 std::begin(versions),
124 std::end(versions),
127 boost::make_function_output_iterator(pickVersion));
128
129 return result;
130}
131
133negotiateProtocolVersion(boost::beast::string_view const& versions)
134{
135 auto const them = parseProtocolVersions(versions);
136
137 return negotiateProtocolVersion(them);
138}
139
140std::string const&
142{
143 static std::string const supported = []() {
144 std::string ret;
145 for (auto const& v : supportedProtocolList)
146 {
147 if (!ret.empty())
148 ret += ", ";
149 ret += to_string(v);
150 }
151
152 return ret;
153 }();
154
155 return supported;
156}
157
158bool
164
165} // namespace xrpl
T begin(T... args)
T distance(T... args)
T empty(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
Result split_commas(FwdIt first, FwdIt last)
Definition rfc2616.h:177
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::vector< ProtocolVersion > parseProtocolVersions(boost::beast::string_view const &value)
Parse a set of protocol versions.
bool isProtocolSupported(ProtocolVersion const &v)
Determine whether we support a specific protocol version.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:600
std::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
constexpr ProtocolVersion make_protocol(std::uint16_t major, std::uint16_t minor)
constexpr ProtocolVersion const supportedProtocolList[]
The list of protocol versions we speak and we prefer to use.
std::string const & supportedProtocolVersions()
The list of all the protocol versions we support.
T push_back(T... args)
T set_intersection(T... args)
T sort(T... args)
T to_string(T... args)
T unique(T... args)