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-2019 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 
27 #include "ndn-cxx/encoding/tlv.hpp"
31 
32 #include <boost/asio/buffer.hpp>
33 #include <boost/range/adaptor/reversed.hpp>
34 #include <cstring>
35 
36 namespace ndn {
37 
38 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
39 
41 
42 // ---- constructor, creation, assignment ----
43 
44 Block::Block() = default;
45 
46 Block::Block(const Block&) = default;
47 
48 Block&
49 Block::operator=(const Block&) = default;
50 
52  : Block(buffer.getBuffer(), buffer.begin(), buffer.end(), true)
53 {
54 }
55 
57  : Block(buffer, buffer->begin(), buffer->end(), true)
58 {
59 }
60 
61 Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
62  bool verifyLength)
63  : m_buffer(std::move(buffer))
64  , m_begin(begin)
65  , m_end(end)
66  , m_valueBegin(m_begin)
67  , m_valueEnd(m_end)
68  , m_size(m_end - m_begin)
69 {
70  if (m_buffer->size() == 0) {
71  NDN_THROW(std::invalid_argument("Buffer is empty"));
72  }
73 
74  const uint8_t* bufferBegin = &m_buffer->front();
75  const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
76  if (&*begin < bufferBegin || &*begin > bufferEnd ||
77  &*end < bufferBegin || &*end > bufferEnd) {
78  NDN_THROW(std::invalid_argument("Begin/end iterators point outside the buffer"));
79  }
80 
82  uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
83  // m_valueBegin now points to TLV-VALUE
84 
85  if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
86  NDN_THROW(Error("TLV-LENGTH does not match buffer size"));
87  }
88 }
89 
90 Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
91  bool verifyLength)
92  : Block(block.m_buffer, begin, end, verifyLength)
93 {
94 }
95 
96 Block::Block(ConstBufferPtr buffer, uint32_t type,
97  Buffer::const_iterator begin, Buffer::const_iterator end,
98  Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
99  : m_buffer(std::move(buffer))
100  , m_begin(begin)
101  , m_end(end)
102  , m_valueBegin(valueBegin)
103  , m_valueEnd(valueEnd)
104  , m_type(type)
105  , m_size(m_end - m_begin)
106 {
107 }
108 
109 Block::Block(const uint8_t* buf, size_t bufSize)
110 {
111  const uint8_t* pos = buf;
112  const uint8_t* const end = buf + bufSize;
113 
114  m_type = tlv::readType(pos, end);
115  uint64_t length = tlv::readVarNumber(pos, end);
116  // pos now points to TLV-VALUE
117 
118  BOOST_ASSERT(pos <= end);
119  if (length > static_cast<uint64_t>(end - pos)) {
120  NDN_THROW(Error("Not enough bytes in the buffer to fully parse TLV"));
121  }
122 
123  BOOST_ASSERT(pos > buf);
124  uint64_t typeLengthSize = static_cast<uint64_t>(pos - buf);
125  m_size = typeLengthSize + length;
126 
127  m_buffer = make_shared<Buffer>(buf, m_size);
128  m_begin = m_buffer->begin();
129  m_end = m_valueEnd = m_buffer->end();
130  m_valueBegin = m_begin + typeLengthSize;
131 }
132 
133 Block::Block(uint32_t type)
134  : m_type(type)
135  , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
136 {
137 }
138 
139 Block::Block(uint32_t type, ConstBufferPtr value)
140  : m_buffer(std::move(value))
141  , m_begin(m_buffer->end())
142  , m_end(m_buffer->end())
143  , m_valueBegin(m_buffer->begin())
144  , m_valueEnd(m_buffer->end())
145  , m_type(type)
146 {
148 }
149 
150 Block::Block(uint32_t type, const Block& value)
151  : m_buffer(value.m_buffer)
152  , m_begin(m_buffer->end())
153  , m_end(m_buffer->end())
154  , m_valueBegin(value.begin())
155  , m_valueEnd(value.end())
156  , m_type(type)
157 {
159 }
160 
161 Block
162 Block::fromStream(std::istream& is)
163 {
164  std::istream_iterator<uint8_t> begin(is >> std::noskipws);
165  std::istream_iterator<uint8_t> end;
166 
167  uint32_t type = tlv::readType(begin, end);
168  uint64_t length = tlv::readVarNumber(begin, end);
169  if (begin != end) {
170  is.putback(*begin);
171  }
172 
173  size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
174  if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
175  NDN_THROW(Error("TLV-LENGTH from stream exceeds limit"));
176  }
177 
178  EncodingBuffer eb(tlSize + length, length);
179  uint8_t* valueBuf = eb.buf();
180  is.read(reinterpret_cast<char*>(valueBuf), length);
181  if (length != static_cast<uint64_t>(is.gcount())) {
182  NDN_THROW(Error("Not enough bytes from stream to fully parse TLV"));
183  }
184 
185  eb.prependVarNumber(length);
186  eb.prependVarNumber(type);
187 
188  // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
189  // has the correct layout.
190  return Block(eb.getBuffer());
191 }
192 
193 std::tuple<bool, Block>
194 Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
195 {
196  auto begin = buffer->begin() + offset;
197  auto pos = begin;
198 
199  uint32_t type = 0;
200  bool isOk = tlv::readType(pos, buffer->end(), type);
201  if (!isOk) {
202  return std::make_tuple(false, Block());
203  }
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(std::move(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 void
250 Block::reset() noexcept
251 {
252  *this = {};
253 }
254 
255 void
257 {
258  m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
260 }
261 
262 Buffer::const_iterator
264 {
265  if (!hasWire())
266  NDN_THROW(Error("Underlying wire buffer is empty"));
267 
268  return m_begin;
269 }
270 
271 Buffer::const_iterator
272 Block::end() const
273 {
274  if (!hasWire())
275  NDN_THROW(Error("Underlying wire buffer is empty"));
276 
277  return m_end;
278 }
279 
280 const uint8_t*
281 Block::wire() const
282 {
283  if (!hasWire())
284  NDN_THROW(Error("Underlying wire buffer is empty"));
285 
286  return &*m_begin;
287 }
288 
289 size_t
290 Block::size() const
291 {
292  if (!isValid()) {
293  NDN_THROW(Error("Cannot determine size of invalid block"));
294  }
295 
296  return m_size;
297 }
298 
299 // ---- value ----
300 
301 const uint8_t*
302 Block::value() const noexcept
303 {
304  return hasValue() ? &*m_valueBegin : nullptr;
305 }
306 
307 size_t
308 Block::value_size() const noexcept
309 {
310  return hasValue() ? static_cast<size_t>(m_valueEnd - m_valueBegin) : 0;
311 }
312 
313 Block
315 {
316  if (!hasValue())
317  NDN_THROW(Error("Block has no TLV-VALUE"));
318 
319  return Block(*this, m_valueBegin, m_valueEnd, true);
320 }
321 
322 // ---- sub elements ----
323 
324 void
326 {
327  if (!m_elements.empty() || value_size() == 0)
328  return;
329 
330  Buffer::const_iterator begin = value_begin();
331  Buffer::const_iterator end = value_end();
332 
333  while (begin != end) {
334  Buffer::const_iterator pos = begin;
335 
336  uint32_t type = tlv::readType(pos, end);
337  uint64_t length = tlv::readVarNumber(pos, end);
338  if (length > static_cast<uint64_t>(end - pos)) {
339  m_elements.clear();
340  NDN_THROW(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
341  " exceeds TLV-VALUE boundary of parent block"));
342  }
343  // pos now points to TLV-VALUE of sub element
344 
345  Buffer::const_iterator subEnd = pos + length;
346  m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
347 
348  begin = subEnd;
349  }
350 }
351 
352 void
354 {
355  if (hasWire())
356  return;
357 
358  EncodingEstimator estimator;
359  size_t estimatedSize = encode(estimator);
360 
361  EncodingBuffer buffer(estimatedSize, 0);
362  encode(buffer);
363 }
364 
365 size_t
366 Block::encode(EncodingEstimator& estimator) const
367 {
368  if (hasValue()) {
369  return m_size;
370  }
371 
372  size_t len = encodeValue(estimator);
373  len += estimator.prependVarNumber(len);
374  len += estimator.prependVarNumber(m_type);
375  return len;
376 }
377 
378 size_t
379 Block::encodeValue(EncodingEstimator& estimator) const
380 {
381  size_t len = 0;
382  for (const Block& element : m_elements | boost::adaptors::reversed) {
383  len += element.encode(estimator);
384  }
385  return len;
386 }
387 
388 size_t
390 {
391  size_t len = 0;
392  m_end = encoder.begin();
393  if (hasValue()) {
394  len += encoder.prependRange(m_valueBegin, m_valueEnd);
395  }
396  else {
397  for (Block& element : m_elements | boost::adaptors::reversed) {
398  len += element.encode(encoder);
399  }
400  }
401  m_valueEnd = m_end;
402  m_valueBegin = encoder.begin();
403 
404  len += encoder.prependVarNumber(len);
405  len += encoder.prependVarNumber(m_type);
406  m_begin = encoder.begin();
407 
408  m_buffer = encoder.getBuffer();
409  m_size = len;
410  return len;
411 }
412 
413 const Block&
414 Block::get(uint32_t type) const
415 {
416  auto it = this->find(type);
417  if (it != m_elements.end()) {
418  return *it;
419  }
420 
421  NDN_THROW(Error("No sub-element of type " + to_string(type) +
422  " found in block of type " + to_string(m_type)));
423 }
424 
426 Block::find(uint32_t type) const
427 {
428  return std::find_if(m_elements.begin(), m_elements.end(),
429  [type] (const Block& subBlock) { return subBlock.type() == type; });
430 }
431 
432 void
433 Block::remove(uint32_t type)
434 {
435  resetWire();
436 
437  auto it = std::remove_if(m_elements.begin(), m_elements.end(),
438  [type] (const Block& subBlock) { return subBlock.type() == type; });
439  m_elements.erase(it, m_elements.end());
440 }
441 
444 {
445  resetWire();
446  return m_elements.erase(position);
447 }
448 
451 {
452  resetWire();
453  return m_elements.erase(first, last);
454 }
455 
456 void
457 Block::push_back(const Block& element)
458 {
459  resetWire();
460  m_elements.push_back(element);
461 }
462 
465 {
466  resetWire();
467  return m_elements.insert(pos, element);
468 }
469 
470 // ---- misc ----
471 
472 Block::operator boost::asio::const_buffer() const
473 {
474  return boost::asio::const_buffer(wire(), size());
475 }
476 
477 bool
478 operator==(const Block& lhs, const Block& rhs)
479 {
480  return lhs.type() == rhs.type() &&
481  lhs.value_size() == rhs.value_size() &&
482  (lhs.value_size() == 0 ||
483  std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
484 }
485 
486 std::ostream&
487 operator<<(std::ostream& os, const Block& block)
488 {
489  auto oldFmt = os.flags(std::ios_base::dec);
490 
491  if (!block.isValid()) {
492  os << "[invalid]";
493  }
494  else if (!block.m_elements.empty()) {
495  EncodingEstimator estimator;
496  size_t tlvLength = block.encodeValue(estimator);
497  os << block.type() << '[' << tlvLength << "]={";
498  std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ','));
499  os << '}';
500  }
501  else if (block.value_size() > 0) {
502  os << block.type() << '[' << block.value_size() << "]=";
503  printHex(os, block.value(), block.value_size(), true);
504  }
505  else {
506  os << block.type() << "[empty]";
507  }
508 
509  os.flags(oldFmt);
510  return os;
511 }
512 
513 Block
514 operator "" _block(const char* input, std::size_t len)
515 {
516  namespace t = security::transform;
517  t::StepSource ss;
518  OBufferStream os;
519  ss >> t::hexDecode() >> t::streamSink(os);
520 
521  for (const char* end = input + len; input != end; ++input) {
522  if (std::strchr("0123456789ABCDEF", *input) != nullptr) {
523  ss.write(reinterpret_cast<const uint8_t*>(input), 1);
524  }
525  }
526 
527  try {
528  ss.end();
529  }
530  catch (const t::Error&) {
531  NDN_THROW(std::invalid_argument("Input has odd number of hexadecimal digits"));
532  }
533 
534  return Block(os.buf());
535 }
536 
537 } // namespace ndn
buf
const uint8_t * buf
Definition: verification-helpers.cpp:47
ndn::Block::m_size
size_t m_size
Total size including Type-Length-Value.
Definition: block.hpp:465
ndn::MAX_SIZE_OF_BLOCK_FROM_STREAM
const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM
Definition: block.cpp:40
string-helper.hpp
tlv.hpp
ndn::Block::blockFromValue
Block blockFromValue() const
Definition: block.cpp:314
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
ndn::Block::value_size
size_t value_size() const noexcept
Return the size of TLV-VALUE, aka TLV-LENGTH.
Definition: block.cpp:308
ndn::Block::insert
element_iterator insert(element_const_iterator pos, const Block &element)
Insert a sub-element.
Definition: block.cpp:464
ndn::Block::Block
Block()
Create an invalid Block.
ndn::Block::hasValue
bool hasValue() const noexcept
Check if the Block has a non-empty TLV-VALUE.
Definition: block.hpp:287
ndn::Block::begin
Buffer::const_iterator begin() const
Get begin iterator of encoded wire.
Definition: block.cpp:263
ndn::Block::elements_begin
element_const_iterator elements_begin() const
Equivalent to elements().begin()
Definition: block.hpp:399
ndn::Block::m_valueBegin
Buffer::const_iterator m_valueBegin
Definition: block.hpp:456
block.hpp
ndn::Block::find
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:426
ndn::Block::m_type
uint32_t m_type
TLV-TYPE.
Definition: block.hpp:459
ndn::Block::value_end
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:305
ndn::make_ostream_joiner
ostream_joiner< std::decay_t< DelimT >, CharT, Traits > make_ostream_joiner(std::basic_ostream< CharT, Traits > &os, DelimT &&delimiter)
Definition: ostream-joiner.hpp:117
ndn::Block::reset
void reset() noexcept
Reset the Block to a default-constructed state.
Definition: block.cpp:250
ndn::Block::isValid
bool isValid() const noexcept
Check if the Block is valid.
Definition: block.hpp:188
ndn::Block::operator=
Block & operator=(const Block &)
Copy assignment operator.
ndn::Block::element_const_iterator
element_container::const_iterator element_const_iterator
Definition: block.hpp:47
ndn::Block::push_back
void push_back(const Block &element)
Append a sub-element.
Definition: block.cpp:457
ndn::Block::m_elements
element_container m_elements
Contains the sub-elements.
Definition: block.hpp:471
ndn::encoding::EncodingEstimator
EncodingImpl< EstimatorTag > EncodingEstimator
Definition: encoding-buffer-fwd.hpp:39
ndn::Block::get
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:414
ndn::Block::remove
void remove(uint32_t type)
Remove all sub-elements of the specified TLV-TYPE.
Definition: block.cpp:433
ndn::Block::fromBuffer
static NDN_CXX_NODISCARD std::tuple< bool, Block > fromBuffer(ConstBufferPtr buffer, size_t offset)
Try to parse Block from a wire buffer.
Definition: block.cpp:194
ndn::Block::type
uint32_t type() const
Return the TLV-TYPE of the Block.
Definition: block.hpp:274
ostream-joiner.hpp
Backport of ostream_joiner from the Library Fundamentals v2 TS.
ndn::Block::erase
element_iterator erase(element_const_iterator position)
Erase a sub-element.
Definition: block.cpp:443
ndn::Block::value_begin
Buffer::const_iterator value_begin() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:296
ndn::Block::m_end
Buffer::const_iterator m_end
Definition: block.hpp:454
ndn::Block::element_iterator
element_container::iterator element_iterator
Definition: block.hpp:46
ndn::printHex
void printHex(std::ostream &os, uint64_t num, bool wantUpperCase)
Output the hex representation of num to the output stream os.
Definition: string-helper.cpp:42
ndn::tlv::readType
NDN_CXX_NODISCARD bool readType(Iterator &begin, Iterator end, uint32_t &type) noexcept
Read TLV-TYPE.
Definition: tlv.hpp:408
NDN_THROW
#define NDN_THROW(e)
Definition: exception.hpp:61
ndn::tlv::sizeOfVarNumber
constexpr size_t sizeOfVarNumber(uint64_t number) noexcept
Get the number of bytes necessary to hold the value of number encoded as VAR-NUMBER.
Definition: tlv.hpp:450
ndn::tlv::readVarNumber
NDN_CXX_NODISCARD bool readVarNumber(Iterator &begin, Iterator end, uint64_t &number) noexcept
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:389
ndn::Block::resetWire
void resetWire() noexcept
Reset wire buffer but keep TLV-TYPE and sub-elements (if any)
Definition: block.cpp:256
ndn::security::transform::hexDecode
unique_ptr< Transform > hexDecode()
Definition: hex-decode.cpp:114
ndn::Block::parse
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:325
ndn::OBufferStream
implements an output stream that constructs ndn::Buffer
Definition: buffer-stream.hpp:71
transform.hpp
ndn::Block::m_begin
Buffer::const_iterator m_begin
Definition: block.hpp:453
ndn::Block::end
Buffer::const_iterator end() const
Get end iterator of encoded wire.
Definition: block.cpp:272
ndn::Block::fromStream
static Block fromStream(std::istream &is)
Parse Block from an input stream.
Definition: block.cpp:162
ndn::MAX_NDN_PACKET_SIZE
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:41
ndn::Block::Error
Definition: block.hpp:50
ndn::Block::value
const uint8_t * value() const noexcept
Return a raw pointer to the beginning of TLV-VALUE.
Definition: block.cpp:302
ndn::Block
Represents a TLV element of NDN packet format.
Definition: block.hpp:43
ndn::security::transform::streamSink
unique_ptr< Sink > streamSink(std::ostream &os)
Definition: stream-sink.cpp:53
ndn::Block::size
size_t size() const
Return the size of the encoded wire, i.e.
Definition: block.cpp:290
ndn::to_string
std::string to_string(const T &val)
Definition: backports.hpp:102
ndn::Block::elements_end
element_const_iterator elements_end() const
Equivalent to elements().end()
Definition: block.hpp:407
ndn::Block::m_valueEnd
Buffer::const_iterator m_valueEnd
Definition: block.hpp:457
ndn::operator==
bool operator==(const Data &lhs, const Data &rhs)
Definition: data.cpp:312
ndn::operator<<
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:322
ndn::Block::hasWire
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:230
buffer-stream.hpp
ndn::OBufferStream::buf
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
Definition: buffer-stream.cpp:54
ndn::Block::wire
const uint8_t * wire() const
Return a raw pointer to the beginning of the encoded wire.
Definition: block.cpp:281
ndn::Block::encode
void encode()
Encode sub-elements into TLV-VALUE.
Definition: block.cpp:353
encoding-buffer.hpp
ndn::ConstBufferPtr
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:126
ndn
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-strategy-choice-helper.hpp:34
ndn::encoding::EncodingBuffer
EncodingImpl< EncoderTag > EncodingBuffer
Definition: encoding-buffer-fwd.hpp:38
ndn::Block::m_buffer
shared_ptr< const Buffer > m_buffer
Underlying buffer storing TLV-VALUE and possibly TLV-TYPE and TLV-LENGTH fields.
Definition: block.hpp:452