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