Fabcoin Core  0.16.2
P2P Digital Currency
RLPXFrameWriter.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16  */
22 #include "RLPXFrameWriter.h"
23 
24 using namespace std;
25 using namespace dev;
26 using namespace dev::p2p;
27 
28 const uint16_t RLPXFrameWriter::EmptyFrameLength = h128::size * 3; // header + headerMAC + frameMAC
29 const uint16_t RLPXFrameWriter::MinFrameDequeLength = h128::size * 4; // header + headerMAC + padded-block + frameMAC
30 
31 void RLPXFrameWriter::enque(RLPXPacket&& _p, PacketPriority _priority)
32 {
33  if (!_p.isValid())
34  return;
35  WriterState& qs = _priority ? m_q.first : m_q.second;
36  DEV_GUARDED(qs.x)
37  qs.q.push_back(move(_p));
38 }
39 
40 void RLPXFrameWriter::enque(uint8_t _packetType, RLPStream& _payload, PacketPriority _priority)
41 {
42  enque(RLPXPacket(m_protocolId, (RLPStream() << _packetType), _payload), _priority);
43 }
44 
45 size_t RLPXFrameWriter::mux(RLPXFrameCoder& _coder, unsigned _size, deque<bytes>& o_toWrite)
46 {
47  static const size_t c_blockSize = h128::size;
48  static const size_t c_overhead = c_blockSize * 3; // header + headerMac + frameMAC
49  if (_size < c_overhead + c_blockSize)
50  return 0;
51 
52  size_t ret = 0;
53  size_t frameLen = _size / 16 * 16;
54  bytes payload(0);
55  bool swapQueues = false;
56  while (frameLen >= c_overhead + c_blockSize)
57  {
58  bool highPending = false;
59  bool lowPending = false;
60  DEV_GUARDED(m_q.first.x)
61  highPending = !!m_q.first.q.size();
62  DEV_GUARDED(m_q.second.x)
63  lowPending = !!m_q.second.q.size();
64 
65  if (!highPending && !lowPending)
66  return ret;
67 
68  // first run when !swapQueues, high > low, otherwise low > high
69  bool high = highPending && !swapQueues ? true : !lowPending;
70  WriterState &qs = high ? m_q.first : m_q.second;
71  size_t frameAllot = (!swapQueues && highPending && lowPending ? frameLen / 2 - (c_overhead + c_blockSize) > 0 ? frameLen / 2 : frameLen : frameLen) - c_overhead;
72  size_t offset = 0;
73  size_t length = 0;
74  while (frameAllot >= c_blockSize)
75  {
76  // Invariants:
77  // !qs.writing && payload.empty() initial entry
78  // !qs.writing && !payload.empty() continuation (multiple packets per frame)
79  // qs.writing && payload.empty() initial entry, continuation (multiple frames per packet)
80  // qs.writing && !payload.empty() INVALID
81 
82  // write packet-type
83  if (qs.writing == nullptr)
84  {
85  {
86  Guard l(qs.x);
87  if (!qs.q.empty())
88  qs.writing = &qs.q[0];
89  else
90  break;
91  }
92 
93  // break here if we can't write-out packet-type
94  // or payload is packed and next packet won't fit (implicit)
95  qs.multiFrame = qs.writing->size() > frameAllot;
96  assert(qs.writing->type().size());
97  if (qs.writing->type().size() > frameAllot || (qs.multiFrame && !payload.empty()))
98  {
99  qs.writing = nullptr;
100  qs.remaining = 0;
101  qs.multiFrame = false;
102  break;
103  }
104  else if (qs.multiFrame)
105  qs.sequence = ++m_sequenceId;
106 
107  frameAllot -= qs.writing->type().size();
108  payload += qs.writing->type();
109 
110  qs.remaining = qs.writing->data().size();
111  }
112 
113  // write payload w/remaining allotment
114  assert(qs.multiFrame || (!qs.multiFrame && frameAllot >= qs.remaining));
115  if (frameAllot && qs.remaining)
116  {
117  offset = qs.writing->data().size() - qs.remaining;
118  length = qs.remaining <= frameAllot ? qs.remaining : frameAllot;
119  bytes portion = bytesConstRef(&qs.writing->data()).cropped(offset, length).toBytes();
120  qs.remaining -= length;
121  frameAllot -= portion.size();
122  payload += portion;
123  }
124 
125  assert((!qs.remaining && (offset > 0 || !qs.multiFrame)) || (qs.remaining && qs.multiFrame));
126  if (!qs.remaining)
127  {
128  qs.writing = nullptr;
129  DEV_GUARDED(qs.x)
130  qs.q.pop_front();
131  ret++;
132  }
133  // qs.writing is left alone for first frame of multi-frame packet
134  if (qs.multiFrame)
135  break;
136  }
137 
138  if (!payload.empty())
139  {
140  if (qs.multiFrame)
141  if (offset == 0 && qs.writing)
142  // 1st frame of segmented packet writes total-size of packet
143  _coder.writeFrame(m_protocolId, qs.sequence, qs.writing->size(), &payload, payload);
144  else
145  _coder.writeFrame(m_protocolId, qs.sequence, &payload, payload);
146  else
147  _coder.writeFrame(m_protocolId, &payload, payload);
148 
149  assert(frameLen >= payload.size());
150  frameLen -= payload.size();
151  o_toWrite.push_back(payload);
152  payload.resize(0);
153 
154  if (!qs.remaining && qs.multiFrame)
155  qs.multiFrame = false;
156  }
157  else if (swapQueues)
158  break;
159  swapQueues = true;
160  }
161  return ret;
162 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
size_t size() const
Definition: RLPXPacket.h:57
bytes const & data() const
Definition: RLPXPacket.h:53
std::hash for asio::adress
Definition: Common.h:323
assert(len-trim+(2 *lenIndices)<=WIDTH)
void writeFrame(uint16_t _protocolType, bytesConstRef _payload, bytes &o_bytes)
Write single-frame payload of packet(s).
#define DEV_GUARDED(MUTEX)
Simple block guard.
Definition: Guards.h:144
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
std::vector< byte > bytes
Definition: Common.h:75
std::vector< unsigned char > toBytes() const
Definition: vector_ref.h:45
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
Queue and state for Writer Properties are used independently; only valid packets should be added to q...
RLPX Packet.
Definition: RLPXPacket.h:39
uint8_t const size_t const size
Definition: sha3.h:20
bytes const & type() const
Definition: RLPXPacket.h:51
Class for writing to an RLP bytestream.
Definition: RLP.h:383
Encoder/decoder transport for RLPx connection established by RLPXHandshake.