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-2022 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_CXX_ENCODING_TLV_HPP
23 #define NDN_CXX_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 
41 const size_t MAX_NDN_PACKET_SIZE = 8800;
42 
46 namespace tlv {
47 
53 class Error : public std::runtime_error
54 {
55 public:
56  using std::runtime_error::runtime_error;
57 
58  Error(const char* expectedType, uint32_t actualType);
59 };
60 
66 enum : uint32_t {
67  Invalid = 0,
68  Interest = 5,
69  Data = 6,
70 
71  Name = 7,
81 
85  Nonce = 10,
87  HopLimit = 34,
91 
92  MetaInfo = 20,
93  Content = 21,
99 
102  KeyDigest = 29,
106 
108  NotBefore = 254,
109  NotAfter = 255,
114 
117 
120 };
121 
127 enum SignatureTypeValue : uint16_t {
134 };
135 
136 std::ostream&
137 operator<<(std::ostream& os, SignatureTypeValue st);
138 
144 enum ContentTypeValue : uint32_t {
152 };
153 
154 std::ostream&
155 operator<<(std::ostream& os, ContentTypeValue ct);
156 
161 constexpr bool
162 isCriticalType(uint32_t type) noexcept
163 {
164  return type <= 31 || (type & 0x01);
165 }
166 
178 template<typename Iterator>
180 readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
181 
195 template<typename Iterator>
197 readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
198 
209 template<typename Iterator>
210 uint64_t
211 readVarNumber(Iterator& begin, Iterator end);
212 
225 template<typename Iterator>
226 uint32_t
227 readType(Iterator& begin, Iterator end);
228 
232 constexpr size_t
233 sizeOfVarNumber(uint64_t number) noexcept;
234 
239 size_t
240 writeVarNumber(std::ostream& os, uint64_t number);
241 
255 template<typename Iterator>
256 uint64_t
257 readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
258 
262 constexpr size_t
263 sizeOfNonNegativeInteger(uint64_t integer) noexcept;
264 
269 size_t
270 writeNonNegativeInteger(std::ostream& os, uint64_t integer);
271 
275 
276 // Inline definitions
277 
281 
282 namespace detail {
283 
286 template<typename Iterator>
288 {
289 public:
290  constexpr bool
291  operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
292  {
293  number = 0;
294  size_t count = 0;
295  for (; begin != end && count < size; ++begin, ++count) {
296  number = (number << 8) | *begin;
297  }
298  return count == size;
299  }
300 };
301 
304 template<typename Iterator>
306 {
307 public:
308  constexpr bool
309  operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
310  {
311  if (begin + size > end) {
312  return false;
313  }
314 
315  switch (size) {
316  case 1: {
317  number = *begin;
318  ++begin;
319  return true;
320  }
321  case 2: {
322  uint16_t value = 0;
323  std::memcpy(&value, &*begin, 2);
324  begin += 2;
325  number = boost::endian::big_to_native(value);
326  return true;
327  }
328  case 4: {
329  uint32_t value = 0;
330  std::memcpy(&value, &*begin, 4);
331  begin += 4;
332  number = boost::endian::big_to_native(value);
333  return true;
334  }
335  case 8: {
336  uint64_t value = 0;
337  std::memcpy(&value, &*begin, 8);
338  begin += 8;
339  number = boost::endian::big_to_native(value);
340  return true;
341  }
342  default: {
344  }
345  }
346  }
347 };
348 
354 template<typename Iterator,
355  typename DecayedIterator = std::decay_t<Iterator>,
356  typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
357 constexpr bool
359 {
360  return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
361  std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
362  std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
363  sizeof(ValueType) == 1 &&
364  !std::is_same<ValueType, bool>::value;
365 }
366 
367 template<typename Iterator>
368 class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
369  ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
370 {
371 };
372 
373 } // namespace detail
374 
375 template<typename Iterator>
376 bool
377 readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
378 {
379  if (begin == end)
380  return false;
381 
382  uint8_t firstOctet = *begin;
383  ++begin;
384  if (firstOctet < 253) {
385  number = firstOctet;
386  return true;
387  }
388 
389  size_t size = firstOctet == 253 ? 2 :
390  firstOctet == 254 ? 4 : 8;
391  return detail::ReadNumber<Iterator>()(size, begin, end, number);
392 }
393 
394 template<typename Iterator>
395 bool
396 readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
397 {
398  uint64_t number = 0;
399  bool isOk = readVarNumber(begin, end, number);
400  if (!isOk || number == Invalid || number > std::numeric_limits<uint32_t>::max()) {
401  return false;
402  }
403 
404  type = static_cast<uint32_t>(number);
405  return true;
406 }
407 
408 template<typename Iterator>
409 uint64_t
410 readVarNumber(Iterator& begin, Iterator end)
411 {
412  if (begin == end) {
413  NDN_THROW(Error("Empty buffer during TLV parsing"));
414  }
415 
416  uint64_t value = 0;
417  bool isOk = readVarNumber(begin, end, value);
418  if (!isOk) {
419  NDN_THROW(Error("Insufficient data during TLV parsing"));
420  }
421 
422  return value;
423 }
424 
425 template<typename Iterator>
426 uint32_t
427 readType(Iterator& begin, Iterator end)
428 {
429  uint64_t type = readVarNumber(begin, end);
430  if (type == Invalid || type > std::numeric_limits<uint32_t>::max()) {
431  NDN_THROW(Error("Illegal TLV-TYPE " + to_string(type)));
432  }
433 
434  return static_cast<uint32_t>(type);
435 }
436 
437 constexpr size_t
438 sizeOfVarNumber(uint64_t number) noexcept
439 {
440  return number < 253 ? 1 :
441  number <= std::numeric_limits<uint16_t>::max() ? 3 :
442  number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
443 }
444 
445 inline size_t
446 writeVarNumber(std::ostream& os, uint64_t number)
447 {
448  if (number < 253) {
449  os.put(static_cast<char>(number));
450  return 1;
451  }
452  else if (number <= std::numeric_limits<uint16_t>::max()) {
453  os.put(static_cast<char>(253));
454  uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
455  os.write(reinterpret_cast<const char*>(&value), 2);
456  return 3;
457  }
458  else if (number <= std::numeric_limits<uint32_t>::max()) {
459  os.put(static_cast<char>(254));
460  uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
461  os.write(reinterpret_cast<const char*>(&value), 4);
462  return 5;
463  }
464  else {
465  os.put(static_cast<char>(255));
466  uint64_t value = boost::endian::native_to_big(number);
467  os.write(reinterpret_cast<const char*>(&value), 8);
468  return 9;
469  }
470 }
471 
472 template<typename Iterator>
473 uint64_t
474 readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
475 {
476  if (size != 1 && size != 2 && size != 4 && size != 8) {
477  NDN_THROW(Error("Invalid length " + to_string(size) + " for NonNegativeInteger"));
478  }
479 
480  uint64_t number = 0;
481  bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
482  if (!isOk) {
483  NDN_THROW(Error("Insufficient data during NonNegativeInteger parsing"));
484  }
485 
486  return number;
487 }
488 
489 constexpr size_t
490 sizeOfNonNegativeInteger(uint64_t integer) noexcept
491 {
492  return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
493  integer <= std::numeric_limits<uint16_t>::max() ? 2 :
494  integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
495 }
496 
497 inline size_t
498 writeNonNegativeInteger(std::ostream& os, uint64_t integer)
499 {
500  if (integer <= std::numeric_limits<uint8_t>::max()) {
501  os.put(static_cast<char>(integer));
502  return 1;
503  }
504  else if (integer <= std::numeric_limits<uint16_t>::max()) {
505  uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
506  os.write(reinterpret_cast<const char*>(&value), 2);
507  return 2;
508  }
509  else if (integer <= std::numeric_limits<uint32_t>::max()) {
510  uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
511  os.write(reinterpret_cast<const char*>(&value), 4);
512  return 4;
513  }
514  else {
515  uint64_t value = boost::endian::native_to_big(integer);
516  os.write(reinterpret_cast<const char*>(&value), 8);
517  return 8;
518  }
519 }
520 
521 } // namespace tlv
522 } // namespace ndn
523 
524 #endif // NDN_CXX_ENCODING_TLV_HPP
#define NDN_CXX_NODISCARD
Definition: backports.hpp:68
#define NDN_CXX_UNREACHABLE
Definition: backports.hpp:138
Represents a Data packet.
Definition: data.hpp:39
Represents an Interest packet.
Definition: interest.hpp:50
A MetaInfo holds the meta info which is signed inside the Data packet.
Definition: meta-info.hpp:62
Represents an absolute name.
Definition: name.hpp:44
Represents a SignatureInfo or InterestSignatureInfo TLV element.
Represents an error in TLV encoding or decoding.
Definition: tlv.hpp:54
Error(const char *expectedType, uint32_t actualType)
Definition: tlv.cpp:27
Function object to read a number from ContiguousIterator.
Definition: tlv.hpp:306
constexpr bool operator()(size_t size, Iterator &begin, Iterator end, uint64_t &number) const noexcept
Definition: tlv.hpp:309
Function object to read a number from InputIterator.
Definition: tlv.hpp:288
constexpr bool operator()(size_t size, Iterator &begin, Iterator end, uint64_t &number) const noexcept
Definition: tlv.hpp:291
Common includes and macros used throughout the library.
#define NDN_THROW(e)
Definition: exception.hpp:61
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
constexpr bool shouldSelectContiguousReadNumber()
Determine whether to select ReadNumber implementation for ContiguousIterator.
Definition: tlv.hpp:358
@ SignatureSeqNum
Definition: tlv.hpp:105
@ KeyDigest
Definition: tlv.hpp:102
@ TimestampNameComponent
Definition: tlv.hpp:79
@ FinalBlockId
Definition: tlv.hpp:98
@ GenericNameComponent
Definition: tlv.hpp:72
@ DescriptionValue
Definition: tlv.hpp:113
@ SignatureNonce
Definition: tlv.hpp:103
@ InterestLifetime
Definition: tlv.hpp:86
@ HopLimit
Definition: tlv.hpp:87
@ DescriptionKey
Definition: tlv.hpp:112
@ AppPrivateBlock2
Definition: tlv.hpp:119
@ InterestSignatureInfo
Definition: tlv.hpp:89
@ ApplicationParameters
Definition: tlv.hpp:88
@ ByteOffsetNameComponent
Definition: tlv.hpp:77
@ ForwardingHint
Definition: tlv.hpp:84
@ AdditionalDescription
Definition: tlv.hpp:110
@ SignatureType
Definition: tlv.hpp:100
@ NameComponentMin
Definition: tlv.hpp:115
@ InterestSignatureValue
Definition: tlv.hpp:90
@ SignatureTime
Definition: tlv.hpp:104
@ VersionNameComponent
Definition: tlv.hpp:78
@ AppPrivateBlock1
Definition: tlv.hpp:118
@ Content
Definition: tlv.hpp:93
@ CanBePrefix
Definition: tlv.hpp:82
@ Invalid
Definition: tlv.hpp:67
@ DescriptionEntry
Definition: tlv.hpp:111
@ ContentType
Definition: tlv.hpp:96
@ SequenceNumNameComponent
Definition: tlv.hpp:80
@ NameComponentMax
Definition: tlv.hpp:116
@ ValidityPeriod
Definition: tlv.hpp:107
@ NotAfter
Definition: tlv.hpp:109
@ FreshnessPeriod
Definition: tlv.hpp:97
@ KeywordNameComponent
Definition: tlv.hpp:75
@ ParametersSha256DigestComponent
Definition: tlv.hpp:74
@ SignatureValue
Definition: tlv.hpp:95
@ ImplicitSha256DigestComponent
Definition: tlv.hpp:73
@ NotBefore
Definition: tlv.hpp:108
@ SegmentNameComponent
Definition: tlv.hpp:76
@ MustBeFresh
Definition: tlv.hpp:83
@ Nonce
Definition: tlv.hpp:85
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:438
constexpr bool isCriticalType(uint32_t type) noexcept
Determine whether a TLV-TYPE is "critical" for evolvability purpose.
Definition: tlv.hpp:162
bool readVarNumber(Iterator &begin, Iterator end, uint64_t &number) noexcept
Read VAR-NUMBER in NDN-TLV encoding.
Definition: tlv.hpp:377
ContentTypeValue
ContentType values.
Definition: tlv.hpp:144
@ ContentType_Key
public key, certificate
Definition: tlv.hpp:147
@ ContentType_Manifest
Definition: tlv.hpp:149
@ ContentType_Link
another name that identifies the actual data content
Definition: tlv.hpp:146
@ ContentType_Blob
payload
Definition: tlv.hpp:145
@ ContentType_Flic
File-Like ICN Collection.
Definition: tlv.hpp:151
@ ContentType_PrefixAnn
prefix announcement
Definition: tlv.hpp:150
@ ContentType_Nack
application-level nack
Definition: tlv.hpp:148
size_t writeNonNegativeInteger(std::ostream &os, uint64_t integer)
Write a NonNegativeInteger to the specified stream.
Definition: tlv.hpp:498
bool readType(Iterator &begin, Iterator end, uint32_t &type) noexcept
Read TLV-TYPE.
Definition: tlv.hpp:396
std::ostream & operator<<(std::ostream &os, SignatureTypeValue st)
Definition: tlv.cpp:33
size_t writeVarNumber(std::ostream &os, uint64_t number)
Write VAR-NUMBER to the specified stream.
Definition: tlv.hpp:446
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:490
SignatureTypeValue
SignatureType values.
Definition: tlv.hpp:127
@ SignatureSha256WithRsa
Definition: tlv.hpp:129
@ DigestSha256
Definition: tlv.hpp:128
@ SignatureHmacWithSha256
Definition: tlv.hpp:131
@ SignatureEd25519
Definition: tlv.hpp:132
@ SignatureSha256WithEcdsa
Definition: tlv.hpp:130
@ NullSignature
Definition: tlv.hpp:133
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read a NonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:474
Definition: data.cpp:25
const size_t MAX_NDN_PACKET_SIZE
Practical size limit of a network-layer packet.
Definition: tlv.hpp:41