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  boost::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  return true;
90  case protocol::mtPING:
91  case protocol::mtCLUSTER:
92  case protocol::mtPROPOSE_LEDGER:
93  case protocol::mtSTATUS_CHANGE:
94  case protocol::mtHAVE_SET:
95  case protocol::mtVALIDATION:
96  case protocol::mtGET_SHARD_INFO:
97  case protocol::mtSHARD_INFO:
98  case protocol::mtGET_PEER_SHARD_INFO:
99  case protocol::mtPEER_SHARD_INFO:
100  case protocol::mtPROOF_PATH_REQ:
101  case protocol::mtPROOF_PATH_RESPONSE:
102  case protocol::mtREPLAY_DELTA_REQ:
103  break;
104  }
105  return false;
106  }();
107 
108  if (compressible)
109  {
110  auto payload = static_cast<void const*>(buffer_.data() + headerBytes);
111 
112  auto compressedSize = ripple::compression::compress(
113  payload,
114  messageBytes,
115  [&](std::size_t inSize) { // size of required compressed buffer
118  });
119 
120  if (compressedSize <
121  (messageBytes - (headerBytesCompressed - headerBytes)))
122  {
124  setHeader(
126  compressedSize,
127  type,
128  Algorithm::LZ4,
129  messageBytes);
130  }
131  else
133  }
134 }
135 
171 void
173  std::uint8_t* in,
174  std::uint32_t payloadBytes,
175  int type,
176  Algorithm compression,
177  std::uint32_t uncompressedBytes)
178 {
179  auto h = in;
180 
181  auto pack = [](std::uint8_t*& in, std::uint32_t size) {
182  *in++ = static_cast<std::uint8_t>(
183  (size >> 24) & 0x0F); // leftmost 4 are compression bits
184  *in++ = static_cast<std::uint8_t>((size >> 16) & 0xFF);
185  *in++ = static_cast<std::uint8_t>((size >> 8) & 0xFF);
186  *in++ = static_cast<std::uint8_t>(size & 0xFF);
187  };
188 
189  pack(in, payloadBytes);
190 
191  *in++ = static_cast<std::uint8_t>((type >> 8) & 0xFF);
192  *in++ = static_cast<std::uint8_t>(type & 0xFF);
193 
194  if (compression != Algorithm::None)
195  {
196  pack(in, uncompressedBytes);
197  *h |= static_cast<std::uint8_t>(compression);
198  }
199 }
200 
203 {
204  return buffer_.size();
205 }
206 
209 {
210  if (tryCompressed == Compressed::Off)
211  return buffer_;
212 
214 
215  if (bufferCompressed_.size() > 0)
216  return bufferCompressed_;
217  else
218  return buffer_;
219 }
220 
221 int
223 {
224  int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
225  return type;
226 }
227 
228 } // 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:208
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:222
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:172
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::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:202
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::size_t
ripple::compression::headerBytesCompressed
constexpr std::size_t headerBytesCompressed
Definition: Compression.h:32
std::vector::data
T data(T... args)
ripple::Message::Message
Message(::google::protobuf::Message const &message, int type, boost::optional< PublicKey > const &validator={})
Constructor.
Definition: Message.cpp:26