rippled
Loading...
Searching...
No Matches
Message.cpp
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#include <xrpld/overlay/Message.h>
21#include <xrpld/overlay/detail/TrafficCount.h>
22#include <cstdint>
23
24namespace ripple {
25
27 ::google::protobuf::Message const& message,
28 int type,
29 std::optional<PublicKey> const& validator)
30 : category_(TrafficCount::categorize(message, type, false))
31 , validatorKey_(validator)
32{
33 using namespace ripple::compression;
34
35 auto const messageBytes = messageSize(message);
36
37 XRPL_ASSERT(
38 messageBytes, "ripple::Message::Message : non-empty message input");
39
40 buffer_.resize(headerBytes + messageBytes);
41
42 setHeader(buffer_.data(), messageBytes, type, Algorithm::None, 0);
43
44 if (messageBytes != 0)
45 message.SerializeToArray(buffer_.data() + headerBytes, messageBytes);
46
47 XRPL_ASSERT(
48 getBufferSize() == totalSize(message),
49 "ripple::Message::Message : message size matches the buffer");
50}
51
52// static
54Message::messageSize(::google::protobuf::Message const& message)
55{
56#if defined(GOOGLE_PROTOBUF_VERSION) && (GOOGLE_PROTOBUF_VERSION >= 3011000)
57 return message.ByteSizeLong();
58#else
59 return message.ByteSize();
60#endif
61}
62
63// static
65Message::totalSize(::google::protobuf::Message const& message)
66{
67 return messageSize(message) + compression::headerBytes;
68}
69
70void
72{
73 using namespace ripple::compression;
74 auto const messageBytes = buffer_.size() - headerBytes;
75
76 auto type = getType(buffer_.data());
77
78 bool const compressible = [&] {
79 if (messageBytes <= 70)
80 return false;
81 switch (type)
82 {
83 case protocol::mtMANIFESTS:
84 case protocol::mtENDPOINTS:
85 case protocol::mtTRANSACTION:
86 case protocol::mtGET_LEDGER:
87 case protocol::mtLEDGER_DATA:
88 case protocol::mtGET_OBJECTS:
89 case protocol::mtVALIDATORLIST:
90 case protocol::mtVALIDATORLISTCOLLECTION:
91 case protocol::mtREPLAY_DELTA_RESPONSE:
92 case protocol::mtTRANSACTIONS:
93 return true;
94 case protocol::mtPING:
95 case protocol::mtCLUSTER:
96 case protocol::mtPROPOSE_LEDGER:
97 case protocol::mtSTATUS_CHANGE:
98 case protocol::mtHAVE_SET:
99 case protocol::mtVALIDATION:
100 case protocol::mtPROOF_PATH_REQ:
101 case protocol::mtPROOF_PATH_RESPONSE:
102 case protocol::mtREPLAY_DELTA_REQ:
103 case protocol::mtHAVE_TRANSACTIONS:
104 break;
105 }
106 return false;
107 }();
108
109 if (compressible)
110 {
111 auto payload = static_cast<void const*>(buffer_.data() + headerBytes);
112
113 auto compressedSize = ripple::compression::compress(
114 payload,
115 messageBytes,
116 [&](std::size_t inSize) { // size of required compressed buffer
117 bufferCompressed_.resize(inSize + headerBytesCompressed);
118 return (bufferCompressed_.data() + headerBytesCompressed);
119 });
120
121 if (compressedSize <
122 (messageBytes - (headerBytesCompressed - headerBytes)))
123 {
124 bufferCompressed_.resize(headerBytesCompressed + compressedSize);
125 setHeader(
127 compressedSize,
128 type,
129 Algorithm::LZ4,
130 messageBytes);
131 }
132 else
134 }
135}
136
172void
175 std::uint32_t payloadBytes,
176 int type,
177 Algorithm compression,
178 std::uint32_t uncompressedBytes)
179{
180 auto h = in;
181
182 auto pack = [](std::uint8_t*& in, std::uint32_t size) {
183 *in++ = static_cast<std::uint8_t>(
184 (size >> 24) & 0x0F); // leftmost 4 are compression bits
185 *in++ = static_cast<std::uint8_t>((size >> 16) & 0xFF);
186 *in++ = static_cast<std::uint8_t>((size >> 8) & 0xFF);
187 *in++ = static_cast<std::uint8_t>(size & 0xFF);
188 };
189
190 pack(in, payloadBytes);
191
192 *in++ = static_cast<std::uint8_t>((type >> 8) & 0xFF);
193 *in++ = static_cast<std::uint8_t>(type & 0xFF);
194
195 if (compression != Algorithm::None)
196 {
197 pack(in, uncompressedBytes);
198 *h |= static_cast<std::uint8_t>(compression);
199 }
200}
201
204{
205 return buffer_.size();
206}
207
210{
211 if (tryCompressed == Compressed::Off)
212 return buffer_;
213
215
216 if (bufferCompressed_.size() > 0)
217 return bufferCompressed_;
218 else
219 return buffer_;
220}
221
222int
224{
225 int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
226 return type;
227}
228
229} // namespace ripple
T call_once(T... args)
std::once_flag once_flag_
Definition: Message.h:107
Message(::google::protobuf::Message const &message, int type, std::optional< PublicKey > const &validator={})
Constructor.
Definition: Message.cpp:26
void setHeader(std::uint8_t *in, std::uint32_t payloadBytes, int type, Algorithm compression, std::uint32_t uncompressedBytes)
Set the payload header.
Definition: Message.cpp:173
std::vector< uint8_t > const & getBuffer(Compressed tryCompressed)
Retrieve the packed message data.
Definition: Message.cpp:209
std::size_t getBufferSize()
Retrieve the size of the packed but uncompressed message data.
Definition: Message.cpp:203
static std::size_t totalSize(::google::protobuf::Message const &message)
Definition: Message.cpp:65
std::vector< uint8_t > buffer_
Definition: Message.h:104
std::vector< uint8_t > bufferCompressed_
Definition: Message.h:105
int getType(std::uint8_t const *in) const
Get the message type from the payload header.
Definition: Message.cpp:223
void compress()
Try to compress the payload.
Definition: Message.cpp:71
static std::size_t messageSize(::google::protobuf::Message const &message)
Definition: Message.cpp:54
T data(T... args)
std::size_t constexpr headerBytes
Definition: Compression.h:31
std::size_t compress(void const *in, std::size_t inSize, BufferFactory &&bf, Algorithm algorithm=Algorithm::LZ4)
Compress input data.
Definition: Compression.h:89
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
T resize(T... args)
T size(T... args)