NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
name-component.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "name-component.hpp"
27 
30 #include "util/string-helper.hpp"
31 #include "security/cryptopp.hpp"
32 #include "util/crypto.hpp"
33 
34 #include <boost/lexical_cast.hpp>
35 
36 namespace ndn {
37 namespace name {
38 
39 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
40 BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
42 BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
43 static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
44  "name::Component::Error must inherit from tlv::Error");
45 
46 static const std::string&
48 {
49  static const std::string prefix{"sha256digest="};
50  return prefix;
51 }
52 
54  : Block(tlv::NameComponent)
55 {
56 }
57 
59  : Block(wire)
60 {
61  if (!isGeneric() && !isImplicitSha256Digest())
62  BOOST_THROW_EXCEPTION(Error("Cannot construct name::Component from not a NameComponent "
63  "or ImplicitSha256DigestComponent TLV wire block"));
64 }
65 
67  : Block(tlv::NameComponent, buffer)
68 {
69 }
70 
72  : Block(makeBinaryBlock(tlv::NameComponent, value.buf(), value.size()))
73 {
74 }
75 
76 Component::Component(const uint8_t* value, size_t valueLen)
77  : Block(makeBinaryBlock(tlv::NameComponent, value, valueLen))
78 {
79 }
80 
81 Component::Component(const char* str)
82  : Block(makeBinaryBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
83 {
84 }
85 
86 Component::Component(const std::string& str)
87  : Block(makeStringBlock(tlv::NameComponent, str))
88 {
89 }
90 
91 
93 Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
94 {
95  std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
96  trim(trimmedString);
97 
98  if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
99  getSha256DigestUriPrefix()) == 0) {
100  if (trimmedString.size() != getSha256DigestUriPrefix().size() + crypto::SHA256_DIGEST_SIZE * 2)
101  BOOST_THROW_EXCEPTION(Error("Cannot convert to ImplicitSha256DigestComponent"
102  "(expected sha256 in hex encoding)"));
103 
104  try {
105  trimmedString.erase(0, getSha256DigestUriPrefix().size());
106  return fromImplicitSha256Digest(fromHex(trimmedString));
107  }
108  catch (StringHelperError& e) {
109  BOOST_THROW_EXCEPTION(Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex "
110  "encoding)"));
111  }
112  }
113  else {
114  std::string value = unescape(trimmedString);
115 
116  if (value.find_first_not_of(".") == std::string::npos) {
117  // Special case for component of only periods.
118  if (value.size() <= 2)
119  // Zero, one or two periods is illegal. Ignore this component.
120  BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
121  else
122  // Remove 3 periods.
123  return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
124  }
125  else
126  return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
127  }
128 }
129 
130 
131 void
132 Component::toUri(std::ostream& result) const
133 {
135  result << getSha256DigestUriPrefix();
136 
137  printHex(result, value(), value_size(), false);
138  }
139  else {
140  const uint8_t* value = this->value();
141  size_t valueSize = value_size();
142 
143  bool gotNonDot = false;
144  for (size_t i = 0; i < valueSize; ++i) {
145  if (value[i] != 0x2e) {
146  gotNonDot = true;
147  break;
148  }
149  }
150  if (!gotNonDot) {
151  // Special case for component of zero or more periods. Add 3 periods.
152  result << "...";
153  for (size_t i = 0; i < valueSize; ++i)
154  result << '.';
155  }
156  else {
157  // In case we need to escape, set to upper case hex and save the previous flags.
158  std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
159 
160  for (size_t i = 0; i < valueSize; ++i) {
161  uint8_t x = value[i];
162  // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
163  if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
164  (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
165  x == 0x2e || x == 0x5f)
166  result << x;
167  else {
168  result << '%';
169  if (x < 16)
170  result << '0';
171  result << static_cast<uint32_t>(x);
172  }
173  }
174 
175  // Restore.
176  result.flags(saveFlags);
177  }
178  }
179 }
180 
181 std::string
183 {
184  std::ostringstream os;
185  toUri(os);
186  return os.str();
187 }
188 
190 
191 bool
193 {
194  return (value_size() == 1 || value_size() == 2 ||
195  value_size() == 4 || value_size() == 8);
196 }
197 
198 bool
199 Component::isNumberWithMarker(uint8_t marker) const
200 {
201  return (!empty() && value()[0] == marker &&
202  (value_size() == 2 || value_size() == 3 ||
203  value_size() == 5 || value_size() == 9));
204 }
205 
206 bool
208 {
210 }
211 
212 bool
214 {
216 }
217 
218 bool
220 {
222 }
223 
224 bool
226 {
228 }
229 
230 bool
232 {
234 }
235 
237 
238 uint64_t
240 {
241  if (!isNumber())
242  BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
243 
244  return readNonNegativeInteger(*this);
245 }
246 
247 uint64_t
248 Component::toNumberWithMarker(uint8_t marker) const
249 {
250  if (!isNumberWithMarker(marker))
251  BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
252  "or the value is not a nonNegativeInteger"));
253 
254  Buffer::const_iterator valueBegin = value_begin() + 1;
255  return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
256 }
257 
258 uint64_t
260 {
262 }
263 
264 uint64_t
266 {
268 }
269 
270 uint64_t
272 {
274 }
275 
278 {
280  return time::getUnixEpoch() + time::microseconds(value);
281 }
282 
283 uint64_t
285 {
287 }
288 
290 
291 Component
292 Component::fromNumber(uint64_t number)
293 {
295 }
296 
297 Component
298 Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
299 {
300  EncodingEstimator estimator;
301 
302  size_t valueLength = estimator.prependNonNegativeInteger(number);
303  valueLength += estimator.prependByteArray(&marker, 1);
304  size_t totalLength = valueLength;
305  totalLength += estimator.prependVarNumber(valueLength);
306  totalLength += estimator.prependVarNumber(tlv::NameComponent);
307 
308  EncodingBuffer encoder(totalLength, 0);
309  encoder.prependNonNegativeInteger(number);
310  encoder.prependByteArray(&marker, 1);
311  encoder.prependVarNumber(valueLength);
312  encoder.prependVarNumber(tlv::NameComponent);
313 
314  return encoder.block();
315 }
316 
317 Component
318 Component::fromVersion(uint64_t version)
319 {
320  return fromNumberWithMarker(VERSION_MARKER, version);
321 }
322 
323 Component
324 Component::fromSegment(uint64_t segmentNo)
325 {
326  return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
327 }
328 
329 Component
331 {
333 }
334 
335 Component
337 {
338  using namespace time;
339  uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
340  return fromNumberWithMarker(TIMESTAMP_MARKER, value);
341 }
342 
343 Component
345 {
347 }
348 
350 
351 bool
353 {
354  return (type() == tlv::NameComponent);
355 }
356 
357 bool
359 {
362 }
363 
364 Component
366 {
367  if (digest->size() != crypto::SHA256_DIGEST_SIZE)
368  BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
369  std::to_string(crypto::SHA256_DIGEST_SIZE) + " octets)"));
370 
372 }
373 
374 Component
375 Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
376 {
377  if (digestSize != crypto::SHA256_DIGEST_SIZE)
378  BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be "
379  + std::to_string(crypto::SHA256_DIGEST_SIZE) + " octets)"));
380 
381  return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
382 }
383 
385 
386 int
387 Component::compare(const Component& other) const
388 {
389  // Imitate ndn_Exclude_compareComponents.
390  if (type() < other.type())
391  return -1;
392  else if (type() > other.type())
393  return 1;
394  else if (value_size() < other.value_size())
395  return -1;
396  if (value_size() > other.value_size())
397  return 1;
398 
399  if (value_size() == 0)
400  return 0;
401 
402  // The components are equal length. Just do a byte compare.
403  return std::memcmp(value(), other.value(), value_size());
404 }
405 
406 Component
408 {
409  size_t totalLength = 0;
410  EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
411  // in unlikely case TLV length increases,
412  // EncodingBuffer will take care of that
413 
414  bool isOverflow = true;
415  size_t i = value_size();
416  for (; isOverflow && i > 0; i--) {
417  uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
418  totalLength += encoder.prependByte(newValue);
419  isOverflow = (newValue == 0);
420  }
421  totalLength += encoder.prependByteArray(value(), i);
422 
423  if (isOverflow) {
424  // new name components has to be extended
425  totalLength += encoder.appendByte(0);
426  }
427 
428  encoder.prependVarNumber(totalLength);
429  encoder.prependVarNumber(type());
430 
431  return encoder.block();
432 }
433 
434 
435 template<encoding::Tag TAG>
436 size_t
437 Component::wireEncode(EncodingImpl<TAG>& encoder) const
438 {
439  size_t totalLength = 0;
440  if (value_size() > 0)
441  totalLength += encoder.prependByteArray(value(), value_size());
442  totalLength += encoder.prependVarNumber(value_size());
443  totalLength += encoder.prependVarNumber(type());
444  return totalLength;
445 }
446 
447 template size_t
448 Component::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
449 
450 template size_t
451 Component::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
452 
453 const Block&
455 {
456  if (this->hasWire())
457  return *this;
458 
459  EncodingEstimator estimator;
460  size_t estimatedSize = wireEncode(estimator);
461 
462  EncodingBuffer buffer(estimatedSize, 0);
463  wireEncode(buffer);
464 
465  const_cast<Component&>(*this) = buffer.block();
466  return *this;
467 }
468 
469 void
471 {
472  *this = wire;
473  // validity check is done within Component(const Block& wire)
474 }
475 
476 } // namespace name
477 } // namespace ndn
static Component fromNumber(uint64_t number)
Create a component encoded as nonNegativeInteger.
static Component fromSequenceNumber(uint64_t seqNo)
Create sequence number component using NDN naming conventions.
bool isGeneric() const
Check if the component is GenericComponent.
Copyright (c) 2011-2015 Regents of the University of California.
uint64_t toSegmentOffset() const
Interpret as segment offset component using NDN naming conventions.
bool isTimestamp() const
Check if the component is timestamp per NDN naming conventions.
static Component fromNumberWithMarker(uint8_t marker, uint64_t number)
Create a component encoded as NameComponentWithMarker.
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
static Component fromEscapedString(const char *escapedString, size_t beginOffset, size_t endOffset)
Create name::Component by decoding the escapedString between beginOffset and endOffset according to t...
const Block & wireEncode() const
Encode to a wire format.
std::string toUri() const
Convert *this by escaping characters according to the NDN URI Scheme.
EncodingImpl< EstimatorTag > EncodingEstimator
time::system_clock::TimePoint toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
bool isNumberWithMarker(uint8_t marker) const
Check if the component is NameComponentWithMarker per NDN naming conventions.
bool isSequenceNumber() const
Check if the component is sequence number per NDN naming conventions.
static const size_t SHA256_DIGEST_SIZE
number of octets in a SHA256 digest
Definition: crypto.hpp:43
static Component fromTimestamp(const time::system_clock::TimePoint &timePoint)
Create sequence number component using NDN naming conventions.
static const std::string & getSha256DigestUriPrefix()
STL namespace.
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
void printHex(std::ostream &os, const uint8_t *buffer, size_t length, bool isUpperCase)
Output the hex representation of the bytes in array to the output stream os.
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block type type containing non-negative integer value.
Buffer::const_iterator value_begin() const
Definition: block.hpp:352
Buffer::const_iterator value_end() const
Definition: block.hpp:358
uint64_t readNonNegativeInteger(const Block &block)
Helper to read a non-negative integer from a block.
static Component fromSegmentOffset(uint64_t offset)
Create segment offset component using NDN naming conventions.
static const uint8_t SEGMENT_OFFSET_MARKER
Segment offset marker for NDN naming conventions.
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as NameComponentWithMarker.
size_t size() const
Definition: block.cpp:504
static Component fromSegment(uint64_t segmentNo)
Create segment number component using NDN naming conventions.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:50
bool isSegment() const
Check if the component is segment number per NDN naming conventions.
bool isVersion() const
Check if the component is version per NDN naming conventions.
uint64_t toVersion() const
Interpret as version component using NDN naming conventions.
EncodingImpl< EncoderTag > EncodingBuffer
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block type type with value from a buffer value of size length.
Component()
Create a new name::Component with an empty value.
Block makeStringBlock(uint32_t type, const std::string &value)
Create a TLV block type type with value from a string .
std::string unescape(const std::string &str)
Decode a percent-encoded string.
uint64_t readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:433
size_t value_size() const
Definition: block.cpp:529
uint32_t type() const
Definition: block.hpp:346
Component getSuccessor() const
static const uint8_t VERSION_MARKER
Version marker for NDN naming conventions.
time_point TimePoint
Definition: time.hpp:78
Component holds a read-only name component value.
static Component fromImplicitSha256Digest(const ConstBufferPtr &digest)
Create ImplicitSha256DigestComponent component.
void wireDecode(const Block &wire)
Decode from the wire format.
static const uint8_t SEGMENT_MARKER
Segment marker for NDN naming conventions.
bool isNumber() const
Check if the component is nonNegativeInteger.
const uint8_t * wire() const
Definition: block.cpp:495
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:471
void trim(std::string &str)
Modify str in place to erase whitespace on the left and right.
const uint8_t * value() const
Definition: block.cpp:520
static Component fromVersion(uint64_t version)
Create version component using NDN naming conventions.
bool isSegmentOffset() const
Check if the component is segment offset per NDN naming conventions.
static const uint8_t SEQUENCE_NUMBER_MARKER
Sequence number marker for NDN naming conventions.
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33
shared_ptr< const Buffer > fromHex(const std::string &hexString)
Convert the hex string to buffer.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:34
Block()
Create an empty Block.
Definition: block.cpp:48
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
static const uint8_t TIMESTAMP_MARKER
Timestamp marker for NDN naming conventions.
a concept check for TLV abstraction with .wireDecode method and constructible from Block ...
Definition: concepts.hpp:70
Class representing a general-use automatically managed/resized buffer.
Definition: buffer.hpp:44
size_t prependNonNegativeInteger(uint64_t integer)
Prepend non-negative integer integer of NDN TLV encoding.
Definition: estimator.cpp:81
const system_clock::TimePoint & getUnixEpoch()
Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) ...
Definition: time.cpp:111
bool isImplicitSha256Digest() const
Check if the component is ImplicitSha256DigestComponent.
Error that can be thrown from name::Component.