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 
26 Message::Message(::google::protobuf::Message const& message, int type)
27  : category_(TrafficCount::categorize(message, type, false))
28 {
29  using namespace ripple::compression;
30 
31 #if defined(GOOGLE_PROTOBUF_VERSION) && (GOOGLE_PROTOBUF_VERSION >= 3011000)
32  auto const messageBytes = message.ByteSizeLong();
33 #else
34  unsigned const messageBytes = message.ByteSize();
35 #endif
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 
47 void
49 {
50  using namespace ripple::compression;
51  auto const messageBytes = buffer_.size() - headerBytes;
52 
53  auto type = getType(buffer_.data());
54 
55  bool const compressible = [&] {
56  if (messageBytes <= 70)
57  return false;
58  switch (type)
59  {
60  case protocol::mtMANIFESTS:
61  case protocol::mtENDPOINTS:
62  case protocol::mtTRANSACTION:
63  case protocol::mtGET_LEDGER:
64  case protocol::mtLEDGER_DATA:
65  case protocol::mtGET_OBJECTS:
66  case protocol::mtVALIDATORLIST:
67  return true;
68  case protocol::mtPING:
69  case protocol::mtCLUSTER:
70  case protocol::mtPROPOSE_LEDGER:
71  case protocol::mtSTATUS_CHANGE:
72  case protocol::mtHAVE_SET:
73  case protocol::mtVALIDATION:
74  case protocol::mtGET_SHARD_INFO:
75  case protocol::mtSHARD_INFO:
76  case protocol::mtGET_PEER_SHARD_INFO:
77  case protocol::mtPEER_SHARD_INFO:
78  break;
79  }
80  return false;
81  }();
82 
83  if (compressible)
84  {
85  auto payload = static_cast<void const*>(buffer_.data() + headerBytes);
86 
87  auto compressedSize = ripple::compression::compress(
88  payload,
89  messageBytes,
90  [&](std::size_t inSize) { // size of required compressed buffer
93  });
94 
95  if (compressedSize <
96  (messageBytes - (headerBytesCompressed - headerBytes)))
97  {
99  setHeader(
101  compressedSize,
102  type,
103  Algorithm::LZ4,
104  messageBytes);
105  }
106  else
108  }
109 }
110 
122 void
124  std::uint8_t* in,
125  std::uint32_t payloadBytes,
126  int type,
127  Algorithm comprAlgorithm,
128  std::uint32_t uncompressedBytes)
129 {
130  auto h = in;
131 
132  auto pack = [](std::uint8_t*& in, std::uint32_t size) {
133  *in++ = static_cast<std::uint8_t>(
134  (size >> 24) & 0x0F); // leftmost 4 are compression bits
135  *in++ = static_cast<std::uint8_t>((size >> 16) & 0xFF);
136  *in++ = static_cast<std::uint8_t>((size >> 8) & 0xFF);
137  *in++ = static_cast<std::uint8_t>(size & 0xFF);
138  };
139 
140  pack(in, payloadBytes);
141 
142  *in++ = static_cast<std::uint8_t>((type >> 8) & 0xFF);
143  *in++ = static_cast<std::uint8_t>(type & 0xFF);
144 
145  if (comprAlgorithm != Algorithm::None)
146  {
147  pack(in, uncompressedBytes);
148  *h |= 0x80 | (static_cast<uint8_t>(comprAlgorithm) << 4);
149  }
150 }
151 
154 {
155  if (tryCompressed == Compressed::Off)
156  return buffer_;
157 
159 
160  if (bufferCompressed_.size() > 0)
161  return bufferCompressed_;
162  else
163  return buffer_;
164 }
165 
166 int
168 {
169  int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
170  return type;
171 }
172 
173 } // 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:153
ripple::Message::compress
void compress()
Try to compress the payload.
Definition: Message.cpp:48
ripple::TrafficCount
Definition: TrafficCount.h:32
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:167
ripple::Message::once_flag_
std::once_flag once_flag_
Definition: overlay/Message.h:81
ripple::QualityDirection::in
@ in
ripple::Message::setHeader
void setHeader(std::uint8_t *in, std::uint32_t payloadBytes, int type, Algorithm comprAlgorithm, std::uint32_t uncompressedBytes)
Set the payload header.
Definition: Message.cpp:123
ripple::Message::Message
Message(::google::protobuf::Message const &message, int type)
Constructor.
Definition: Message.cpp:26
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:85
ripple::compression::Compressed
Compressed
Definition: Compression.h:36
cstdint
std::uint8_t
ripple::compression
Definition: Compression.h:29
ripple::compression::Algorithm
Algorithm
Definition: Compression.h:34
ripple::Message::buffer_
std::vector< uint8_t > buffer_
Definition: overlay/Message.h:78
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:79
std::size_t
ripple::compression::headerBytesCompressed
constexpr std::size_t headerBytesCompressed
Definition: Compression.h:32
std::vector::data
T data(T... args)