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 < (messageBytes - (headerBytesCompressed - headerBytes)))
96  {
98  setHeader(bufferCompressed_.data(), compressedSize, type, Algorithm::LZ4, messageBytes);
99  }
100  else
102  }
103 }
104 
118 void
119 Message::setHeader(std::uint8_t* in, std::uint32_t payloadBytes, int type,
120  Algorithm comprAlgorithm, std::uint32_t uncompressedBytes)
121 {
122  auto h = in;
123 
124  auto pack = [](std::uint8_t*& in, std::uint32_t size) {
125  *in++ = static_cast<std::uint8_t>((size >> 24) & 0x0F); // leftmost 4 are compression bits
126  *in++ = static_cast<std::uint8_t>((size >> 16) & 0xFF);
127  *in++ = static_cast<std::uint8_t>((size >> 8) & 0xFF);
128  *in++ = static_cast<std::uint8_t>(size & 0xFF);
129  };
130 
131  pack(in, payloadBytes);
132 
133  *in++ = static_cast<std::uint8_t>((type >> 8) & 0xFF);
134  *in++ = static_cast<std::uint8_t> (type & 0xFF);
135 
136  if (comprAlgorithm != Algorithm::None)
137  {
138  pack(in, uncompressedBytes);
139  *h |= 0x80 | (static_cast<uint8_t>(comprAlgorithm) << 4);
140  }
141 }
142 
145 {
146  if (tryCompressed == Compressed::Off)
147  return buffer_;
148 
150 
151  if (bufferCompressed_.size() > 0)
152  return bufferCompressed_;
153  else
154  return buffer_;
155 }
156 
157 int
159 {
160  int type = (static_cast<int>(*(in + 4)) << 8) + *(in + 5);
161  return type;
162 }
163 
164 }
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:144
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:158
ripple::Message::once_flag_
std::once_flag once_flag_
Definition: overlay/Message.h:80
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:119
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:83
ripple::compression::Compressed
Compressed
Definition: Compression.h:39
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:77
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:78
std::size_t
ripple::compression::headerBytesCompressed
constexpr std::size_t headerBytesCompressed
Definition: Compression.h:32
std::vector::data
T data(T... args)