All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
block.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2013, Regents of the University of California
4  *
5  * BSD license, See the LICENSE file for more information
6  *
7  * Author: Alexander Afanasyev <[email protected]>
8  */
9 
10 #include "common.hpp"
11 
12 #include "block.hpp"
13 #include "tlv.hpp"
14 #include "encoding-buffer.hpp"
15 
16 namespace ndn {
17 
19  : m_type(std::numeric_limits<uint32_t>::max())
20 {
21 }
22 
24  : m_buffer(buffer.m_buffer)
25  , m_begin(buffer.begin())
26  , m_end(buffer.end())
27  , m_size(m_end - m_begin)
28 {
31 
33  uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
34  if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
35  {
36  throw Tlv::Error("TLV length doesn't match buffer length");
37  }
38 }
39 
41  uint32_t type,
42  const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
43  const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
44  : m_buffer(wire)
45  , m_type(type)
46  , m_begin(begin)
47  , m_end(end)
48  , m_size(m_end - m_begin)
49  , m_value_begin(valueBegin)
50  , m_value_end(valueEnd)
51 {
52 }
53 
55  : m_buffer(buffer)
56  , m_begin(m_buffer->begin())
57  , m_end(m_buffer->end())
58  , m_size(m_end - m_begin)
59 {
62 
64 
65  uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
66  if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
67  {
68  throw Tlv::Error("TLV length doesn't match buffer length");
69  }
70 }
71 
73  const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
74  bool verifyLength/* = true*/)
75  : m_buffer(buffer)
76  , m_begin(begin)
77  , m_end(end)
78  , m_size(m_end - m_begin)
79 {
82 
84  uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
85  if (verifyLength)
86  {
87  if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
88  {
89  throw Tlv::Error("TLV length doesn't match buffer length");
90  }
91  }
92 }
93 
94 Block::Block(std::istream& is)
95 {
96  std::istream_iterator<uint8_t> tmp_begin(is);
97  std::istream_iterator<uint8_t> tmp_end;
98 
99  m_type = Tlv::readType(tmp_begin, tmp_end);
100  uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
101 
102  // We may still have some problem here, if some exception happens in this constructor,
103  // we may completely lose all the bytes extracted from the stream.
104 
105  OBufferStream os;
106  size_t headerLength = Tlv::writeVarNumber(os, m_type);
107  headerLength += Tlv::writeVarNumber(os, length);
108 
109  char* buf = new char[length];
110  buf[0] = *tmp_begin;
111  is.read(buf+1, length-1);
112 
113  if (length != static_cast<uint64_t>(is.gcount()) + 1)
114  {
115  delete [] buf;
116  throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
117  }
118 
119  os.write(buf, length);
120  delete [] buf;
121 
122  m_buffer = os.buf();
123 
124  m_begin = m_buffer->begin();
125  m_end = m_buffer->end();
126  m_size = m_end - m_begin;
127 
128  m_value_begin = m_buffer->begin() + headerLength;
129  m_value_end = m_buffer->end();
130 }
131 
132 
133 Block::Block(const uint8_t* buffer, size_t maxlength)
134 {
135  const uint8_t* tmp_begin = buffer;
136  const uint8_t* tmp_end = buffer + maxlength;
137 
138  m_type = Tlv::readType(tmp_begin, tmp_end);
139  uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
140 
141  if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
142  {
143  throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
144  }
145 
146  m_buffer = ptr_lib::make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
147 
148  m_begin = m_buffer->begin();
149  m_end = m_buffer->end();
150  m_size = m_end - m_begin;
151 
152  m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
153  m_value_end = m_buffer->end();
154 }
155 
156 Block::Block(const void* bufferX, size_t maxlength)
157 {
158  const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
159 
160  const uint8_t* tmp_begin = buffer;
161  const uint8_t* tmp_end = buffer + maxlength;
162 
163  m_type = Tlv::readType(tmp_begin, tmp_end);
164  uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
165 
166  if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
167  {
168  throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
169  }
170 
171  m_buffer = ptr_lib::make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
172 
173  m_begin = m_buffer->begin();
174  m_end = m_buffer->end();
175  m_size = m_end - m_begin;
176 
177  m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
178  m_value_end = m_buffer->end();
179 }
180 
181 Block::Block(uint32_t type)
182  : m_type(type)
183 {
184 }
185 
186 Block::Block(uint32_t type, const ConstBufferPtr& value)
187  : m_buffer(value)
188  , m_type(type)
189  , m_begin(m_buffer->end())
190  , m_end(m_buffer->end())
191  , m_value_begin(m_buffer->begin())
192  , m_value_end(m_buffer->end())
193 {
195 }
196 
197 Block::Block(uint32_t type, const Block& value)
198  : m_buffer(value.m_buffer)
199  , m_type(type)
200  , m_begin(m_buffer->end())
201  , m_end(m_buffer->end())
202  , m_value_begin(value.begin())
203  , m_value_end(value.end())
204 {
206 }
207 
208 bool
209 Block::fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block)
210 {
211  Buffer::const_iterator tempBegin = wire->begin() + offset;
212 
213  uint32_t type;
214  bool isOk = Tlv::readType(tempBegin, wire->end(), type);
215  if (!isOk)
216  return false;
217 
218  uint64_t length;
219  isOk = Tlv::readVarNumber(tempBegin, wire->end(), length);
220  if (!isOk)
221  return false;
222 
223  if (length > static_cast<uint64_t>(wire->end() - tempBegin))
224  {
225  return false;
226  }
227 
228  block = Block(wire, type,
229  wire->begin() + offset, tempBegin + length,
230  tempBegin, tempBegin + length);
231 
232  return true;
233 }
234 
235 bool
236 Block::fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block)
237 {
238  const uint8_t* tempBegin = buffer;
239  const uint8_t* tempEnd = buffer + maxSize;
240 
241  uint32_t type = 0;
242  bool isOk = Tlv::readType(tempBegin, tempEnd, type);
243  if (!isOk)
244  return false;
245 
246  uint64_t length;
247  isOk = Tlv::readVarNumber(tempBegin, tempEnd, length);
248  if (!isOk)
249  return false;
250 
251  if (length > static_cast<uint64_t>(tempEnd - tempBegin))
252  {
253  return false;
254  }
255 
256  BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
257  block = Block(sharedBuffer, type,
258  sharedBuffer->begin(), sharedBuffer->end(),
259  sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end());
260 
261  return true;
262 }
263 
264 void
266 {
267  if (!m_subBlocks.empty() || value_size() == 0)
268  return;
269 
270  Buffer::const_iterator begin = value_begin();
271  Buffer::const_iterator end = value_end();
272 
273  while (begin != end)
274  {
275  Buffer::const_iterator element_begin = begin;
276 
277  uint32_t type = Tlv::readType(begin, end);
278  uint64_t length = Tlv::readVarNumber(begin, end);
279 
280  if (length > static_cast<uint64_t>(end - begin))
281  {
282  m_subBlocks.clear();
283  throw Tlv::Error("TLV length exceeds buffer length");
284  }
285  Buffer::const_iterator element_end = begin + length;
286 
287  m_subBlocks.push_back(Block(m_buffer,
288  type,
289  element_begin, element_end,
290  begin, element_end));
291 
292  begin = element_end;
293  // don't do recursive parsing, just the top level
294  }
295 }
296 
297 void
299 {
300  if (hasWire())
301  return;
302 
303  OBufferStream os;
304  Tlv::writeVarNumber(os, type());
305 
306  if (hasValue())
307  {
309  os.write(reinterpret_cast<const char*>(value()), value_size());
310  }
311  else if (m_subBlocks.size() == 0)
312  {
313  Tlv::writeVarNumber(os, 0);
314  }
315  else
316  {
317  size_t valueSize = 0;
318  for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
319  valueSize += i->size();
320  }
321 
322  Tlv::writeVarNumber(os, valueSize);
323 
324  for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
325  if (i->hasWire())
326  os.write(reinterpret_cast<const char*>(i->wire()), i->size());
327  else if (i->hasValue()) {
328  Tlv::writeVarNumber(os, i->type());
329  Tlv::writeVarNumber(os, i->value_size());
330  os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
331  }
332  else
333  throw Error("Underlying value buffer is empty");
334  }
335  }
336 
337  // now assign correct block
338 
339  m_buffer = os.buf();
340  m_begin = m_buffer->begin();
341  m_end = m_buffer->end();
342  m_size = m_end - m_begin;
343 
344  m_value_begin = m_buffer->begin();
345  m_value_end = m_buffer->end();
346 
349 }
350 
351 Block
353 {
354  if (value_size() == 0)
355  throw Error("Underlying value buffer is empty");
356 
357  Buffer::const_iterator begin = value_begin(),
358  end = value_end();
359 
360  Buffer::const_iterator element_begin = begin;
361 
362  uint32_t type = Tlv::readType(begin, end);
363  uint64_t length = Tlv::readVarNumber(begin, end);
364 
365  if (length != static_cast<uint64_t>(end - begin))
366  throw Tlv::Error("TLV length mismatches buffer length");
367 
368  return Block(m_buffer,
369  type,
370  element_begin, end,
371  begin, end);
372 }
373 
374 } // namespace ndn
Class implementing interface similar to ostringstream, but to construct ndn::Buffer.
Definition: buffer.hpp:176
bool hasValue() const
Check if the Block has value block (no type and length are encoded)
Definition: block.hpp:294
size_t writeVarNumber(std::ostream &os, uint64_t varNumber)
Write VAR-NUMBER to the specified stream.
Definition: tlv.hpp:344
size_t sizeOfVarNumber(uint64_t varNumber)
Get number of bytes necessary to hold value of VAR-NUMBER.
Definition: tlv.hpp:327
Buffer::const_iterator end() const
Definition: block.hpp:406
Buffer::const_iterator m_begin
Definition: block.hpp:265
bool readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t &number)
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:182
ptr_lib::shared_ptr< Buffer > BufferPtr
Definition: buffer.hpp:19
Class representing wire element of the NDN packet.
Definition: block.hpp:26
Buffer::const_iterator value_begin() const
Definition: block.hpp:425
Buffer::const_iterator value_end() const
Definition: block.hpp:431
uint32_t m_size
Definition: block.hpp:267
ConstBufferPtr m_buffer
Definition: block.hpp:261
ptr_lib::shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:17
Buffer::const_iterator m_value_end
Definition: block.hpp:270
Block blockFromValue() const
Definition: block.cpp:352
ptr_lib::shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
Definition: buffer.hpp:192
element_container::const_iterator element_const_iterator
Definition: block.hpp:31
size_t value_size() const
Definition: block.hpp:455
void parse() const
Parse wire buffer into subblocks.
Definition: block.cpp:265
uint32_t type() const
Definition: block.hpp:320
void encode()
Encode subblocks into wire buffer.
Definition: block.cpp:298
element_container m_subBlocks
Definition: block.hpp:272
Buffer::const_iterator m_end
Definition: block.hpp:266
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.hpp:288
static bool fromBuffer(const ConstBufferPtr &wire, size_t offset, Block &block)
Try to construct block from Buffer, referencing data block pointed by wire.
Definition: block.cpp:209
const uint8_t * value() const
Definition: block.hpp:446
bool readType(InputIterator &begin, const InputIterator &end, uint32_t &type)
Read TLV Type.
Definition: tlv.hpp:227
uint32_t m_type
Definition: block.hpp:263
Buffer::const_iterator m_value_begin
Definition: block.hpp:269
Block()
Default constructor to create an empty Block.
Definition: block.cpp:18
Error that can be thrown from Block.
Definition: block.hpp:34
Buffer::const_iterator begin() const
Definition: block.hpp:397