rippled
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 <ripple/overlay/Message.h>
21 #include <ripple/overlay/impl/TrafficCount.h>
22 #include <cstdint>
23 
24 namespace 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  assert(messageBytes != 0);
38 
39  buffer_.resize(headerBytes + messageBytes);
40 
41  setHeader(buffer_.data(), messageBytes, type, Algorithm::None, 0);
42 
43  if (messageBytes != 0)
44  message.SerializeToArray(buffer_.data() + headerBytes, messageBytes);
45 
46  assert(getBufferSize() == totalSize(message));
47 }
48 
49 // static
51 Message::messageSize(::google::protobuf::Message const& message)
52 {
53 #if defined(GOOGLE_PROTOBUF_VERSION) && (GOOGLE_PROTOBUF_VERSION >= 3011000)
54  return message.ByteSizeLong();
55 #else
56  return message.ByteSize();
57 #endif
58 }
59 
60 // static
62 Message::totalSize(::google::protobuf::Message const& message)
63 {
64  return messageSize(message) + compression::headerBytes;
65 }
66 
67 void
69 {
70  using namespace ripple::compression;
71  auto const messageBytes = buffer_.size() - headerBytes;
72 
73  auto type = getType(buffer_.data());
74 
75  bool const compressible = [&] {
76  if (messageBytes <= 70)
77  return false;
78  switch (type)
79  {
80  case protocol::mtMANIFESTS:
81  case protocol::mtENDPOINTS:
82  case protocol::mtTRANSACTION:
83  case protocol::mtGET_LEDGER:
84  case protocol::mtLEDGER_DATA:
85  case protocol::mtGET_OBJECTS:
86  case protocol::mtVALIDATORLIST:
87  case protocol::mtVALIDATORLISTCOLLECTION:
88  case protocol::mtREPLAY_DELTA_RESPONSE:
89  case protocol::mtTRANSACTIONS:
90  return true;
91  case protocol::mtPING:
92  case protocol::mtCLUSTER:
93  case protocol::mtPROPOSE_LEDGER:
94  case protocol::mtSTATUS_CHANGE:
95  case protocol::mtHAVE_SET:
96  case protocol::mtVALIDATION:
97  case protocol::mtGET_PEER_SHARD_INFO:
98  case protocol::mtPEER_SHARD_INFO:
99  case protocol::mtPROOF_PATH_REQ:
100  case protocol::mtPROOF_PATH_RESPONSE:
101  case protocol::mtREPLAY_DELTA_REQ:
102  case protocol::mtGET_PEER_SHARD_INFO_V2:
103  case protocol::mtPEER_SHARD_INFO_V2:
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
120  });
121 
122  if (compressedSize <
123  (messageBytes - (headerBytesCompressed - headerBytes)))
124  {
126  setHeader(
128  compressedSize,
129  type,
130  Algorithm::LZ4,
131  messageBytes);
132  }
133  else
135  }
136 }
137 
173 void
175  std::uint8_t* in,
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 
223 int
225 {
226  int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
227  return type;
228 }
229 
230 } // namespace ripple
std::call_once
T call_once(T... args)
std::vector::resize
T resize(T... args)
ripple::Message::getBuffer
std::vector< uint8_t > const & getBuffer(Compressed tryCompressed)
Retrieve the packed message data.
Definition: Message.cpp:210
ripple::Message::compress
void compress()
Try to compress the payload.
Definition: Message.cpp:68
ripple::TrafficCount
Definition: TrafficCount.h:32
ripple::Message::totalSize
static std::size_t totalSize(::google::protobuf::Message const &message)
Definition: Message.cpp:62
ripple::Message::messageSize
static std::size_t messageSize(::google::protobuf::Message const &message)
Definition: Message.cpp:51
std::vector< uint8_t >
std::vector::size
T size(T... args)
ripple::compression::headerBytes
constexpr std::size_t headerBytes
Definition: Compression.h:31
ripple::Message::getType
int getType(std::uint8_t const *in) const
Get the message type from the payload header.
Definition: Message.cpp:224
ripple::Message::setHeader
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
ripple::Message::once_flag_
std::once_flag once_flag_
Definition: overlay/Message.h:107
ripple::QualityDirection::in
@ in
ripple::compression::compress
std::size_t compress(void const *in, std::size_t inSize, BufferFactory &&bf, Algorithm algorithm=Algorithm::LZ4)
Compress input data.
Definition: Compression.h:87
ripple::Message::Message
Message(::google::protobuf::Message const &message, int type, std::optional< PublicKey > const &validator={})
Constructor.
Definition: Message.cpp:26
ripple::compression::Compressed::Off
@ Off
ripple::compression::Compressed
Compressed
Definition: Compression.h:38
cstdint
std::uint8_t
ripple::compression
Definition: Compression.h:29
ripple::compression::Algorithm
Algorithm
Definition: Compression.h:36
ripple::Message::buffer_
std::vector< uint8_t > buffer_
Definition: overlay/Message.h:104
ripple::Message::getBufferSize
std::size_t getBufferSize()
Retrieve the size of the packed but uncompressed message data.
Definition: Message.cpp:204
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Message::bufferCompressed_
std::vector< uint8_t > bufferCompressed_
Definition: overlay/Message.h:105
std::optional
std::size_t
ripple::compression::headerBytesCompressed
constexpr std::size_t headerBytesCompressed
Definition: Compression.h:32
std::vector::data
T data(T... args)