rippled
Loading...
Searching...
No Matches
ProtocolMessage.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
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#ifndef RIPPLE_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED
21#define RIPPLE_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED
22
23#include <xrpld/overlay/Compression.h>
24#include <xrpld/overlay/Message.h>
25#include <xrpld/overlay/detail/ZeroCopyStream.h>
26#include <xrpl/beast/utility/instrumentation.h>
27#include <xrpl/protocol/messages.h>
28
29#include <boost/asio/buffer.hpp>
30#include <boost/asio/buffers_iterator.hpp>
31
32#include <cstdint>
33#include <optional>
34#include <type_traits>
35#include <vector>
36
37namespace ripple {
38
39inline protocol::MessageType
40protocolMessageType(protocol::TMGetLedger const&)
41{
42 return protocol::mtGET_LEDGER;
43}
44
45inline protocol::MessageType
46protocolMessageType(protocol::TMReplayDeltaRequest const&)
47{
48 return protocol::mtREPLAY_DELTA_REQ;
49}
50
51inline protocol::MessageType
52protocolMessageType(protocol::TMProofPathRequest const&)
53{
54 return protocol::mtPROOF_PATH_REQ;
55}
56
58template <class = void>
61{
62 switch (type)
63 {
64 case protocol::mtMANIFESTS:
65 return "manifests";
66 case protocol::mtPING:
67 return "ping";
68 case protocol::mtCLUSTER:
69 return "cluster";
70 case protocol::mtENDPOINTS:
71 return "endpoints";
72 case protocol::mtTRANSACTION:
73 return "tx";
74 case protocol::mtGET_LEDGER:
75 return "get_ledger";
76 case protocol::mtLEDGER_DATA:
77 return "ledger_data";
78 case protocol::mtPROPOSE_LEDGER:
79 return "propose";
80 case protocol::mtSTATUS_CHANGE:
81 return "status";
82 case protocol::mtHAVE_SET:
83 return "have_set";
84 case protocol::mtVALIDATORLIST:
85 return "validator_list";
86 case protocol::mtVALIDATORLISTCOLLECTION:
87 return "validator_list_collection";
88 case protocol::mtVALIDATION:
89 return "validation";
90 case protocol::mtGET_OBJECTS:
91 return "get_objects";
92 case protocol::mtHAVE_TRANSACTIONS:
93 return "have_transactions";
94 case protocol::mtTRANSACTIONS:
95 return "transactions";
96 case protocol::mtSQUELCH:
97 return "squelch";
98 case protocol::mtPROOF_PATH_REQ:
99 return "proof_path_request";
100 case protocol::mtPROOF_PATH_RESPONSE:
101 return "proof_path_response";
102 case protocol::mtREPLAY_DELTA_REQ:
103 return "replay_delta_request";
104 case protocol::mtREPLAY_DELTA_RESPONSE:
105 return "replay_delta_response";
106 default:
107 break;
108 }
109 return "unknown";
110}
111
112namespace detail {
113
115{
121
124
127
130
133
139};
140
141template <typename BufferSequence>
142auto
143buffersBegin(BufferSequence const& bufs)
144{
145 return boost::asio::buffers_iterator<BufferSequence, std::uint8_t>::begin(
146 bufs);
147}
148
149template <typename BufferSequence>
150auto
151buffersEnd(BufferSequence const& bufs)
152{
153 return boost::asio::buffers_iterator<BufferSequence, std::uint8_t>::end(
154 bufs);
155}
156
166template <class BufferSequence>
169 boost::system::error_code& ec,
170 BufferSequence const& bufs,
171 std::size_t size)
172{
173 using namespace ripple::compression;
174
175 MessageHeader hdr;
176 auto iter = buffersBegin(bufs);
177 XRPL_ASSERT(
178 iter != buffersEnd(bufs),
179 "ripple::detail::parseMessageHeader : non-empty buffer");
180
181 // Check valid header compressed message:
182 // - 4 bits are the compression algorithm, 1st bit is always set to 1
183 // - 2 bits are always set to 0
184 // - 26 bits are the payload size
185 // - 32 bits are the uncompressed data size
186 if (*iter & 0x80)
187 {
188 hdr.header_size = headerBytesCompressed;
189
190 // not enough bytes to parse the header
191 if (size < hdr.header_size)
192 {
193 ec = make_error_code(boost::system::errc::success);
194 return std::nullopt;
195 }
196
197 if (*iter & 0x0C)
198 {
199 ec = make_error_code(boost::system::errc::protocol_error);
200 return std::nullopt;
201 }
202
203 hdr.algorithm = static_cast<compression::Algorithm>(*iter & 0xF0);
204
206 {
207 ec = make_error_code(boost::system::errc::protocol_error);
208 return std::nullopt;
209 }
210
211 for (int i = 0; i != 4; ++i)
212 hdr.payload_wire_size = (hdr.payload_wire_size << 8) + *iter++;
213
214 // clear the top four bits (the compression bits).
215 hdr.payload_wire_size &= 0x0FFFFFFF;
216
218
219 for (int i = 0; i != 2; ++i)
220 hdr.message_type = (hdr.message_type << 8) + *iter++;
221
222 for (int i = 0; i != 4; ++i)
223 hdr.uncompressed_size = (hdr.uncompressed_size << 8) + *iter++;
224
225 return hdr;
226 }
227
228 // Check valid header uncompressed message:
229 // - 6 bits are set to 0
230 // - 26 bits are the payload size
231 if ((*iter & 0xFC) == 0)
232 {
233 hdr.header_size = headerBytes;
234
235 if (size < hdr.header_size)
236 {
237 ec = make_error_code(boost::system::errc::success);
238 return std::nullopt;
239 }
240
241 hdr.algorithm = Algorithm::None;
242
243 for (int i = 0; i != 4; ++i)
244 hdr.payload_wire_size = (hdr.payload_wire_size << 8) + *iter++;
245
248
249 for (int i = 0; i != 2; ++i)
250 hdr.message_type = (hdr.message_type << 8) + *iter++;
251
252 return hdr;
253 }
254
255 ec = make_error_code(boost::system::errc::no_message);
256 return std::nullopt;
257}
258
259template <
260 class T,
261 class Buffers,
262 class = std::enable_if_t<
265parseMessageContent(MessageHeader const& header, Buffers const& buffers)
266{
267 auto const m = std::make_shared<T>();
268
269 ZeroCopyInputStream<Buffers> stream(buffers);
270 stream.Skip(header.header_size);
271
273 {
275 payload.resize(header.uncompressed_size);
276
277 auto const payloadSize = ripple::compression::decompress(
278 stream,
279 header.payload_wire_size,
280 payload.data(),
281 header.uncompressed_size,
282 header.algorithm);
283
284 if (payloadSize == 0 || !m->ParseFromArray(payload.data(), payloadSize))
285 return {};
286 }
287 else if (!m->ParseFromZeroCopyStream(&stream))
288 return {};
289
290 return m;
291}
292
293template <
294 class T,
295 class Buffers,
296 class Handler,
297 class = std::enable_if_t<
299bool
300invoke(MessageHeader const& header, Buffers const& buffers, Handler& handler)
301{
302 auto const m = parseMessageContent<T>(header, buffers);
303 if (!m)
304 return false;
305
306 using namespace ripple::compression;
307 handler.onMessageBegin(
308 header.message_type,
309 m,
310 header.payload_wire_size,
311 header.uncompressed_size,
312 header.algorithm != Algorithm::None);
313 handler.onMessage(m);
314 handler.onMessageEnd(header.message_type, m);
315
316 return true;
317}
318
319} // namespace detail
320
333template <class Buffers, class Handler>
336 Buffers const& buffers,
337 Handler& handler,
338 std::size_t& hint)
339{
341
342 auto const size = boost::asio::buffer_size(buffers);
343
344 if (size == 0)
345 return result;
346
347 auto header = detail::parseMessageHeader(result.second, buffers, size);
348
349 // If we can't parse the header then it may be that we don't have enough
350 // bytes yet, or because the message was cut off (if error_code is success).
351 // Otherwise we failed to match the header's marker (error_code is set to
352 // no_message) or the compression algorithm is invalid (error_code is
353 // protocol_error) and signal an error.
354 if (!header)
355 return result;
356
357 // We implement a maximum size for protocol messages. Sending a message
358 // whose size exceeds this may result in the connection being dropped. A
359 // larger message size may be supported in the future or negotiated as
360 // part of a protocol upgrade.
361 if (header->payload_wire_size > maximiumMessageSize ||
362 header->uncompressed_size > maximiumMessageSize)
363 {
364 result.second = make_error_code(boost::system::errc::message_size);
365 return result;
366 }
367
368 // We requested uncompressed messages from the peer but received compressed.
369 if (!handler.compressionEnabled() &&
370 header->algorithm != compression::Algorithm::None)
371 {
372 result.second = make_error_code(boost::system::errc::protocol_error);
373 return result;
374 }
375
376 // We don't have the whole message yet. This isn't an error but we have
377 // nothing to do.
378 if (header->total_wire_size > size)
379 {
380 hint = header->total_wire_size - size;
381 return result;
382 }
383
384 bool success;
385
386 switch (header->message_type)
387 {
388 case protocol::mtMANIFESTS:
389 success = detail::invoke<protocol::TMManifests>(
390 *header, buffers, handler);
391 break;
392 case protocol::mtPING:
393 success =
394 detail::invoke<protocol::TMPing>(*header, buffers, handler);
395 break;
396 case protocol::mtCLUSTER:
397 success =
398 detail::invoke<protocol::TMCluster>(*header, buffers, handler);
399 break;
400 case protocol::mtENDPOINTS:
401 success = detail::invoke<protocol::TMEndpoints>(
402 *header, buffers, handler);
403 break;
404 case protocol::mtTRANSACTION:
405 success = detail::invoke<protocol::TMTransaction>(
406 *header, buffers, handler);
407 break;
408 case protocol::mtGET_LEDGER:
409 success = detail::invoke<protocol::TMGetLedger>(
410 *header, buffers, handler);
411 break;
412 case protocol::mtLEDGER_DATA:
413 success = detail::invoke<protocol::TMLedgerData>(
414 *header, buffers, handler);
415 break;
416 case protocol::mtPROPOSE_LEDGER:
417 success = detail::invoke<protocol::TMProposeSet>(
418 *header, buffers, handler);
419 break;
420 case protocol::mtSTATUS_CHANGE:
421 success = detail::invoke<protocol::TMStatusChange>(
422 *header, buffers, handler);
423 break;
424 case protocol::mtHAVE_SET:
425 success = detail::invoke<protocol::TMHaveTransactionSet>(
426 *header, buffers, handler);
427 break;
428 case protocol::mtVALIDATION:
429 success = detail::invoke<protocol::TMValidation>(
430 *header, buffers, handler);
431 break;
432 case protocol::mtVALIDATORLIST:
433 success = detail::invoke<protocol::TMValidatorList>(
434 *header, buffers, handler);
435 break;
436 case protocol::mtVALIDATORLISTCOLLECTION:
437 success = detail::invoke<protocol::TMValidatorListCollection>(
438 *header, buffers, handler);
439 break;
440 case protocol::mtGET_OBJECTS:
441 success = detail::invoke<protocol::TMGetObjectByHash>(
442 *header, buffers, handler);
443 break;
444 case protocol::mtHAVE_TRANSACTIONS:
445 success = detail::invoke<protocol::TMHaveTransactions>(
446 *header, buffers, handler);
447 break;
448 case protocol::mtTRANSACTIONS:
449 success = detail::invoke<protocol::TMTransactions>(
450 *header, buffers, handler);
451 break;
452 case protocol::mtSQUELCH:
453 success =
454 detail::invoke<protocol::TMSquelch>(*header, buffers, handler);
455 break;
456 case protocol::mtPROOF_PATH_REQ:
457 success = detail::invoke<protocol::TMProofPathRequest>(
458 *header, buffers, handler);
459 break;
460 case protocol::mtPROOF_PATH_RESPONSE:
461 success = detail::invoke<protocol::TMProofPathResponse>(
462 *header, buffers, handler);
463 break;
464 case protocol::mtREPLAY_DELTA_REQ:
465 success = detail::invoke<protocol::TMReplayDeltaRequest>(
466 *header, buffers, handler);
467 break;
468 case protocol::mtREPLAY_DELTA_RESPONSE:
469 success = detail::invoke<protocol::TMReplayDeltaResponse>(
470 *header, buffers, handler);
471 break;
472 default:
473 handler.onMessageUnknown(header->message_type);
474 success = true;
475 break;
476 }
477
478 result.first = header->total_wire_size;
479
480 if (!success)
481 result.second = make_error_code(boost::system::errc::bad_message);
482
483 return result;
484}
485
486} // namespace ripple
487
488#endif
Implements ZeroCopyInputStream around a buffer sequence.
T data(T... args)
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:49
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:26
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)
Definition: token_errors.h:97
constexpr std::size_t maximiumMessageSize
Definition: Message.h:33
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.