tlv.hpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2020 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 
22 #ifndef NDN_ENCODING_TLV_HPP
23 #define NDN_ENCODING_TLV_HPP
24 
26 
27 #include <cstring>
28 #include <iterator>
29 #include <ostream>
30 #include <vector>
31 
32 #include <boost/endian/conversion.hpp>
33 
34 namespace ndn {
35 
40 const size_t MAX_NDN_PACKET_SIZE = 8800;
41 
45 namespace tlv {
46 
51 class Error : public std::runtime_error
52 {
53 public:
54  using std::runtime_error::runtime_error;
55 
56  Error(const char* expectedType, uint32_t actualType);
57 };
58 
62 enum : uint32_t {
63  Invalid = 0,
64  Interest = 5,
65  Data = 6,
66  Name = 7,
73  Nonce = 10,
75  HopLimit = 34,
79  MetaInfo = 20,
80  Content = 21,
87  KeyLocator = 28,
88  KeyDigest = 29,
94 
97 
100 };
101 
105 enum : uint32_t {
110  Exclude = 16,
112  Any = 19,
113 };
114 
118 enum : uint32_t {
125 };
126 
131 enum SignatureTypeValue : uint16_t {
137 };
138 
139 std::ostream&
140 operator<<(std::ostream& os, SignatureTypeValue st);
141 
145 enum {
147  NotBefore = 254,
148  NotAfter = 255,
149 
154 };
155 
159 enum ContentTypeValue : uint32_t {
167 };
168 
169 std::ostream&
170 operator<<(std::ostream& os, ContentTypeValue ct);
171 
176 constexpr bool
177 isCriticalType(uint32_t type)
178 {
179  return type <= 31 || (type & 0x01);
180 }
181 
193 template<typename Iterator>
195 readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
196 
210 template<typename Iterator>
212 readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
213 
224 template<typename Iterator>
225 uint64_t
226 readVarNumber(Iterator& begin, Iterator end);
227 
240 template<typename Iterator>
241 uint32_t
242 readType(Iterator& begin, Iterator end);
243 
247 constexpr size_t
248 sizeOfVarNumber(uint64_t number) noexcept;
249 
254 size_t
255 writeVarNumber(std::ostream& os, uint64_t number);
256 
270 template<typename Iterator>
271 uint64_t
272 readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
273 
277 constexpr size_t
278 sizeOfNonNegativeInteger(uint64_t integer) noexcept;
279 
284 size_t
285 writeNonNegativeInteger(std::ostream& os, uint64_t integer);
286 
290 
291 // Inline definitions
292 
296 
297 namespace detail {
298 
301 template<typename Iterator>
303 {
304 public:
305  constexpr bool
306  operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
307  {
308  number = 0;
309  size_t count = 0;
310  for (; begin != end && count < size; ++begin, ++count) {
311  number = (number << 8) | *begin;
312  }
313  return count == size;
314  }
315 };
316 
319 template<typename Iterator>
321 {
322 public:
323  constexpr bool
324  operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
325  {
326  if (begin + size > end) {
327  return false;
328  }
329 
330  switch (size) {
331  case 1: {
332  number = *begin;
333  ++begin;
334  return true;
335  }
336  case 2: {
337  uint16_t value = 0;
338  std::memcpy(&value, &*begin, 2);
339  begin += 2;
340  number = boost::endian::big_to_native(value);
341  return true;
342  }
343  case 4: {
344  uint32_t value = 0;
345  std::memcpy(&value, &*begin, 4);
346  begin += 4;
347  number = boost::endian::big_to_native(value);
348  return true;
349  }
350  case 8: {
351  uint64_t value = 0;
352  std::memcpy(&value, &*begin, 8);
353  begin += 8;
354  number = boost::endian::big_to_native(value);
355  return true;
356  }
357  default: {
359  }
360  }
361  }
362 };
363 
369 template<typename Iterator,
370  typename DecayedIterator = std::decay_t<Iterator>,
371  typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
372 constexpr bool
374 {
375  return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
376  std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
377  std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
378  sizeof(ValueType) == 1 &&
379  !std::is_same<ValueType, bool>::value;
380 }
381 
382 template<typename Iterator>
383 class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
384  ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
385 {
386 };
387 
388 } // namespace detail
389 
390 template<typename Iterator>
391 bool
392 readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
393 {
394  if (begin == end)
395  return false;
396 
397  uint8_t firstOctet = *begin;
398  ++begin;
399  if (firstOctet < 253) {
400  number = firstOctet;
401  return true;
402  }
403 
404  size_t size = firstOctet == 253 ? 2 :
405  firstOctet == 254 ? 4 : 8;
406  return detail::ReadNumber<Iterator>()(size, begin, end, number);
407 }
408 
409 template<typename Iterator>
410 bool
411 readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
412 {
413  uint64_t number = 0;
414  bool isOk = readVarNumber(begin, end, number);
415  if (!isOk || number == Invalid || number > std::numeric_limits<uint32_t>::max()) {
416  return false;
417  }
418 
419  type = static_cast<uint32_t>(number);
420  return true;
421 }
422 
423 template<typename Iterator>
424 uint64_t
425 readVarNumber(Iterator& begin, Iterator end)
426 {
427  if (begin == end) {
428  NDN_THROW(Error("Empty buffer during TLV parsing"));
429  }
430 
431  uint64_t value = 0;
432  bool isOk = readVarNumber(begin, end, value);
433  if (!isOk) {
434  NDN_THROW(Error("Insufficient data during TLV parsing"));
435  }
436 
437  return value;
438 }
439 
440 template<typename Iterator>
441 uint32_t
442 readType(Iterator& begin, Iterator end)
443 {
444  uint64_t type = readVarNumber(begin, end);
445  if (type == Invalid || type > std::numeric_limits<uint32_t>::max()) {
446  NDN_THROW(Error("Illegal TLV-TYPE " + to_string(type)));
447  }
448 
449  return static_cast<uint32_t>(type);
450 }
451 
452 constexpr size_t
453 sizeOfVarNumber(uint64_t number) noexcept
454 {
455  return number < 253 ? 1 :
456  number <= std::numeric_limits<uint16_t>::max() ? 3 :
457  number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
458 }
459 
460 inline size_t
461 writeVarNumber(std::ostream& os, uint64_t number)
462 {
463  if (number < 253) {
464  os.put(static_cast<char>(number));
465  return 1;
466  }
467  else if (number <= std::numeric_limits<uint16_t>::max()) {
468  os.put(static_cast<char>(253));
469  uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
470  os.write(reinterpret_cast<const char*>(&value), 2);
471  return 3;
472  }
473  else if (number <= std::numeric_limits<uint32_t>::max()) {
474  os.put(static_cast<char>(254));
475  uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
476  os.write(reinterpret_cast<const char*>(&value), 4);
477  return 5;
478  }
479  else {
480  os.put(static_cast<char>(255));
481  uint64_t value = boost::endian::native_to_big(number);
482  os.write(reinterpret_cast<const char*>(&value), 8);
483  return 9;
484  }
485 }
486 
487 template<typename Iterator>
488 uint64_t
489 readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
490 {
491  if (size != 1 && size != 2 && size != 4 && size != 8) {
492  NDN_THROW(Error("Invalid length " + to_string(size) + " for nonNegativeInteger"));
493  }
494 
495  uint64_t number = 0;
496  bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
497  if (!isOk) {
498  NDN_THROW(Error("Insufficient data during nonNegativeInteger parsing"));
499  }
500 
501  return number;
502 }
503 
504 constexpr size_t
505 sizeOfNonNegativeInteger(uint64_t integer) noexcept
506 {
507  return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
508  integer <= std::numeric_limits<uint16_t>::max() ? 2 :
509  integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
510 }
511 
512 inline size_t
513 writeNonNegativeInteger(std::ostream& os, uint64_t integer)
514 {
515  if (integer <= std::numeric_limits<uint8_t>::max()) {
516  os.put(static_cast<char>(integer));
517  return 1;
518  }
519  else if (integer <= std::numeric_limits<uint16_t>::max()) {
520  uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
521  os.write(reinterpret_cast<const char*>(&value), 2);
522  return 2;
523  }
524  else if (integer <= std::numeric_limits<uint32_t>::max()) {
525  uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
526  os.write(reinterpret_cast<const char*>(&value), 4);
527  return 4;
528  }
529  else {
530  uint64_t value = boost::endian::native_to_big(integer);
531  os.write(reinterpret_cast<const char*>(&value), 8);
532  return 8;
533  }
534 }
535 
536 } // namespace tlv
537 } // namespace ndn
538 
539 #endif // NDN_ENCODING_TLV_HPP
Represents a signature of Sha256WithRsa type.
Definition: data.cpp:26
constexpr size_t sizeOfNonNegativeInteger(uint64_t integer) noexcept
Get the number of bytes necessary to hold the value of integer encoded as nonNegativeInteger.
Definition: tlv.hpp:505
Represents a SignatureInfo or InterestSignatureInfo TLV element.
std::ostream & operator<<(std::ostream &os, SignatureTypeValue st)
Definition: tlv.cpp:33
std::string to_string(const T &val)
Definition: backports.hpp:101
constexpr bool operator()(size_t size, Iterator &begin, Iterator end, uint64_t &number) const noexcept
Definition: tlv.hpp:324
constexpr bool operator()(size_t size, Iterator &begin, Iterator end, uint64_t &number) const noexcept
Definition: tlv.hpp:306
constexpr bool isCriticalType(uint32_t type)
Determine whether a TLV-TYPE is "critical" for evolvability purpose.
Definition: tlv.hpp:177
public key, certificate
Definition: tlv.hpp:162
Represents a signature of DigestSha256 type.
prefix announcement
Definition: tlv.hpp:165
Represents an Interest packet.
Definition: interest.hpp:50
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:489
File-Like ICN Collection.
Definition: tlv.hpp:166
another name that identifies the actual data content
Definition: tlv.hpp:161
#define NDN_THROW(e)
Definition: exception.hpp:61
size_t writeNonNegativeInteger(std::ostream &os, uint64_t integer)
Write nonNegativeInteger to the specified stream.
Definition: tlv.hpp:513
size_t writeVarNumber(std::ostream &os, uint64_t number)
Write VAR-NUMBER to the specified stream.
Definition: tlv.hpp:461
Represents a signature of Sha256WithEcdsa type.
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:453
bool readType(Iterator &begin, Iterator end, uint32_t &type) noexcept
Read TLV-TYPE.
Definition: tlv.hpp:411
#define NDN_CXX_NODISCARD
Definition: backports.hpp:68
Common includes and macros used throughout the library.
A MetaInfo holds the meta info which is signed inside the data packet.
Definition: meta-info.hpp:58
constexpr bool shouldSelectContiguousReadNumber()
Determine whether to select ReadNumber implementation for ContiguousIterator.
Definition: tlv.hpp:373
Represents an absolute name.
Definition: name.hpp:44
ContentTypeValue
ContentType values.
Definition: tlv.hpp:159
SignatureTypeValue
SignatureType values.
Definition: tlv.hpp:131
application-level nack
Definition: tlv.hpp:163
Function object to read a number from InputIterator.
Definition: tlv.hpp:302
#define NDN_CXX_UNREACHABLE
Definition: backports.hpp:72
Represents a Data packet.
Definition: data.hpp:39
Error(const char *expectedType, uint32_t actualType)
Definition: tlv.cpp:27
represents an error in TLV encoding or decoding
Definition: tlv.hpp:51
bool readVarNumber(Iterator &begin, Iterator end, uint64_t &number) noexcept
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:392
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:40
Function object to read a number from ContiguousIterator.
Definition: tlv.hpp:320