interest.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2017 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 #include "interest.hpp"
23 #include "util/random.hpp"
24 #include "data.hpp"
25 
26 #include <cstring>
27 #include <sstream>
28 
29 namespace ndn {
30 
31 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
32 BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
33 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Interest>));
34 BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
35 static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
36  "Interest::Error must inherit from tlv::Error");
37 
38 Interest::Interest(const Name& name, time::milliseconds interestLifetime)
39  : m_name(name)
40  , m_interestLifetime(interestLifetime)
41 {
42  if (interestLifetime < time::milliseconds::zero()) {
43  BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
44  }
45 }
46 
48 {
49  wireDecode(wire);
50 }
51 
52 // ---- encode and decode ----
53 
54 template<encoding::Tag TAG>
55 size_t
56 Interest::wireEncode(EncodingImpl<TAG>& encoder) const
57 {
58  size_t totalLength = 0;
59 
60  // Interest ::= INTEREST-TYPE TLV-LENGTH
61  // Name
62  // Selectors?
63  // Nonce
64  // InterestLifetime?
65  // ForwardingHint?
66 
67  // (reverse encoding)
68 
69  // ForwardingHint
70  if (m_forwardingHint.size() > 0) {
71  totalLength += m_forwardingHint.wireEncode(encoder);
72  }
73 
74  // InterestLifetime
76  totalLength += prependNonNegativeIntegerBlock(encoder,
78  getInterestLifetime().count());
79  }
80 
81  // Nonce
82  uint32_t nonce = this->getNonce(); // assigns random Nonce if needed
83  totalLength += encoder.prependByteArray(reinterpret_cast<uint8_t*>(&nonce), sizeof(nonce));
84  totalLength += encoder.prependVarNumber(sizeof(nonce));
85  totalLength += encoder.prependVarNumber(tlv::Nonce);
86 
87  // Selectors
88  if (hasSelectors()) {
89  totalLength += getSelectors().wireEncode(encoder);
90  }
91 
92  // Name
93  totalLength += getName().wireEncode(encoder);
94 
95  totalLength += encoder.prependVarNumber(totalLength);
96  totalLength += encoder.prependVarNumber(tlv::Interest);
97  return totalLength;
98 }
99 
101 
102 const Block&
104 {
105  if (m_wire.hasWire())
106  return m_wire;
107 
108  EncodingEstimator estimator;
109  size_t estimatedSize = wireEncode(estimator);
110 
111  EncodingBuffer buffer(estimatedSize, 0);
112  wireEncode(buffer);
113 
114  const_cast<Interest*>(this)->wireDecode(buffer.block());
115  return m_wire;
116 }
117 
118 void
120 {
121  m_wire = wire;
122  m_wire.parse();
123 
124  if (m_wire.type() != tlv::Interest)
125  BOOST_THROW_EXCEPTION(Error("Unexpected TLV number when decoding Interest"));
126 
127  // Name
128  m_name.wireDecode(m_wire.get(tlv::Name));
129 
130  // Selectors
132  if (val != m_wire.elements_end()) {
133  m_selectors.wireDecode(*val);
134  }
135  else
136  m_selectors = Selectors();
137 
138  // Nonce
139  val = m_wire.find(tlv::Nonce);
140  if (val == m_wire.elements_end()) {
141  BOOST_THROW_EXCEPTION(Error("Nonce element is missing"));
142  }
143  uint32_t nonce = 0;
144  if (val->value_size() != sizeof(nonce)) {
145  BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
146  }
147  std::memcpy(&nonce, val->value(), sizeof(nonce));
148  m_nonce = nonce;
149 
150  // InterestLifetime
151  val = m_wire.find(tlv::InterestLifetime);
152  if (val != m_wire.elements_end()) {
153  m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
154  }
155  else {
156  m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
157  }
158 
159  // ForwardingHint
160  val = m_wire.find(tlv::ForwardingHint);
161  if (val != m_wire.elements_end()) {
162  m_forwardingHint.wireDecode(*val, false);
163  }
164  else {
165  m_forwardingHint = DelegationList();
166  }
167 }
168 
169 std::string
171 {
172  std::ostringstream os;
173  os << *this;
174  return os.str();
175 }
176 
177 // ---- matching ----
178 
179 bool
180 Interest::matchesName(const Name& name) const
181 {
182  if (name.size() < m_name.size())
183  return false;
184 
185  if (!m_name.isPrefixOf(name))
186  return false;
187 
188  if (getMinSuffixComponents() >= 0 &&
189  // name must include implicit digest
190  !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
191  return false;
192 
193  if (getMaxSuffixComponents() >= 0 &&
194  // name must include implicit digest
195  !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
196  return false;
197 
198  if (!getExclude().empty() &&
199  name.size() > m_name.size() &&
200  getExclude().isExcluded(name[m_name.size()]))
201  return false;
202 
203  return true;
204 }
205 
206 bool
207 Interest::matchesData(const Data& data) const
208 {
209  size_t interestNameLength = m_name.size();
210  const Name& dataName = data.getName();
211  size_t fullNameLength = dataName.size() + 1;
212 
213  // check MinSuffixComponents
214  bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
215  size_t minSuffixComponents = hasMinSuffixComponents ?
216  static_cast<size_t>(getMinSuffixComponents()) : 0;
217  if (!(interestNameLength + minSuffixComponents <= fullNameLength))
218  return false;
219 
220  // check MaxSuffixComponents
221  bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
222  if (hasMaxSuffixComponents &&
223  !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
224  return false;
225 
226  // check prefix
227  if (interestNameLength == fullNameLength) {
228  if (m_name.get(-1).isImplicitSha256Digest()) {
229  if (m_name != data.getFullName())
230  return false;
231  }
232  else {
233  // Interest Name is same length as Data full Name, but last component isn't digest
234  // so there's no possibility of matching
235  return false;
236  }
237  }
238  else {
239  // Interest Name is a strict prefix of Data full Name
240  if (!m_name.isPrefixOf(dataName))
241  return false;
242  }
243 
244  // check Exclude
245  // Exclude won't be violated if Interest Name is same as Data full Name
246  if (!getExclude().empty() && fullNameLength > interestNameLength) {
247  if (interestNameLength == fullNameLength - 1) {
248  // component to exclude is the digest
249  if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
250  return false;
251  // There's opportunity to inspect the Exclude filter and determine whether
252  // the digest would make a difference.
253  // eg. "<NameComponent>AA</NameComponent><Any/>" doesn't exclude any digest -
254  // fullName not needed;
255  // "<Any/><NameComponent>AA</NameComponent>" and
256  // "<Any/><ImplicitSha256DigestComponent>ffffffffffffffffffffffffffffffff
257  // </ImplicitSha256DigestComponent>"
258  // excludes all digests - fullName not needed;
259  // "<Any/><ImplicitSha256DigestComponent>80000000000000000000000000000000
260  // </ImplicitSha256DigestComponent>"
261  // excludes some digests - fullName required
262  // But Interests that contain the exact Data Name before digest and also
263  // contain Exclude filter is too rare to optimize for, so we request
264  // fullName no matter what's in the Exclude filter.
265  }
266  else {
267  // component to exclude is not the digest
268  if (getExclude().isExcluded(dataName.get(interestNameLength)))
269  return false;
270  }
271  }
272 
273  // check PublisherPublicKeyLocator
274  const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
275  if (!publisherPublicKeyLocator.empty()) {
276  const Signature& signature = data.getSignature();
277  const Block& signatureInfo = signature.getInfo();
279  if (it == signatureInfo.elements_end()) {
280  return false;
281  }
282  if (publisherPublicKeyLocator.wireEncode() != *it) {
283  return false;
284  }
285  }
286 
287  return true;
288 }
289 
290 bool
292 {
294  return (this->getName() == other.getName() &&
295  this->getSelectors() == other.getSelectors());
296 }
297 
298 // ---- field accessors ----
299 
300 uint32_t
302 {
303  if (!m_nonce) {
304  m_nonce = random::generateWord32();
305  }
306  return *m_nonce;
307 }
308 
309 Interest&
310 Interest::setNonce(uint32_t nonce)
311 {
312  m_nonce = nonce;
313  m_wire.reset();
314  return *this;
315 }
316 
317 void
319 {
320  if (!hasNonce())
321  return;
322 
323  uint32_t oldNonce = getNonce();
324  uint32_t newNonce = oldNonce;
325  while (newNonce == oldNonce)
326  newNonce = random::generateWord32();
327 
328  setNonce(newNonce);
329 }
330 
331 Interest&
332 Interest::setInterestLifetime(time::milliseconds interestLifetime)
333 {
334  if (interestLifetime < time::milliseconds::zero()) {
335  BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
336  }
337  m_interestLifetime = interestLifetime;
338  m_wire.reset();
339  return *this;
340 }
341 
342 Interest&
344 {
345  m_forwardingHint = value;
346  m_wire.reset();
347  return *this;
348 }
349 
350 // ---- operators ----
351 
352 std::ostream&
353 operator<<(std::ostream& os, const Interest& interest)
354 {
355  os << interest.getName();
356 
357  char delim = '?';
358 
359  if (interest.getMinSuffixComponents() >= 0) {
360  os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
361  delim = '&';
362  }
363  if (interest.getMaxSuffixComponents() >= 0) {
364  os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
365  delim = '&';
366  }
367  if (interest.getChildSelector() != DEFAULT_CHILD_SELECTOR) {
368  os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
369  delim = '&';
370  }
371  if (interest.getMustBeFresh()) {
372  os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
373  delim = '&';
374  }
376  os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
377  delim = '&';
378  }
379 
380  if (interest.hasNonce()) {
381  os << delim << "ndn.Nonce=" << interest.getNonce();
382  delim = '&';
383  }
384  if (!interest.getExclude().empty()) {
385  os << delim << "ndn.Exclude=" << interest.getExclude();
386  delim = '&';
387  }
388 
389  return os;
390 }
391 
392 } // namespace ndn
void wireDecode(const Block &wire)
Decode the input from wire format.
Definition: selectors.cpp:131
size_t wireEncode(EncodingImpl< TAG > &encoder) const
prepend wire encoding
Definition: key-locator.cpp:52
int getMinSuffixComponents() const
Definition: interest.hpp:248
int getMaxSuffixComponents() const
Definition: interest.hpp:262
const Name & getName() const
Definition: interest.hpp:139
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
bool matchesName(const Name &name) const
Check if Interest, including selectors, matches the given name.
Definition: interest.cpp:180
size_t prependNonNegativeIntegerBlock(EncodingImpl< TAG > &encoder, uint32_t type, uint64_t value)
Prepend a TLV element containing a non-negative integer.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: selectors.cpp:61
element_const_iterator find(uint32_t type) const
Find the first sub element of specified TLV-TYPE.
Definition: block.cpp:429
void refreshNonce()
Refresh nonce.
Definition: interest.cpp:318
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:274
element_container::const_iterator element_const_iterator
Definition: block.hpp:47
bool hasSelectors() const
Definition: interest.hpp:228
const Signature & getSignature() const
Get Signature.
Definition: data.hpp:182
const int DEFAULT_CHILD_SELECTOR
Definition: selectors.hpp:31
const Block & wireEncode() const
Encode to a wire format.
Definition: interest.cpp:103
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:131
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
represents an Interest packet
Definition: interest.hpp:42
std::string toUri() const
Encode the name according to the NDN URI Scheme.
Definition: interest.cpp:170
int getChildSelector() const
Definition: interest.hpp:304
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
uint32_t getNonce() const
Get nonce.
Definition: interest.cpp:301
uint32_t generateWord32()
Generate a non-cryptographically-secure random integer in the range [0, 2^32)
Definition: random.cpp:63
Interest(const Name &name=Name(), time::milliseconds interestLifetime=DEFAULT_INTEREST_LIFETIME)
Create a new Interest with the given name and interest lifetime.
Definition: interest.cpp:38
bool isExcluded(const name::Component &comp) const
Check if name component is excluded.
Definition: exclude.cpp:228
void wireDecode(const Block &block, bool wantSort=true)
decode a DelegationList
const Selectors & getSelectors() const
Definition: interest.hpp:234
int getMustBeFresh() const
Definition: interest.hpp:318
bool empty() const
Definition: key-locator.hpp:95
Interest & setNonce(uint32_t nonce)
Set nonce.
Definition: interest.cpp:310
const Exclude & getExclude() const
Definition: interest.hpp:290
const Block & get(uint32_t type) const
Get the first sub element of specified TLV-TYPE.
Definition: block.cpp:417
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
size_t size() const
Get number of components.
Definition: name.hpp:154
size_t size() const noexcept
void reset()
Reset wire buffer of the element.
Definition: block.cpp:257
Represents an absolute name.
Definition: name.hpp:42
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
Definition: name.cpp:260
bool matchesData(const Data &data) const
Check if Interest can be satisfied by data.
Definition: interest.cpp:207
void parse() const
Parse TLV-VALUE into sub elements.
Definition: block.cpp:335
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
void wireDecode(const Block &wire)
Decode from the wire format.
Definition: interest.cpp:119
bool matchesInterest(const Interest &other) const
Check if Interest matches other interest.
Definition: interest.cpp:291
const Name & getName() const
Get name.
Definition: data.hpp:121
bool empty() const
Definition: exclude.hpp:322
Interest & setInterestLifetime(time::milliseconds interestLifetime)
Set Interest&#39;s lifetime.
Definition: interest.cpp:332
const Block & getInfo() const
Get SignatureInfo as wire format.
Definition: signature.hpp:77
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:251
represents a list of Delegations
Interest & setForwardingHint(const DelegationList &value)
Definition: interest.cpp:343
const KeyLocator & getPublisherPublicKeyLocator() const
Definition: interest.hpp:276
const time::milliseconds DEFAULT_INTEREST_LIFETIME
default value for InterestLifetime
Definition: interest.hpp:38
element_const_iterator elements_end() const
Equivalent to elements().end()
Definition: block.hpp:363
time::milliseconds getInterestLifetime() const
Definition: interest.hpp:183
const Name & getFullName() const
Get full name including implicit digest.
Definition: data.cpp:148
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition: name.cpp:164
Represents a Data packet.
Definition: data.hpp:35
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:164
EncodingImpl< EncoderTag > EncodingBuffer
size_t wireEncode(EncodingImpl< TAG > &encoder, uint32_t type=tlv::ForwardingHint) const
encode into wire format
EncodingImpl< EstimatorTag > EncodingEstimator
bool isImplicitSha256Digest() const
Check if the component is ImplicitSha256DigestComponent.
Holds SignatureInfo and SignatureValue in a Data packet.
Definition: signature.hpp:37
bool hasNonce() const
Check if Nonce set.
Definition: interest.hpp:155