rippled
Loading...
Searching...
No Matches
ProtocolMessage.h
1#ifndef XRPL_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED
2#define XRPL_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED
3
4#include <xrpld/overlay/Compression.h>
5#include <xrpld/overlay/Message.h>
6#include <xrpld/overlay/detail/ZeroCopyStream.h>
7
8#include <xrpl/beast/utility/instrumentation.h>
9#include <xrpl/protocol/messages.h>
10
11#include <boost/asio/buffer.hpp>
12#include <boost/asio/buffers_iterator.hpp>
13
14#include <cstdint>
15#include <optional>
16#include <type_traits>
17#include <vector>
18
19namespace ripple {
20
21inline protocol::MessageType
22protocolMessageType(protocol::TMGetLedger const&)
23{
24 return protocol::mtGET_LEDGER;
25}
26
27inline protocol::MessageType
28protocolMessageType(protocol::TMReplayDeltaRequest const&)
29{
30 return protocol::mtREPLAY_DELTA_REQ;
31}
32
33inline protocol::MessageType
34protocolMessageType(protocol::TMProofPathRequest const&)
35{
36 return protocol::mtPROOF_PATH_REQ;
37}
38
40template <class = void>
43{
44 switch (type)
45 {
46 case protocol::mtMANIFESTS:
47 return "manifests";
48 case protocol::mtPING:
49 return "ping";
50 case protocol::mtCLUSTER:
51 return "cluster";
52 case protocol::mtENDPOINTS:
53 return "endpoints";
54 case protocol::mtTRANSACTION:
55 return "tx";
56 case protocol::mtGET_LEDGER:
57 return "get_ledger";
58 case protocol::mtLEDGER_DATA:
59 return "ledger_data";
60 case protocol::mtPROPOSE_LEDGER:
61 return "propose";
62 case protocol::mtSTATUS_CHANGE:
63 return "status";
64 case protocol::mtHAVE_SET:
65 return "have_set";
66 case protocol::mtVALIDATORLIST:
67 return "validator_list";
68 case protocol::mtVALIDATORLISTCOLLECTION:
69 return "validator_list_collection";
70 case protocol::mtVALIDATION:
71 return "validation";
72 case protocol::mtGET_OBJECTS:
73 return "get_objects";
74 case protocol::mtHAVE_TRANSACTIONS:
75 return "have_transactions";
76 case protocol::mtTRANSACTIONS:
77 return "transactions";
78 case protocol::mtSQUELCH:
79 return "squelch";
80 case protocol::mtPROOF_PATH_REQ:
81 return "proof_path_request";
82 case protocol::mtPROOF_PATH_RESPONSE:
83 return "proof_path_response";
84 case protocol::mtREPLAY_DELTA_REQ:
85 return "replay_delta_request";
86 case protocol::mtREPLAY_DELTA_RESPONSE:
87 return "replay_delta_response";
88 default:
89 break;
90 }
91 return "unknown";
92}
93
94namespace detail {
95
122
123template <typename BufferSequence>
124auto
125buffersBegin(BufferSequence const& bufs)
126{
127 return boost::asio::buffers_iterator<BufferSequence, std::uint8_t>::begin(
128 bufs);
129}
130
131template <typename BufferSequence>
132auto
133buffersEnd(BufferSequence const& bufs)
134{
135 return boost::asio::buffers_iterator<BufferSequence, std::uint8_t>::end(
136 bufs);
137}
138
148template <class BufferSequence>
151 boost::system::error_code& ec,
152 BufferSequence const& bufs,
153 std::size_t size)
154{
155 using namespace ripple::compression;
156
157 MessageHeader hdr;
158 auto iter = buffersBegin(bufs);
159 XRPL_ASSERT(
160 iter != buffersEnd(bufs),
161 "ripple::detail::parseMessageHeader : non-empty buffer");
162
163 // Check valid header compressed message:
164 // - 4 bits are the compression algorithm, 1st bit is always set to 1
165 // - 2 bits are always set to 0
166 // - 26 bits are the payload size
167 // - 32 bits are the uncompressed data size
168 if (*iter & 0x80)
169 {
170 hdr.header_size = headerBytesCompressed;
171
172 // not enough bytes to parse the header
173 if (size < hdr.header_size)
174 {
175 ec = make_error_code(boost::system::errc::success);
176 return std::nullopt;
177 }
178
179 if (*iter & 0x0C)
180 {
181 ec = make_error_code(boost::system::errc::protocol_error);
182 return std::nullopt;
183 }
184
185 hdr.algorithm = static_cast<compression::Algorithm>(*iter & 0xF0);
186
188 {
189 ec = make_error_code(boost::system::errc::protocol_error);
190 return std::nullopt;
191 }
192
193 for (int i = 0; i != 4; ++i)
194 hdr.payload_wire_size = (hdr.payload_wire_size << 8) + *iter++;
195
196 // clear the top four bits (the compression bits).
197 hdr.payload_wire_size &= 0x0FFFFFFF;
198
200
201 for (int i = 0; i != 2; ++i)
202 hdr.message_type = (hdr.message_type << 8) + *iter++;
203
204 for (int i = 0; i != 4; ++i)
205 hdr.uncompressed_size = (hdr.uncompressed_size << 8) + *iter++;
206
207 return hdr;
208 }
209
210 // Check valid header uncompressed message:
211 // - 6 bits are set to 0
212 // - 26 bits are the payload size
213 if ((*iter & 0xFC) == 0)
214 {
215 hdr.header_size = headerBytes;
216
217 if (size < hdr.header_size)
218 {
219 ec = make_error_code(boost::system::errc::success);
220 return std::nullopt;
221 }
222
223 hdr.algorithm = Algorithm::None;
224
225 for (int i = 0; i != 4; ++i)
226 hdr.payload_wire_size = (hdr.payload_wire_size << 8) + *iter++;
227
230
231 for (int i = 0; i != 2; ++i)
232 hdr.message_type = (hdr.message_type << 8) + *iter++;
233
234 return hdr;
235 }
236
237 ec = make_error_code(boost::system::errc::no_message);
238 return std::nullopt;
239}
240
241template <
242 class T,
243 class Buffers,
244 class = std::enable_if_t<
247parseMessageContent(MessageHeader const& header, Buffers const& buffers)
248{
249 auto const m = std::make_shared<T>();
250
251 ZeroCopyInputStream<Buffers> stream(buffers);
252 stream.Skip(header.header_size);
253
255 {
257 payload.resize(header.uncompressed_size);
258
259 auto const payloadSize = ripple::compression::decompress(
260 stream,
261 header.payload_wire_size,
262 payload.data(),
263 header.uncompressed_size,
264 header.algorithm);
265
266 if (payloadSize == 0 || !m->ParseFromArray(payload.data(), payloadSize))
267 return {};
268 }
269 else if (!m->ParseFromZeroCopyStream(&stream))
270 return {};
271
272 return m;
273}
274
275template <
276 class T,
277 class Buffers,
278 class Handler,
279 class = std::enable_if_t<
281bool
282invoke(MessageHeader const& header, Buffers const& buffers, Handler& handler)
283{
284 auto const m = parseMessageContent<T>(header, buffers);
285 if (!m)
286 return false;
287
288 using namespace ripple::compression;
289 handler.onMessageBegin(
290 header.message_type,
291 m,
292 header.payload_wire_size,
293 header.uncompressed_size,
294 header.algorithm != Algorithm::None);
295 handler.onMessage(m);
296 handler.onMessageEnd(header.message_type, m);
297
298 return true;
299}
300
301} // namespace detail
302
315template <class Buffers, class Handler>
318 Buffers const& buffers,
319 Handler& handler,
320 std::size_t& hint)
321{
323
324 auto const size = boost::asio::buffer_size(buffers);
325
326 if (size == 0)
327 return result;
328
329 auto header = detail::parseMessageHeader(result.second, buffers, size);
330
331 // If we can't parse the header then it may be that we don't have enough
332 // bytes yet, or because the message was cut off (if error_code is success).
333 // Otherwise we failed to match the header's marker (error_code is set to
334 // no_message) or the compression algorithm is invalid (error_code is
335 // protocol_error) and signal an error.
336 if (!header)
337 return result;
338
339 // We implement a maximum size for protocol messages. Sending a message
340 // whose size exceeds this may result in the connection being dropped. A
341 // larger message size may be supported in the future or negotiated as
342 // part of a protocol upgrade.
343 if (header->payload_wire_size > maximiumMessageSize ||
344 header->uncompressed_size > maximiumMessageSize)
345 {
346 result.second = make_error_code(boost::system::errc::message_size);
347 return result;
348 }
349
350 // We requested uncompressed messages from the peer but received compressed.
351 if (!handler.compressionEnabled() &&
352 header->algorithm != compression::Algorithm::None)
353 {
354 result.second = make_error_code(boost::system::errc::protocol_error);
355 return result;
356 }
357
358 // We don't have the whole message yet. This isn't an error but we have
359 // nothing to do.
360 if (header->total_wire_size > size)
361 {
362 hint = header->total_wire_size - size;
363 return result;
364 }
365
366 bool success;
367
368 switch (header->message_type)
369 {
370 case protocol::mtMANIFESTS:
371 success = detail::invoke<protocol::TMManifests>(
372 *header, buffers, handler);
373 break;
374 case protocol::mtPING:
375 success =
376 detail::invoke<protocol::TMPing>(*header, buffers, handler);
377 break;
378 case protocol::mtCLUSTER:
379 success =
380 detail::invoke<protocol::TMCluster>(*header, buffers, handler);
381 break;
382 case protocol::mtENDPOINTS:
383 success = detail::invoke<protocol::TMEndpoints>(
384 *header, buffers, handler);
385 break;
386 case protocol::mtTRANSACTION:
387 success = detail::invoke<protocol::TMTransaction>(
388 *header, buffers, handler);
389 break;
390 case protocol::mtGET_LEDGER:
391 success = detail::invoke<protocol::TMGetLedger>(
392 *header, buffers, handler);
393 break;
394 case protocol::mtLEDGER_DATA:
395 success = detail::invoke<protocol::TMLedgerData>(
396 *header, buffers, handler);
397 break;
398 case protocol::mtPROPOSE_LEDGER:
399 success = detail::invoke<protocol::TMProposeSet>(
400 *header, buffers, handler);
401 break;
402 case protocol::mtSTATUS_CHANGE:
403 success = detail::invoke<protocol::TMStatusChange>(
404 *header, buffers, handler);
405 break;
406 case protocol::mtHAVE_SET:
407 success = detail::invoke<protocol::TMHaveTransactionSet>(
408 *header, buffers, handler);
409 break;
410 case protocol::mtVALIDATION:
411 success = detail::invoke<protocol::TMValidation>(
412 *header, buffers, handler);
413 break;
414 case protocol::mtVALIDATORLIST:
415 success = detail::invoke<protocol::TMValidatorList>(
416 *header, buffers, handler);
417 break;
418 case protocol::mtVALIDATORLISTCOLLECTION:
419 success = detail::invoke<protocol::TMValidatorListCollection>(
420 *header, buffers, handler);
421 break;
422 case protocol::mtGET_OBJECTS:
423 success = detail::invoke<protocol::TMGetObjectByHash>(
424 *header, buffers, handler);
425 break;
426 case protocol::mtHAVE_TRANSACTIONS:
427 success = detail::invoke<protocol::TMHaveTransactions>(
428 *header, buffers, handler);
429 break;
430 case protocol::mtTRANSACTIONS:
431 success = detail::invoke<protocol::TMTransactions>(
432 *header, buffers, handler);
433 break;
434 case protocol::mtSQUELCH:
435 success =
436 detail::invoke<protocol::TMSquelch>(*header, buffers, handler);
437 break;
438 case protocol::mtPROOF_PATH_REQ:
439 success = detail::invoke<protocol::TMProofPathRequest>(
440 *header, buffers, handler);
441 break;
442 case protocol::mtPROOF_PATH_RESPONSE:
443 success = detail::invoke<protocol::TMProofPathResponse>(
444 *header, buffers, handler);
445 break;
446 case protocol::mtREPLAY_DELTA_REQ:
447 success = detail::invoke<protocol::TMReplayDeltaRequest>(
448 *header, buffers, handler);
449 break;
450 case protocol::mtREPLAY_DELTA_RESPONSE:
451 success = detail::invoke<protocol::TMReplayDeltaResponse>(
452 *header, buffers, handler);
453 break;
454 default:
455 handler.onMessageUnknown(header->message_type);
456 success = true;
457 break;
458 }
459
460 result.first = header->total_wire_size;
461
462 if (!success)
463 result.second = make_error_code(boost::system::errc::bad_message);
464
465 return result;
466}
467
468} // namespace ripple
469
470#endif
Implements ZeroCopyInputStream around a buffer sequence.
T data(T... args)
T is_same_v
std::size_t decompress(InputStream &in, std::size_t inSize, std::uint8_t *decompressed, std::size_t decompressedSize, Algorithm algorithm=Algorithm::LZ4)
Decompress input stream.
Definition Compression.h:30
std::shared_ptr< T > parseMessageContent(MessageHeader const &header, Buffers const &buffers)
bool invoke(MessageHeader const &header, Buffers const &buffers, Handler &handler)
auto buffersBegin(BufferSequence const &bufs)
std::optional< MessageHeader > parseMessageHeader(boost::system::error_code &ec, BufferSequence const &bufs, std::size_t size)
Parse a message header.
auto buffersEnd(BufferSequence const &bufs)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string protocolMessageName(int type)
Returns the name of a protocol message given its type.
protocol::MessageType protocolMessageType(protocol::TMGetLedger const &)
std::pair< std::size_t, boost::system::error_code > invokeProtocolMessage(Buffers const &buffers, Handler &handler, std::size_t &hint)
Calls the handler for up to one protocol message in the passed buffers.
std::error_code make_error_code(ripple::TokenCodecErrc e)
constexpr std::size_t maximiumMessageSize
Definition Message.h:15
T resize(T... args)
std::uint32_t header_size
The size of the header associated with this message.
compression::Algorithm algorithm
Indicates which compression algorithm the payload is compressed with.
std::uint16_t message_type
The type of the message.
std::uint32_t payload_wire_size
The size of the payload on the wire.
std::uint32_t total_wire_size
The size of the message on the wire.
std::uint32_t uncompressed_size
Uncompressed message size if the message is compressed.