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