NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
block.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
24 #include "block.hpp"
25 #include "block-helpers.hpp"
26 
27 #include "tlv.hpp"
28 #include "encoding-buffer.hpp"
29 #include "buffer-stream.hpp"
30 
31 #include <boost/lexical_cast.hpp>
32 #include <boost/asio/buffer.hpp>
33 
34 namespace ndn {
35 
36 #if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
37 static_assert(std::is_nothrow_move_constructible<Block>::value,
38  "Block must be MoveConstructible with noexcept");
39 #endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
40 
41 #if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
42 static_assert(std::is_nothrow_move_assignable<Block>::value,
43  "Block must be MoveAssignable with noexcept");
44 #endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
45 
46 const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = 8800;
47 
49  : m_type(std::numeric_limits<uint32_t>::max())
50 {
51 }
52 
54  : m_buffer(const_cast<EncodingBuffer&>(buffer).getBuffer())
55  , m_begin(buffer.begin())
56  , m_end(buffer.end())
57  , m_size(m_end - m_begin)
58 {
61 
63  uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
64  if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
65  {
66  BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
67  }
68 }
69 
71  uint32_t type,
72  const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
73  const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
74  : m_buffer(wire)
75  , m_type(type)
76  , m_begin(begin)
77  , m_end(end)
78  , m_size(m_end - m_begin)
79  , m_value_begin(valueBegin)
80  , m_value_end(valueEnd)
81 {
82 }
83 
85  : m_buffer(buffer)
86  , m_begin(m_buffer->begin())
87  , m_end(m_buffer->end())
88  , m_size(m_end - m_begin)
89 {
92 
94 
95  uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
96  if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
97  {
98  BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
99  }
100 }
101 
103  const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
104  bool verifyLength/* = true*/)
105  : m_buffer(buffer)
106  , m_begin(begin)
107  , m_end(end)
108  , m_size(m_end - m_begin)
109 {
111  m_value_end = m_end;
112 
114  uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
115  if (verifyLength) {
116  if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
117  BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
118  }
119  }
120 }
121 
122 Block::Block(const Block& block,
123  const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
124  bool verifyLength/* = true*/)
125  : m_buffer(block.m_buffer)
126  , m_begin(begin)
127  , m_end(end)
128  , m_size(m_end - m_begin)
129 {
130  if (!(m_buffer->begin() <= begin && begin <= m_buffer->end()) ||
131  !(m_buffer->begin() <= end && end <= m_buffer->end())) {
132  BOOST_THROW_EXCEPTION(Error("begin/end iterators do not point to the underlying buffer of the block"));
133  }
134 
136  m_value_end = m_end;
137 
139  uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
140  if (verifyLength) {
141  if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
142  BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
143  }
144  }
145 }
146 
147 Block::Block(const uint8_t* buffer, size_t maxlength)
148 {
149  const uint8_t* tmp_begin = buffer;
150  const uint8_t* tmp_end = buffer + maxlength;
151 
152  m_type = tlv::readType(tmp_begin, tmp_end);
153  uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
154 
155  if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
156  {
157  BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
158  }
159 
160  m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
161 
162  m_begin = m_buffer->begin();
163  m_end = m_buffer->end();
164  m_size = m_end - m_begin;
165 
166  m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
167  m_value_end = m_buffer->end();
168 }
169 
170 Block::Block(const void* bufferX, size_t maxlength)
171 {
172  const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
173 
174  const uint8_t* tmp_begin = buffer;
175  const uint8_t* tmp_end = buffer + maxlength;
176 
177  m_type = tlv::readType(tmp_begin, tmp_end);
178  uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
179 
180  if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
181  {
182  BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
183  }
184 
185  m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
186 
187  m_begin = m_buffer->begin();
188  m_end = m_buffer->end();
189  m_size = m_end - m_begin;
190 
191  m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
192  m_value_end = m_buffer->end();
193 }
194 
196  : m_type(type)
197 {
198 }
199 
201  : m_buffer(value)
202  , m_type(type)
203  , m_begin(m_buffer->end())
204  , m_end(m_buffer->end())
206  , m_value_end(m_buffer->end())
207 {
209 }
210 
211 Block::Block(uint32_t type, const Block& value)
212  : m_buffer(value.m_buffer)
213  , m_type(type)
214  , m_begin(m_buffer->end())
215  , m_end(m_buffer->end())
216  , m_value_begin(value.begin())
217  , m_value_end(value.end())
218 {
220 }
221 
222 Block
223 Block::fromStream(std::istream& is)
224 {
225  std::istream_iterator<uint8_t> begin(is >> std::noskipws);
226  std::istream_iterator<uint8_t> end;
227 
228  uint32_t type = tlv::readType(begin, end);
229  uint64_t length = tlv::readVarNumber(begin, end);
230 
231  if (length == 0) {
232  return makeEmptyBlock(type);
233  }
234 
235  if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM)
236  BOOST_THROW_EXCEPTION(tlv::Error("Length of block from stream is too large"));
237 
238  // We may still have some problem here, if some exception happens,
239  // we may completely lose all the bytes extracted from the stream.
240 
242  buf[0] = *begin;
243  is.read(buf + 1, length - 1);
244 
245  if (length != static_cast<uint64_t>(is.gcount()) + 1) {
246  BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
247  }
248 
249  return makeBinaryBlock(type, buf, length);
250 }
251 
252 std::tuple<bool, Block>
253 Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
254 {
255  Buffer::const_iterator tempBegin = buffer->begin() + offset;
256 
257  uint32_t type;
258  bool isOk = tlv::readType(tempBegin, buffer->end(), type);
259  if (!isOk)
260  return std::make_tuple(false, Block());
261 
262  uint64_t length;
263  isOk = tlv::readVarNumber(tempBegin, buffer->end(), length);
264  if (!isOk)
265  return std::make_tuple(false, Block());
266 
267  if (length > static_cast<uint64_t>(buffer->end() - tempBegin))
268  return std::make_tuple(false, Block());
269 
270  return std::make_tuple(true, Block(buffer, type,
271  buffer->begin() + offset, tempBegin + length,
272  tempBegin, tempBegin + length));
273 }
274 
275 std::tuple<bool, Block>
276 Block::fromBuffer(const uint8_t* buffer, size_t maxSize)
277 {
278  const uint8_t* tempBegin = buffer;
279  const uint8_t* tempEnd = buffer + maxSize;
280 
281  uint32_t type = 0;
282  bool isOk = tlv::readType(tempBegin, tempEnd, type);
283  if (!isOk)
284  return std::make_tuple(false, Block());
285 
286  uint64_t length;
287  isOk = tlv::readVarNumber(tempBegin, tempEnd, length);
288  if (!isOk)
289  return std::make_tuple(false, Block());
290 
291  if (length > static_cast<uint64_t>(tempEnd - tempBegin))
292  return std::make_tuple(false, Block());
293 
294  BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
295  return std::make_tuple(true,
296  Block(sharedBuffer, type,
297  sharedBuffer->begin(), sharedBuffer->end(),
298  sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end()));
299 }
300 
301 void
303 {
304  m_buffer.reset(); // reset of the shared_ptr
305  m_subBlocks.clear(); // remove all parsed subelements
306 
307  m_type = std::numeric_limits<uint32_t>::max();
308  m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
309 }
310 
311 void
313 {
314  m_buffer.reset(); // reset of the shared_ptr
315  // keep subblocks
316 
317  // keep type
318  m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
319 }
320 
321 void
323 {
324  if (!m_subBlocks.empty() || value_size() == 0)
325  return;
326 
327  Buffer::const_iterator begin = value_begin();
328  Buffer::const_iterator end = value_end();
329 
330  while (begin != end)
331  {
332  Buffer::const_iterator element_begin = begin;
333 
334  uint32_t type = tlv::readType(begin, end);
335  uint64_t length = tlv::readVarNumber(begin, end);
336 
337  if (length > static_cast<uint64_t>(end - begin))
338  {
339  m_subBlocks.clear();
340  BOOST_THROW_EXCEPTION(tlv::Error("TLV length exceeds buffer length"));
341  }
342  Buffer::const_iterator element_end = begin + length;
343 
344  m_subBlocks.push_back(Block(m_buffer,
345  type,
346  element_begin, element_end,
347  begin, element_end));
348 
349  begin = element_end;
350  // don't do recursive parsing, just the top level
351  }
352 }
353 
354 void
356 {
357  if (hasWire())
358  return;
359 
360  OBufferStream os;
361  tlv::writeVarNumber(os, type());
362 
363  if (hasValue())
364  {
366  os.write(reinterpret_cast<const char*>(value()), value_size());
367  }
368  else if (m_subBlocks.size() == 0)
369  {
370  tlv::writeVarNumber(os, 0);
371  }
372  else
373  {
374  size_t valueSize = 0;
375  for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
376  valueSize += i->size();
377  }
378 
379  tlv::writeVarNumber(os, valueSize);
380 
381  for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
382  if (i->hasWire())
383  os.write(reinterpret_cast<const char*>(i->wire()), i->size());
384  else if (i->hasValue()) {
385  tlv::writeVarNumber(os, i->type());
386  tlv::writeVarNumber(os, i->value_size());
387  os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
388  }
389  else
390  BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty"));
391  }
392  }
393 
394  // now assign correct block
395 
396  m_buffer = os.buf();
397  m_begin = m_buffer->begin();
398  m_end = m_buffer->end();
399  m_size = m_end - m_begin;
400 
401  m_value_begin = m_buffer->begin();
402  m_value_end = m_buffer->end();
403 
406 }
407 
408 const Block&
409 Block::get(uint32_t type) const
410 {
411  element_const_iterator it = this->find(type);
412  if (it != m_subBlocks.end())
413  return *it;
414 
415  BOOST_THROW_EXCEPTION(Error("(Block::get) Requested a non-existed type [" +
416  boost::lexical_cast<std::string>(type) + "] from Block"));
417 }
418 
420 Block::find(uint32_t type) const
421 {
422  return std::find_if(m_subBlocks.begin(), m_subBlocks.end(),
423  [type] (const Block& subBlock) { return subBlock.type() == type; });
424 }
425 
426 void
428 {
429  resetWire();
430 
431  auto it = std::remove_if(m_subBlocks.begin(), m_subBlocks.end(),
432  [type] (const Block& subBlock) { return subBlock.type() == type; });
433  m_subBlocks.resize(it - m_subBlocks.begin());
434 }
435 
436 Block
438 {
439  if (value_size() == 0)
440  BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty"));
441 
442  Buffer::const_iterator begin = value_begin(),
443  end = value_end();
444 
445  Buffer::const_iterator element_begin = begin;
446 
447  uint32_t type = tlv::readType(begin, end);
448  uint64_t length = tlv::readVarNumber(begin, end);
449 
450  if (length != static_cast<uint64_t>(end - begin))
451  BOOST_THROW_EXCEPTION(tlv::Error("TLV length mismatches buffer length"));
452 
453  return Block(m_buffer,
454  type,
455  element_begin, end,
456  begin, end);
457 }
458 
459 Block::operator boost::asio::const_buffer() const
460 {
461  return boost::asio::const_buffer(wire(), size());
462 }
463 
464 bool
466 {
467  return m_type == std::numeric_limits<uint32_t>::max();
468 }
469 
470 bool
472 {
473  return m_buffer && (m_begin != m_end);
474 }
475 
476 Buffer::const_iterator
478 {
479  if (!hasWire())
480  BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
481 
482  return m_begin;
483 }
484 
485 Buffer::const_iterator
486 Block::end() const
487 {
488  if (!hasWire())
489  BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
490 
491  return m_end;
492 }
493 
494 const uint8_t*
495 Block::wire() const
496 {
497  if (!hasWire())
498  BOOST_THROW_EXCEPTION(Error("(Block::wire) Underlying wire buffer is empty"));
499 
500  return &*m_begin;
501 }
502 
503 size_t
504 Block::size() const
505 {
506  if (hasWire() || hasValue()) {
507  return m_size;
508  }
509  else
510  BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
511 }
512 
513 bool
515 {
516  return static_cast<bool>(m_buffer);
517 }
518 
519 const uint8_t*
521 {
522  if (!hasValue())
523  return 0;
524 
525  return &*m_value_begin;
526 }
527 
528 size_t
530 {
531  if (!hasValue())
532  return 0;
533 
534  return m_value_end - m_value_begin;
535 }
536 
539 {
540  resetWire();
541 
542 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
543  return m_subBlocks.erase(position);
544 #else
545  element_iterator it = m_subBlocks.begin();
546  std::advance(it, std::distance(m_subBlocks.cbegin(), position));
547  return m_subBlocks.erase(it);
548 #endif
549 }
550 
553 {
554  resetWire();
555 
556 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
557  return m_subBlocks.erase(first, last);
558 #else
559  element_iterator itStart = m_subBlocks.begin();
560  element_iterator itEnd = m_subBlocks.begin();
561  std::advance(itStart, std::distance(m_subBlocks.cbegin(), first));
562  std::advance(itEnd, std::distance(m_subBlocks.cbegin(), last));
563  return m_subBlocks.erase(itStart, itEnd);
564 #endif
565 }
566 
567 void
568 Block::push_back(const Block& element)
569 {
570  resetWire();
571  m_subBlocks.push_back(element);
572 }
573 
576 {
577  resetWire();
578 
579 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
580  return m_subBlocks.insert(pos, element);
581 #else
582  element_iterator it = m_subBlocks.begin();
583  std::advance(it, std::distance(m_subBlocks.cbegin(), pos));
584  return m_subBlocks.insert(it, element);
585 #endif
586 }
587 
590 {
591  return m_subBlocks.begin();
592 }
593 
596 {
597  return m_subBlocks.end();
598 }
599 
600 size_t
602 {
603  return m_subBlocks.size();
604 }
605 
606 bool
607 Block::operator!=(const Block& other) const
608 {
609  return !this->operator==(other);
610 }
611 
612 bool
613 Block::operator==(const Block& other) const
614 {
615  return this->size() == other.size() &&
616  std::equal(this->begin(), this->end(), other.begin());
617 }
618 
619 } // namespace ndn
shared_ptr< const Buffer > m_buffer
Definition: block.hpp:321
bool empty() const
Check if the Block is empty.
Definition: block.cpp:465
bool operator!=(const Block &other) const
Definition: block.cpp:607
static Block fromStream(std::istream &is)
Create a Block from an input stream.
Definition: block.cpp:223
Copyright (c) 2011-2015 Regents of the University of California.
bool hasValue() const
Check if the Block has value block (no type and length are encoded)
Definition: block.cpp:514
static std::tuple< bool, Block > fromBuffer(ConstBufferPtr buffer, size_t offset)
Try to construct block from Buffer.
Definition: block.cpp:253
Block makeEmptyBlock(uint32_t type)
Create a TLV block type type containing no value (i.e., a boolean block)
Buffer::const_iterator end() const
Definition: block.cpp:486
shared_ptr< Buffer > BufferPtr
Definition: buffer.hpp:35
Buffer::const_iterator m_begin
Definition: block.hpp:325
element_const_iterator find(uint32_t type) const
Definition: block.cpp:420
element_container::iterator element_iterator
Definition: block.hpp:47
STL namespace.
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
bool readType(InputIterator &begin, const InputIterator &end, uint32_t &type)
Read TLV Type.
Definition: tlv.hpp:288
element_iterator insert(element_const_iterator pos, const Block &element)
insert Insert a new element in a specific position
Definition: block.cpp:575
element_iterator erase(element_const_iterator position)
Definition: block.cpp:538
Buffer::const_iterator value_begin() const
Definition: block.hpp:352
Buffer::const_iterator value_end() const
Definition: block.hpp:358
void resetWire()
Reset wire buffer but keep sub elements (if any)
Definition: block.cpp:312
uint32_t m_size
Definition: block.hpp:327
size_t writeVarNumber(std::ostream &os, uint64_t varNumber)
Write VAR-NUMBER to the specified stream.
Definition: tlv.hpp:405
bool readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t &number)
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:243
element_const_iterator elements_end() const
Definition: block.cpp:595
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
size_t size() const
Definition: block.cpp:504
element_const_iterator elements_begin() const
Definition: block.cpp:589
Buffer::const_iterator m_value_end
Definition: block.hpp:330
EncodingImpl< EncoderTag > EncodingBuffer
Block blockFromValue() const
Definition: block.cpp:437
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block type type with value from a buffer value of size length.
const Block & get(uint32_t type) const
Get the first subelement of the requested type.
Definition: block.cpp:409
element_container::const_iterator element_const_iterator
Definition: block.hpp:48
size_t elements_size() const
Definition: block.cpp:601
void remove(uint32_t type)
remove all subelements of type
Definition: block.cpp:427
void reset()
Reset wire buffer of the element.
Definition: block.cpp:302
void push_back(const Block &element)
Definition: block.cpp:568
size_t value_size() const
Definition: block.cpp:529
void parse() const
Parse wire buffer into subblocks.
Definition: block.cpp:322
uint32_t type() const
Definition: block.hpp:346
shared_ptr< const Buffer > getBuffer() const
Get underlying buffer.
Definition: block.hpp:340
void encode()
Encode subblocks into wire buffer.
Definition: block.cpp:355
const uint8_t * wire() const
Definition: block.cpp:495
element_container m_subBlocks
Definition: block.hpp:332
Buffer::const_iterator m_end
Definition: block.hpp:326
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:471
const uint8_t * value() const
Definition: block.cpp:520
Class implementing interface similar to ostringstream, but to construct ndn::Buffer.
uint32_t m_type
Definition: block.hpp:323
bool operator==(const Block &other) const
Definition: block.cpp:613
Buffer::const_iterator m_value_begin
Definition: block.hpp:329
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33
Block()
Create an empty Block.
Definition: block.cpp:48
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
Buffer::const_iterator begin() const
Definition: block.cpp:477
size_t sizeOfVarNumber(uint64_t varNumber)
Get number of bytes necessary to hold value of VAR-NUMBER.
Definition: tlv.hpp:388
const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM
Definition: block.cpp:46