NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: 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; -*- */
2 /*
3  * Copyright (c) 2013-2018 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 Jeff Thompson <jefft0@remap.ucla.edu>
22  * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
23  * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
24  */
25 
26 #include "name-component.hpp"
27 
30 #include "util/sha256.hpp"
31 #include "util/string-helper.hpp"
32 
33 #include <cstring>
34 #include <sstream>
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 
53 void
54 Component::ensureValid() const
55 {
57  BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
58  }
60  BOOST_THROW_EXCEPTION(Error("ImplicitSha256DigestComponent TLV-LENGTH must be " +
62  }
63 }
64 
65 Component::Component(uint32_t type)
66  : Block(type)
67 {
68  ensureValid();
69 }
70 
72  : Block(wire)
73 {
74  ensureValid();
75 }
76 
77 Component::Component(uint32_t type, ConstBufferPtr buffer)
78  : Block(type, std::move(buffer))
79 {
80 }
81 
82 Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
83  : Block(makeBinaryBlock(type, value, valueLen))
84 {
85 }
86 
87 Component::Component(const char* str)
88  : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
89 {
90 }
91 
92 Component::Component(const std::string& str)
94 {
95 }
96 
97 static Component
98 parseSha256DigestUri(std::string input)
99 {
100  input.erase(0, getSha256DigestUriPrefix().size());
101 
102  try {
104  }
105  catch (const StringHelperError&) {
106  BOOST_THROW_EXCEPTION(Component::Error("Cannot convert to a ImplicitSha256DigestComponent "
107  "(invalid hex encoding)"));
108  }
109 }
110 
111 Component
113 {
114  uint32_t type = tlv::GenericNameComponent;
115  size_t equalPos = input.find('=');
116  if (equalPos != std::string::npos) {
117  if (equalPos + 1 == getSha256DigestUriPrefix().size() &&
118  input.compare(0, getSha256DigestUriPrefix().size(), getSha256DigestUriPrefix()) == 0) {
119  return parseSha256DigestUri(std::move(input));
120  }
121 
122  long parsedType = std::strtol(input.data(), nullptr, 10);
123  if (parsedType < tlv::NameComponentMin || parsedType > tlv::NameComponentMax ||
124  parsedType == tlv::ImplicitSha256DigestComponent || parsedType == tlv::GenericNameComponent ||
125  to_string(parsedType).size() != equalPos) {
126  BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE in NameComponent URI"));
127  }
128  type = static_cast<uint32_t>(parsedType);
129  input.erase(0, equalPos + 1);
130  }
131 
132  std::string value = unescape(input);
133  if (value.find_first_not_of('.') == std::string::npos) { // all periods
134  if (value.size() < 3) {
135  BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
136  }
137  return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
138  }
139  return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
140 }
141 
142 void
143 Component::toUri(std::ostream& os) const
144 {
146  os << getSha256DigestUriPrefix();
147  printHex(os, value(), value_size(), false);
148  return;
149  }
150 
151  if (type() != tlv::GenericNameComponent) {
152  os << type() << '=';
153  }
154 
155  if (std::all_of(value_begin(), value_end(), [] (uint8_t x) { return x == '.'; })) { // all periods
156  os << "...";
157  }
158 
159  escape(os, reinterpret_cast<const char*>(value()), value_size());
160 }
161 
162 std::string
164 {
165  std::ostringstream os;
166  toUri(os);
167  return os.str();
168 }
169 
171 
172 bool
174 {
175  return (value_size() == 1 || value_size() == 2 ||
176  value_size() == 4 || value_size() == 8);
177 }
178 
179 bool
180 Component::isNumberWithMarker(uint8_t marker) const
181 {
182  return (!empty() && value()[0] == marker &&
183  (value_size() == 2 || value_size() == 3 ||
184  value_size() == 5 || value_size() == 9));
185 }
186 
187 bool
189 {
191 }
192 
193 bool
195 {
197 }
198 
199 bool
201 {
203 }
204 
205 bool
207 {
209 }
210 
211 bool
213 {
215 }
216 
218 
219 uint64_t
221 {
222  if (!isNumber())
223  BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
224 
225  return readNonNegativeInteger(*this);
226 }
227 
228 uint64_t
229 Component::toNumberWithMarker(uint8_t marker) const
230 {
231  if (!isNumberWithMarker(marker))
232  BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
233  "or the value is not a nonNegativeInteger"));
234 
235  Buffer::const_iterator valueBegin = value_begin() + 1;
236  return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
237 }
238 
239 uint64_t
241 {
243 }
244 
245 uint64_t
247 {
249 }
250 
251 uint64_t
253 {
255 }
256 
259 {
261  return time::getUnixEpoch() + time::microseconds(value);
262 }
263 
264 uint64_t
266 {
268 }
269 
271 
272 Component
273 Component::fromNumber(uint64_t number)
274 {
276 }
277 
278 Component
279 Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
280 {
281  EncodingEstimator estimator;
282 
283  size_t valueLength = estimator.prependNonNegativeInteger(number);
284  valueLength += estimator.prependByteArray(&marker, 1);
285  size_t totalLength = valueLength;
286  totalLength += estimator.prependVarNumber(valueLength);
287  totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
288 
289  EncodingBuffer encoder(totalLength, 0);
290  encoder.prependNonNegativeInteger(number);
291  encoder.prependByteArray(&marker, 1);
292  encoder.prependVarNumber(valueLength);
293  encoder.prependVarNumber(tlv::GenericNameComponent);
294 
295  return encoder.block();
296 }
297 
298 Component
299 Component::fromVersion(uint64_t version)
300 {
301  return fromNumberWithMarker(VERSION_MARKER, version);
302 }
303 
304 Component
305 Component::fromSegment(uint64_t segmentNo)
306 {
307  return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
308 }
309 
310 Component
312 {
314 }
315 
316 Component
318 {
319  using namespace time;
320  uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
322 }
323 
324 Component
326 {
328 }
329 
331 
332 bool
334 {
335  return type() == tlv::GenericNameComponent;
336 }
337 
338 bool
340 {
343 }
344 
345 Component
347 {
348  if (digest->size() != util::Sha256::DIGEST_SIZE)
349  BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
350  to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
351 
353 }
354 
355 Component
356 Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
357 {
358  if (digestSize != util::Sha256::DIGEST_SIZE)
359  BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
360  to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
361 
362  return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
363 }
364 
366 
367 bool
368 Component::equals(const Component& other) const
369 {
370  return type() == other.type() &&
371  value_size() == other.value_size() &&
372  (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
373  std::equal(value_begin(), value_end(), other.value_begin()));
374 }
375 
376 int
377 Component::compare(const Component& other) const
378 {
379  if (this->hasWire() && other.hasWire()) {
380  // In the common case where both components have wire encoding,
381  // it's more efficient to simply compare the wire encoding.
382  // This works because lexical order of TLV encoding happens to be
383  // the same as canonical order of the value.
384  return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
385  }
386 
387  int cmpType = type() - other.type();
388  if (cmpType != 0)
389  return cmpType;
390 
391  int cmpSize = value_size() - other.value_size();
392  if (cmpSize != 0)
393  return cmpSize;
394 
395  if (empty())
396  return 0;
397 
398  return std::memcmp(value(), other.value(), value_size());
399 }
400 
401 Component
403 {
404  size_t totalLength = 0;
405  EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
406  // in unlikely case TLV length increases,
407  // EncodingBuffer will take care of that
408 
409  bool isOverflow = true;
410  size_t i = value_size();
411  for (; isOverflow && i > 0; i--) {
412  uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
413  totalLength += encoder.prependByte(newValue);
414  isOverflow = (newValue == 0);
415  }
416  totalLength += encoder.prependByteArray(value(), i);
417 
418  if (isOverflow) {
419  // new name components has to be extended
420  totalLength += encoder.appendByte(0);
421  }
422 
423  encoder.prependVarNumber(totalLength);
424  encoder.prependVarNumber(type());
425 
426  return encoder.block();
427 }
428 
429 template<encoding::Tag TAG>
430 size_t
432 {
433  size_t totalLength = 0;
434  if (value_size() > 0)
435  totalLength += encoder.prependByteArray(value(), value_size());
436  totalLength += encoder.prependVarNumber(value_size());
437  totalLength += encoder.prependVarNumber(type());
438  return totalLength;
439 }
440 
442 
443 const Block&
445 {
446  if (this->hasWire())
447  return *this;
448 
449  EncodingEstimator estimator;
450  size_t estimatedSize = wireEncode(estimator);
451 
452  EncodingBuffer buffer(estimatedSize, 0);
453  wireEncode(buffer);
454 
455  const_cast<Component&>(*this) = buffer.block();
456  return *this;
457 }
458 
459 void
461 {
462  *this = wire;
463  // validity check is done within Component(const Block& wire)
464 }
465 
466 } // namespace name
467 } // 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:252
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 const size_t DIGEST_SIZE
Length in bytes of a SHA-256 digest.
Definition: sha256.hpp:60
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:319
Component(uint32_t type=tlv::GenericNameComponent)
Construct a NameComponent of TLV-TYPE type, using empty TLV-VALUE.
bool isNumberWithMarker(uint8_t marker) const
Check if the component is NameComponentWithMarker per NDN naming conventions.
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
Get pointer to encoded wire.
Definition: block.cpp:292
STL namespace.
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
const uint8_t * value() const
Get pointer to TLV-VALUE.
Definition: block.cpp:313
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block containing a non-negative integer.
element_iterator erase(element_const_iterator position)
Erase a sub element.
Definition: block.cpp:454
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
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
Get begin iterator of TLV-VALUE.
Definition: block.hpp:255
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:60
size_t size() const
Get size of encoded wire, including Type-Length-Value.
Definition: block.cpp:301
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, const Iterator &end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:474
shared_ptr< Buffer > fromHex(const std::string &hexString)
Convert the hex string to buffer.
static Component fromEscapedString(const char *input, size_t beginOffset, size_t endOffset)
Decode NameComponent from a URI component.
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block copying TLV-VALUE from raw buffer.
bool isSegment() const
Check if the component is segment number per NDN naming conventions.
Block makeStringBlock(uint32_t type, const std::string &value)
Create a TLV block containing a string.
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:264
static Component parseSha256DigestUri(std::string input)
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.
std::string escape(const std::string &str)
Percent-encode a string.
bool equals(const Component &other) const
Check if this is the same component as other.
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:196
Represents a name component.
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.
NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component)
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.
void printHex(std::ostream &os, uint64_t num, bool wantUpperCase)
Output the hex representation of num to the output stream os.
std::string to_string(const V &v)
Definition: backports.hpp:107
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.
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:44
Block()
Create an empty Block.
Definition: block.cpp:51
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:80
size_t prependNonNegativeInteger(uint64_t integer)
Prepend non-negative integer integer of NDN TLV encoding.
Definition: estimator.cpp:81
EncodingImpl< EncoderTag > EncodingBuffer
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
const system_clock::TimePoint & getUnixEpoch()
Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) ...
Definition: time.cpp:106
EncodingImpl< EstimatorTag > EncodingEstimator
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:89