NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: 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; -*- */
2 /*
3  * Copyright (c) 2013-2017 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  *
21  * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
22  */
23 
24 #include "block.hpp"
25 #include "buffer-stream.hpp"
26 #include "encoding-buffer.hpp"
27 #include "tlv.hpp"
28 
29 #include <boost/asio/buffer.hpp>
30 #include <boost/range/adaptor/reversed.hpp>
31 
32 namespace ndn {
33 
34 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
35 #if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
37  "Block must be MoveConstructible with noexcept");
38 #endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
39 
40 #if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
42  "Block must be MoveAssignable with noexcept");
43 #endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
44 
46 
47 // ---- constructor, creation, assignment ----
48 
50  : m_type(std::numeric_limits<uint32_t>::max())
51  , m_size(0)
52 {
53 }
54 
56  : Block(const_cast<EncodingBuffer&>(buffer).getBuffer(), buffer.begin(), buffer.end(), true)
57 {
58 }
59 
61  : Block(buffer, buffer->begin(), buffer->end(), true)
62 {
63 }
64 
65 Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
66  bool verifyLength)
67  : m_buffer(std::move(buffer))
68  , m_begin(begin)
69  , m_end(end)
71  , m_valueEnd(m_end)
72  , m_size(m_end - m_begin)
73 {
74  if (m_buffer->size() == 0) {
75  BOOST_THROW_EXCEPTION(std::invalid_argument("buffer is empty"));
76  }
77 
78  const uint8_t* bufferBegin = &m_buffer->front();
79  const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
80  if (&*begin < bufferBegin || &*begin > bufferEnd ||
81  &*end < bufferBegin || &*end > bufferEnd) {
82  BOOST_THROW_EXCEPTION(std::invalid_argument("begin/end iterators points out of the buffer"));
83  }
84 
86  uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
87  // m_valueBegin now points to TLV-VALUE
88 
89  if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
90  BOOST_THROW_EXCEPTION(Error("TLV-LENGTH doesn't match buffer size"));
91  }
92 }
93 
94 Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
95  bool verifyLength)
96  : Block(block.m_buffer, begin, end, verifyLength)
97 {
98 }
99 
101  Buffer::const_iterator begin, Buffer::const_iterator end,
102  Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
103  : m_buffer(std::move(buffer))
104  , m_begin(begin)
105  , m_end(end)
106  , m_valueBegin(valueBegin)
107  , m_valueEnd(valueEnd)
108  , m_type(type)
109  , m_size(m_end - m_begin)
110 {
111 }
112 
113 Block::Block(const uint8_t* buf, size_t bufSize)
114 {
115  const uint8_t* pos = buf;
116  const uint8_t* const end = buf + bufSize;
117 
118  m_type = tlv::readType(pos, end);
119  uint64_t length = tlv::readVarNumber(pos, end);
120  // pos now points to TLV-VALUE
121 
122  if (length > static_cast<uint64_t>(end - pos)) {
123  BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
124  }
125  size_t typeLengthSize = pos - buf;
126  m_size = typeLengthSize + length;
127 
128  m_buffer = make_shared<Buffer>(buf, m_size);
129  m_begin = m_buffer->begin();
130  m_end = m_valueEnd = m_buffer->end();
131  m_valueBegin = m_begin + typeLengthSize;
132 }
133 
135  : m_type(type)
136  , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
137 {
138 }
139 
141  : m_buffer(std::move(value))
142  , m_begin(m_buffer->end())
143  , m_end(m_buffer->end())
145  , m_valueEnd(m_buffer->end())
146  , m_type(type)
147 {
149 }
150 
151 Block::Block(uint32_t type, const Block& value)
152  : m_buffer(value.m_buffer)
153  , m_begin(m_buffer->end())
154  , m_end(m_buffer->end())
155  , m_valueBegin(value.begin())
156  , m_valueEnd(value.end())
157  , m_type(type)
158 {
160 }
161 
162 Block
163 Block::fromStream(std::istream& is)
164 {
165  std::istream_iterator<uint8_t> begin(is >> std::noskipws);
166  std::istream_iterator<uint8_t> end;
167 
168  uint32_t type = tlv::readType(begin, end);
169  uint64_t length = tlv::readVarNumber(begin, end);
170  if (begin != end) {
171  is.putback(*begin);
172  }
173 
174  size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
175  if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
176  BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
177  }
178 
179  EncodingBuffer eb(tlSize + length, length);
180  uint8_t* valueBuf = eb.buf();
181  is.read(reinterpret_cast<char*>(valueBuf), length);
182  if (length != static_cast<uint64_t>(is.gcount())) {
183  BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
184  }
185 
186  eb.prependVarNumber(length);
187  eb.prependVarNumber(type);
188 
189  // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
190  // has the correct layout.
191  return Block(eb.getBuffer());
192 }
193 
194 std::tuple<bool, Block>
195 Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
196 {
197  const Buffer::const_iterator begin = buffer->begin() + offset;
198  Buffer::const_iterator pos = begin;
199 
200  uint32_t type = 0;
201  bool isOk = tlv::readType(pos, buffer->end(), type);
202  if (!isOk) {
203  return std::make_tuple(false, Block());
204  }
205  uint64_t length = 0;
206  isOk = tlv::readVarNumber(pos, buffer->end(), length);
207  if (!isOk) {
208  return std::make_tuple(false, Block());
209  }
210  // pos now points to TLV-VALUE
211 
212  if (length > static_cast<uint64_t>(buffer->end() - pos)) {
213  return std::make_tuple(false, Block());
214  }
215 
216  return std::make_tuple(true, Block(buffer, type, begin, pos + length, pos, pos + length));
217 }
218 
219 std::tuple<bool, Block>
220 Block::fromBuffer(const uint8_t* buf, size_t bufSize)
221 {
222  const uint8_t* pos = buf;
223  const uint8_t* const end = buf + bufSize;
224 
225  uint32_t type = 0;
226  bool isOk = tlv::readType(pos, end, type);
227  if (!isOk) {
228  return std::make_tuple(false, Block());
229  }
230  uint64_t length = 0;
231  isOk = tlv::readVarNumber(pos, end, length);
232  if (!isOk) {
233  return std::make_tuple(false, Block());
234  }
235  // pos now points to TLV-VALUE
236 
237  if (length > static_cast<uint64_t>(end - pos)) {
238  return std::make_tuple(false, Block());
239  }
240 
241  size_t typeLengthSize = pos - buf;
242  auto b = make_shared<Buffer>(buf, pos + length);
243  return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
244  b->begin() + typeLengthSize, b->end()));
245 }
246 
247 // ---- wire format ----
248 
249 bool
251 {
252  return m_buffer != nullptr && m_begin != m_end;
253 }
254 
255 void
257 {
258  this->resetWire();
259 
260  m_type = std::numeric_limits<uint32_t>::max();
261  m_elements.clear();
262 }
263 
264 void
266 {
267  m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
268  m_begin = m_end = m_valueBegin = m_valueEnd = Buffer::const_iterator();
269 }
270 
271 Buffer::const_iterator
273 {
274  if (!hasWire())
275  BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
276 
277  return m_begin;
278 }
279 
280 Buffer::const_iterator
281 Block::end() const
282 {
283  if (!hasWire())
284  BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
285 
286  return m_end;
287 }
288 
289 const uint8_t*
290 Block::wire() const
291 {
292  if (!hasWire())
293  BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
294 
295  return &*m_begin;
296 }
297 
298 size_t
299 Block::size() const
300 {
301  if (empty()) {
302  BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
303  }
304 
305  return m_size;
306 }
307 
308 // ---- value ----
309 
310 const uint8_t*
312 {
313  return hasValue() ? &*m_valueBegin : nullptr;
314 }
315 
316 size_t
318 {
319  return hasValue() ? m_valueEnd - m_valueBegin : 0;
320 }
321 
322 Block
324 {
325  if (!hasValue())
326  BOOST_THROW_EXCEPTION(Error("Block has no TLV-VALUE"));
327 
328  return Block(*this, m_valueBegin, m_valueEnd, true);
329 }
330 
331 // ---- sub elements ----
332 
333 void
335 {
336  if (!m_elements.empty() || value_size() == 0)
337  return;
338 
339  Buffer::const_iterator begin = value_begin();
340  Buffer::const_iterator end = value_end();
341 
342  while (begin != end) {
343  Buffer::const_iterator pos = begin;
344 
345  uint32_t type = tlv::readType(pos, end);
346  uint64_t length = tlv::readVarNumber(pos, end);
347  if (length > static_cast<uint64_t>(end - pos)) {
348  m_elements.clear();
349  BOOST_THROW_EXCEPTION(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
350  " exceeds TLV-VALUE boundary of parent block"));
351  }
352  // pos now points to TLV-VALUE of sub element
353 
354  Buffer::const_iterator subEnd = pos + length;
355  m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
356 
357  begin = subEnd;
358  }
359 }
360 
361 void
363 {
364  if (hasWire())
365  return;
366 
367  EncodingEstimator estimator;
368  size_t estimatedSize = encode(estimator);
369 
370  EncodingBuffer buffer(estimatedSize, 0);
371  encode(buffer);
372 }
373 
374 size_t
375 Block::encode(EncodingEstimator& estimator) const
376 {
377  if (hasValue()) {
378  return m_size;
379  }
380 
381  size_t len = 0;
382  for (const Block& element : m_elements | boost::adaptors::reversed) {
383  len += element.encode(estimator);
384  }
385  len += estimator.prependVarNumber(len);
386  len += estimator.prependVarNumber(m_type);
387  return len;
388 }
389 
390 size_t
392 {
393  size_t len = 0;
394  m_end = encoder.begin();
395  if (hasValue()) {
396  len += encoder.prependRange(m_valueBegin, m_valueEnd);
397  }
398  else {
399  for (Block& element : m_elements | boost::adaptors::reversed) {
400  len += element.encode(encoder);
401  }
402  }
403  m_valueEnd = m_end;
404  m_valueBegin = encoder.begin();
405 
406  len += encoder.prependVarNumber(len);
407  len += encoder.prependVarNumber(m_type);
408  m_begin = encoder.begin();
409 
410  m_buffer = encoder.getBuffer();
411  m_size = len;
412  return len;
413 }
414 
415 const Block&
416 Block::get(uint32_t type) const
417 {
418  auto it = this->find(type);
419  if (it != m_elements.end()) {
420  return *it;
421  }
422 
423  BOOST_THROW_EXCEPTION(Error("No sub-element of type " + to_string(type) +
424  " is found in block of type " + to_string(m_type)));
425 }
426 
428 Block::find(uint32_t type) const
429 {
430  return std::find_if(m_elements.begin(), m_elements.end(),
431  [type] (const Block& subBlock) { return subBlock.type() == type; });
432 }
433 
434 void
436 {
437  resetWire();
438 
439  auto it = std::remove_if(m_elements.begin(), m_elements.end(),
440  [type] (const Block& subBlock) { return subBlock.type() == type; });
441  m_elements.resize(it - m_elements.begin());
442 }
443 
446 {
447  resetWire();
448 
449 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
450  return m_elements.erase(position);
451 #else
452  element_iterator it = m_elements.begin();
453  std::advance(it, std::distance(m_elements.cbegin(), position));
454  return m_elements.erase(it);
455 #endif
456 }
457 
460 {
461  resetWire();
462 
463 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
464  return m_elements.erase(first, last);
465 #else
466  element_iterator itStart = m_elements.begin();
467  element_iterator itEnd = m_elements.begin();
468  std::advance(itStart, std::distance(m_elements.cbegin(), first));
469  std::advance(itEnd, std::distance(m_elements.cbegin(), last));
470  return m_elements.erase(itStart, itEnd);
471 #endif
472 }
473 
474 void
475 Block::push_back(const Block& element)
476 {
477  resetWire();
478  m_elements.push_back(element);
479 }
480 
483 {
484  resetWire();
485 
486 #ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
487  return m_elements.insert(pos, element);
488 #else
489  element_iterator it = m_elements.begin();
490  std::advance(it, std::distance(m_elements.cbegin(), pos));
491  return m_elements.insert(it, element);
492 #endif
493 }
494 
495 // ---- misc ----
496 
497 Block::operator boost::asio::const_buffer() const
498 {
499  return boost::asio::const_buffer(wire(), size());
500 }
501 
502 bool
503 operator==(const Block& lhs, const Block& rhs)
504 {
505  return lhs.type() == rhs.type() &&
506  lhs.value_size() == rhs.value_size() &&
507  ::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0;
508 }
509 
510 } // namespace ndn
shared_ptr< const Buffer > m_buffer
underlying buffer storing TLV-VALUE and possibly TLV-TYPE and TLV-LENGTH fields
Definition: block.hpp:403
bool empty() const
Check if the Block is empty.
Definition: block.hpp:173
static Block fromStream(std::istream &is)
Parse Block from an input stream.
Definition: block.cpp:163
Copyright (c) 2011-2015 Regents of the University of California.
bool hasValue() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:246
bool readType(Iterator &begin, const Iterator &end, uint32_t &type)
Read TLV-TYPE.
Definition: tlv.hpp:375
static std::tuple< bool, Block > fromBuffer(ConstBufferPtr buffer, size_t offset)
Try to parse Block from a wire buffer.
Definition: block.cpp:195
Buffer::const_iterator m_valueBegin
Definition: block.hpp:407
Buffer::const_iterator end() const
Get end iterator of encoded wire.
Definition: block.cpp:281
Buffer::const_iterator m_begin
Definition: block.hpp:404
element_const_iterator find(uint32_t type) const
Find the first sub element of specified TLV-TYPE.
Definition: block.cpp:428
element_container::const_iterator element_const_iterator
Definition: block.hpp:47
STL namespace.
element_container m_elements
sub elements
Definition: block.hpp:422
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
element_iterator insert(element_const_iterator pos, const Block &element)
Insert a sub element.
Definition: block.cpp:482
element_iterator erase(element_const_iterator position)
Erase a sub element.
Definition: block.cpp:445
Buffer::const_iterator value_begin() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:255
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:264
void resetWire()
Reset wire buffer but keep TLV-TYPE and sub elements (if any)
Definition: block.cpp:265
uint32_t m_size
total size including Type-Length-Value
Definition: block.hpp:416
bool readVarNumber(Iterator &begin, const Iterator &end, uint64_t &number)
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:356
Buffer::const_iterator m_valueEnd
Definition: block.hpp:408
size_t size() const
Get size of encoded wire, including Type-Length-Value.
Definition: block.cpp:299
Block blockFromValue() const
Definition: block.cpp:323
const Block & get(uint32_t type) const
Get the first sub element of specified TLV-TYPE.
Definition: block.cpp:416
element_container::iterator element_iterator
Definition: block.hpp:46
void remove(uint32_t type)
Remove all sub elements of specified TLV-TYPE.
Definition: block.cpp:435
void reset()
Reset wire buffer of the element.
Definition: block.cpp:256
void push_back(const Block &element)
Append a sub element.
Definition: block.cpp:475
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:317
void parse() const
Parse TLV-VALUE into sub elements.
Definition: block.cpp:334
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
void encode()
Encode sub elements into TLV-VALUE.
Definition: block.cpp:362
const uint8_t * wire() const
Get pointer to encoded wire.
Definition: block.cpp:290
Buffer::const_iterator m_end
Definition: block.hpp:405
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:250
const uint8_t * value() const
Get pointer to TLV-VALUE.
Definition: block.cpp:311
bool operator==(const Data &lhs, const Data &rhs)
Definition: data.cpp:265
shared_ptr< const Buffer > getBuffer() const
Get underlying buffer.
Definition: block.hpp:226
std::string to_string(const V &v)
Definition: backports.hpp:84
uint32_t m_type
TLV-TYPE.
Definition: block.hpp:410
constexpr size_t sizeOfVarNumber(uint64_t number)
Get number of bytes necessary to hold value of VAR-NUMBER.
Definition: tlv.hpp:416
Block()
Create an empty Block.
Definition: block.cpp:49
EncodingImpl< EncoderTag > EncodingBuffer
Buffer::const_iterator begin() const
Get begin iterator of encoded wire.
Definition: block.cpp:272
EncodingImpl< EstimatorTag > EncodingEstimator
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:39
const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM
Definition: block.cpp:45
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:89