xrpld
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/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 <string>
18#include <vector>
19
20namespace xrpl {
21
27
29 {2, 1},
30 {2, 2},
31};
32
33// This ugly construct ensures that supportedProtocolList is sorted in strictly
34// ascending order and doesn't contain any duplicates.
35// FIXME: With C++20 we can use std::is_sorted with an appropriate comparator
36static_assert(
37 []() constexpr -> bool {
38 auto const len =
40
41 // There should be at least one protocol we're willing to speak.
42 if (len == 0)
43 return false;
44
45 // A list with only one entry is, by definition, sorted so we don't
46 // need to check it.
47 if (len != 1)
48 {
49 for (auto i = 0; i != len - 1; ++i)
50 {
52 return false;
53 }
54 }
55
56 return true;
57 }(),
58 "The list of supported protocols isn't properly sorted.");
59
60std::string
62{
63 return "XRPL/" + std::to_string(p.first) + "." + std::to_string(p.second);
64}
65
67parseProtocolVersions(boost::beast::string_view const& value)
68{
69 static boost::regex const kRE(
70 "^" // start of line
71 "XRPL/" // The string "XRPL/"
72 "([2-9]|(?:[1-9][0-9]+))" // a number (greater than 2 with no leading
73 // zeroes)
74 "\\." // a period
75 "(0|(?:[1-9][0-9]*))" // a number (no leading zeroes unless exactly
76 // zero)
77 "$" // The end of the string
78 ,
79 boost::regex_constants::optimize);
80
82
83 for (auto const& s : beast::rfc2616::splitCommas(value))
84 {
85 boost::smatch m;
86
87 if (boost::regex_match(s, m, kRE))
88 {
89 std::uint16_t major = 0;
90 std::uint16_t minor = 0;
91 if (!beast::lexicalCastChecked(major, std::string(m[1])))
92 continue;
93
94 if (!beast::lexicalCastChecked(minor, std::string(m[2])))
95 continue;
96
97 auto const proto = makeProtocol(major, minor);
98
99 // This is an extra sanity check: we check that the protocol we just
100 // decoded corresponds to the token we were parsing.
101 if (to_string(proto) == s)
102 result.push_back(makeProtocol(major, minor));
103 }
104 }
105
106 // We guarantee that the returned list is sorted and contains no duplicates:
107 std::ranges::sort(result);
108 auto const uniq = std::ranges::unique(result);
109 result.erase(uniq.begin(), uniq.end());
110
111 return result;
112}
113
116{
118
119 // The protocol version we want to negotiate is the largest item in the
120 // intersection of the versions supported by us and the peer. Since the
121 // output of std::set_intersection is sorted, that item is always going
122 // to be the last one. So we get a little clever and avoid the need for
123 // a container:
124 std::function<void(ProtocolVersion const&)> const pickVersion =
125 [&result](ProtocolVersion const& v) { result = v; };
126
128 versions, kSupportedProtocolList, boost::make_function_output_iterator(pickVersion));
129
130 return result;
131}
132
134negotiateProtocolVersion(boost::beast::string_view const& versions)
135{
136 auto const them = parseProtocolVersions(versions);
137
138 return negotiateProtocolVersion(them);
139}
140
141std::string const&
143{
144 static std::string const kSupported = []() {
145 std::string ret;
146 for (auto const& v : kSupportedProtocolList)
147 {
148 if (!ret.empty())
149 ret += ", ";
150 ret += to_string(v);
151 }
152
153 return ret;
154 }();
155
156 return kSupported;
157}
158
159bool
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 splitCommas(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::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
constexpr ProtocolVersion const kSupportedProtocolList[]
The list of protocol versions we speak and we prefer to use.
constexpr ProtocolVersion makeProtocol(std::uint16_t major, std::uint16_t minor)
std::string const & supportedProtocolVersions()
The list of all the protocol versions we support.
std::pair< std::uint16_t, std::uint16_t > ProtocolVersion
Represents a particular version of the peer-to-peer protocol.
T push_back(T... args)
T set_intersection(T... args)
T sort(T... args)
T to_string(T... args)
T unique(T... args)