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  return true;
89  case protocol::mtPING:
90  case protocol::mtCLUSTER:
91  case protocol::mtPROPOSE_LEDGER:
92  case protocol::mtSTATUS_CHANGE:
93  case protocol::mtHAVE_SET:
94  case protocol::mtVALIDATION:
95  case protocol::mtGET_SHARD_INFO:
96  case protocol::mtSHARD_INFO:
97  case protocol::mtGET_PEER_SHARD_INFO:
98  case protocol::mtPEER_SHARD_INFO:
99  break;
100  }
101  return false;
102  }();
103 
104  if (compressible)
105  {
106  auto payload = static_cast<void const*>(buffer_.data() + headerBytes);
107 
108  auto compressedSize = ripple::compression::compress(
109  payload,
110  messageBytes,
111  [&](std::size_t inSize) { // size of required compressed buffer
114  });
115 
116  if (compressedSize <
117  (messageBytes - (headerBytesCompressed - headerBytes)))
118  {
120  setHeader(
122  compressedSize,
123  type,
124  Algorithm::LZ4,
125  messageBytes);
126  }
127  else
129  }
130 }
131 
167 void
169  std::uint8_t* in,
170  std::uint32_t payloadBytes,
171  int type,
172  Algorithm compression,
173  std::uint32_t uncompressedBytes)
174 {
175  auto h = in;
176 
177  auto pack = [](std::uint8_t*& in, std::uint32_t size) {
178  *in++ = static_cast<std::uint8_t>(
179  (size >> 24) & 0x0F); // leftmost 4 are compression bits
180  *in++ = static_cast<std::uint8_t>((size >> 16) & 0xFF);
181  *in++ = static_cast<std::uint8_t>((size >> 8) & 0xFF);
182  *in++ = static_cast<std::uint8_t>(size & 0xFF);
183  };
184 
185  pack(in, payloadBytes);
186 
187  *in++ = static_cast<std::uint8_t>((type >> 8) & 0xFF);
188  *in++ = static_cast<std::uint8_t>(type & 0xFF);
189 
190  if (compression != Algorithm::None)
191  {
192  pack(in, uncompressedBytes);
193  *h |= static_cast<std::uint8_t>(compression);
194  }
195 }
196 
199 {
200  return buffer_.size();
201 }
202 
205 {
206  if (tryCompressed == Compressed::Off)
207  return buffer_;
208 
210 
211  if (bufferCompressed_.size() > 0)
212  return bufferCompressed_;
213  else
214  return buffer_;
215 }
216 
217 int
219 {
220  int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
221  return type;
222 }
223 
224 } // 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:204
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:218
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:168
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:198
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