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  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  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
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 hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:471
Copyright (c) 2011-2015 Regents of the University of California.
std::string toUri() const
Convert *this by escaping characters according to the NDN URI Scheme.
bool isSequenceNumber() const
Check if the component is sequence number per NDN naming conventions.
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
static Component fromNumberWithMarker(uint8_t marker, uint64_t number)
Create a component encoded as NameComponentWithMarker.
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...
EncodingImpl< EstimatorTag > EncodingEstimator
size_t value_size() const
Definition: block.cpp:529
bool isNumberWithMarker(uint8_t marker) const
Check if the component is NameComponentWithMarker 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()
const uint8_t * wire() const
Definition: block.cpp:495
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.
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
const uint8_t * value() const
Definition: block.cpp:520
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block type type containing non-negative integer value.
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.
bool isNumber() const
Check if the component is nonNegativeInteger.
Buffer::const_iterator value_begin() const
Definition: block.hpp:352
bool isSegmentOffset() const
Check if the component is segment offset per NDN naming conventions.
static Component fromSegment(uint64_t segmentNo)
Create segment number component using NDN naming conventions.
Component getSuccessor() const
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:50
size_t size() const
Definition: block.cpp:504
EncodingImpl< EncoderTag > EncodingBuffer
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.
bool isSegment() const
Check if the component is segment number per NDN naming conventions.
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 value.
Buffer::const_iterator value_end() const
Definition: block.hpp:358
uint64_t toSegmentOffset() const
Interpret as segment offset component using NDN naming conventions.
std::string unescape(const std::string &str)
Decode a percent-encoded string.
bool isImplicitSha256Digest() const
Check if the component is ImplicitSha256DigestComponent.
uint64_t readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:433
const Block & wireEncode() const
Encode to a wire format.
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
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.
uint64_t toVersion() const
Interpret as version component using NDN naming conventions.
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
static const uint8_t SEGMENT_MARKER
Segment marker for NDN naming conventions.
void trim(std::string &str)
Modify str in place to erase whitespace on the left and right.
bool isTimestamp() const
Check if the component is timestamp per NDN naming conventions.
static Component fromVersion(uint64_t version)
Create version component using NDN naming conventions.
std::string to_string(const V &v)
Definition: backports.hpp:55
static const uint8_t SEQUENCE_NUMBER_MARKER
Sequence number marker for NDN naming conventions.
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as NameComponentWithMarker.
bool isGeneric() const
Check if the component is GenericComponent.
bool isVersion() const
Check if the component is version per 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.
time::system_clock::TimePoint toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:34
Block()
Create an empty Block.
Definition: block.cpp:48
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
uint32_t type() const
Definition: block.hpp:346
const system_clock::TimePoint & getUnixEpoch()
Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) ...
Definition: time.cpp:111
Error that can be thrown from name::Component.