blob: d53b9496f75a6b0725b21bc3c133319109f2dd44 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompson47eecfc2013-07-07 22:56:46 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * Based on code originally written by Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompsonb7f95562013-07-03 18:36:42 -070022 */
23
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080024#include "interest.hpp"
Alexander Afanasyeve9fdb802014-02-05 17:36:51 -080025#include "util/random.hpp"
Junxiao Shi42c23622014-07-03 00:55:11 -070026#include "util/crypto.hpp"
Junxiao Shic2b8d242014-11-04 08:35:29 -070027#include "util/concepts.hpp"
Junxiao Shiaf8eeea2014-03-31 20:10:56 -070028#include "data.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080029
Jeff Thompsonb7f95562013-07-03 18:36:42 -070030namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080031
Junxiao Shic2b8d242014-11-04 08:35:29 -070032BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
33BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
34BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
35static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
36 "Interest::Error must inherit from tlv::Error");
37
Junxiao Shi2af905b2014-11-27 13:10:54 -070038Interest::Interest()
39 : m_scope(-1)
40 , m_interestLifetime(time::milliseconds::min())
41{
42}
43
44Interest::Interest(const Name& name)
45 : m_name(name)
46 , m_scope(-1)
47 , m_interestLifetime(time::milliseconds::min())
48{
49}
50
51Interest::Interest(const Name& name, const time::milliseconds& interestLifetime)
52 : m_name(name)
53 , m_scope(-1)
54 , m_interestLifetime(interestLifetime)
55{
56}
57
58Interest::Interest(const Name& name,
59 const Selectors& selectors,
60 int scope,
61 const time::milliseconds& interestLifetime,
62 uint32_t nonce)
63 : m_name(name)
64 , m_selectors(selectors)
65 , m_scope(scope)
66 , m_interestLifetime(interestLifetime)
67{
68 if (nonce > 0) {
69 setNonce(nonce);
70 }
71}
72
73Interest::Interest(const Block& wire)
74{
75 wireDecode(wire);
76}
77
Alexander Afanasyeve881e932014-06-08 14:47:03 +030078uint32_t
Alexander Afanasyev840139f2013-12-28 15:02:50 -080079Interest::getNonce() const
80{
Alexander Afanasyeve881e932014-06-08 14:47:03 +030081 if (!m_nonce.hasWire())
82 const_cast<Interest*>(this)->setNonce(random::generateWord32());
Alexander Afanasyev840139f2013-12-28 15:02:50 -080083
Alexander Afanasyeve881e932014-06-08 14:47:03 +030084 if (m_nonce.value_size() == sizeof(uint32_t))
85 return *reinterpret_cast<const uint32_t*>(m_nonce.value());
86 else {
87 // for compatibility reasons. Should be removed eventually
88 return readNonNegativeInteger(m_nonce);
89 }
Alexander Afanasyev840139f2013-12-28 15:02:50 -080090}
91
Alexander Afanasyeve881e932014-06-08 14:47:03 +030092Interest&
93Interest::setNonce(uint32_t nonce)
94{
95 if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) {
96 std::memcpy(const_cast<uint8_t*>(m_nonce.value()), &nonce, sizeof(nonce));
97 }
98 else {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060099 m_nonce = dataBlock(tlv::Nonce,
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300100 reinterpret_cast<const uint8_t*>(&nonce),
101 sizeof(nonce));
102 m_wire.reset();
103 }
104 return *this;
105}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800106
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700107void
108Interest::refreshNonce()
109{
110 if (!hasNonce())
111 return;
112
113 uint32_t oldNonce = getNonce();
114 uint32_t newNonce = oldNonce;
115 while (newNonce == oldNonce)
116 newNonce = random::generateWord32();
117
118 setNonce(newNonce);
119}
120
Alexander Afanasyev84681982014-01-03 13:26:09 -0800121bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700122Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -0700123{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700124 if (name.size() < m_name.size())
125 return false;
126
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800127 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800128 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700129
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800130 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700131 // name must include implicit digest
132 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800133 return false;
134
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800135 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700136 // name must include implicit digest
137 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800138 return false;
139
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700140 if (!getExclude().empty() &&
141 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800142 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800143 return false;
144
145 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700146}
147
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700148bool
149Interest::matchesData(const Data& data) const
150{
Junxiao Shi42c23622014-07-03 00:55:11 -0700151 size_t interestNameLength = m_name.size();
152 const Name& dataName = data.getName();
153 size_t fullNameLength = dataName.size() + 1;
154
155 // check MinSuffixComponents
156 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
157 size_t minSuffixComponents = hasMinSuffixComponents ?
158 static_cast<size_t>(getMinSuffixComponents()) : 0;
159 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700160 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700161
162 // check MaxSuffixComponents
163 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
164 if (hasMaxSuffixComponents &&
165 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
166 return false;
167
168 // check prefix
169 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800170 if (m_name.get(-1).isImplicitSha256Digest()) {
171 if (m_name != data.getFullName())
Junxiao Shi42c23622014-07-03 00:55:11 -0700172 return false;
173 }
174 else {
175 // Interest Name is same length as Data full Name, but last component isn't digest
176 // so there's no possibility of matching
177 return false;
178 }
179 }
180 else {
181 // Interest Name is a strict prefix of Data full Name
182 if (!m_name.isPrefixOf(dataName))
183 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700184 }
185
Junxiao Shi42c23622014-07-03 00:55:11 -0700186 // check Exclude
187 // Exclude won't be violated if Interest Name is same as Data full Name
188 if (!getExclude().empty() && fullNameLength > interestNameLength) {
189 if (interestNameLength == fullNameLength - 1) {
190 // component to exclude is the digest
191 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
192 return false;
193 // There's opportunity to inspect the Exclude filter and determine whether
194 // the digest would make a difference.
Junxiao Shi08d07082014-12-03 11:31:44 -0700195 // eg. "<NameComponent>AA</NameComponent><Any/>" doesn't exclude any digest -
196 // fullName not needed;
197 // "<Any/><NameComponent>AA</NameComponent>" and
198 // "<Any/><ImplicitSha256DigestComponent>ffffffffffffffffffffffffffffffff
199 // </ImplicitSha256DigestComponent>"
200 // excludes all digests - fullName not needed;
201 // "<Any/><ImplicitSha256DigestComponent>80000000000000000000000000000000
202 // </ImplicitSha256DigestComponent>"
203 // excludes some digests - fullName required
Junxiao Shi42c23622014-07-03 00:55:11 -0700204 // But Interests that contain the exact Data Name before digest and also
205 // contain Exclude filter is too rare to optimize for, so we request
206 // fullName no mater what's in the Exclude filter.
207 }
208 else {
209 // component to exclude is not the digest
210 if (getExclude().isExcluded(dataName.get(interestNameLength)))
211 return false;
212 }
213 }
214
215 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700216 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
217 if (!publisherPublicKeyLocator.empty()) {
218 const Signature& signature = data.getSignature();
219 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600220 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700221 if (it == signatureInfo.elements_end()) {
222 return false;
223 }
224 if (publisherPublicKeyLocator.wireEncode() != *it) {
225 return false;
226 }
227 }
228
229 return true;
230}
231
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700232template<bool T>
233size_t
234Interest::wireEncode(EncodingImpl<T>& block) const
235{
236 size_t totalLength = 0;
237
238 // Interest ::= INTEREST-TYPE TLV-LENGTH
239 // Name
240 // Selectors?
241 // Nonce
242 // Scope?
243 // InterestLifetime?
244
245 // (reverse encoding)
246
247 // InterestLifetime
248 if (getInterestLifetime() >= time::milliseconds::zero() &&
249 getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
250 {
251 totalLength += prependNonNegativeIntegerBlock(block,
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600252 tlv::InterestLifetime,
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700253 getInterestLifetime().count());
254 }
255
256 // Scope
257 if (getScope() >= 0)
258 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600259 totalLength += prependNonNegativeIntegerBlock(block, tlv::Scope, getScope());
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700260 }
261
262 // Nonce
263 getNonce(); // to ensure that Nonce is properly set
264 totalLength += block.prependBlock(m_nonce);
265
266 // Selectors
267 if (hasSelectors())
268 {
269 totalLength += getSelectors().wireEncode(block);
270 }
271
272 // Name
273 totalLength += getName().wireEncode(block);
274
275 totalLength += block.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600276 totalLength += block.prependVarNumber(tlv::Interest);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700277 return totalLength;
278}
279
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700280template size_t
281Interest::wireEncode<true>(EncodingImpl<true>& block) const;
282
283template size_t
284Interest::wireEncode<false>(EncodingImpl<false>& block) const;
285
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700286const Block&
287Interest::wireEncode() const
288{
289 if (m_wire.hasWire())
290 return m_wire;
291
292 EncodingEstimator estimator;
293 size_t estimatedSize = wireEncode(estimator);
294
295 EncodingBuffer buffer(estimatedSize, 0);
296 wireEncode(buffer);
297
298 // to ensure that Nonce block points to the right memory location
299 const_cast<Interest*>(this)->wireDecode(buffer.block());
300
301 return m_wire;
302}
303
304void
305Interest::wireDecode(const Block& wire)
306{
307 m_wire = wire;
308 m_wire.parse();
309
310 // Interest ::= INTEREST-TYPE TLV-LENGTH
311 // Name
312 // Selectors?
313 // Nonce
314 // Scope?
315 // InterestLifetime?
316
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600317 if (m_wire.type() != tlv::Interest)
Junxiao Shic2b8d242014-11-04 08:35:29 -0700318 throw Error("Unexpected TLV number when decoding Interest");
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700319
320 // Name
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600321 m_name.wireDecode(m_wire.get(tlv::Name));
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700322
323 // Selectors
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600324 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700325 if (val != m_wire.elements_end())
326 {
327 m_selectors.wireDecode(*val);
328 }
329 else
330 m_selectors = Selectors();
331
332 // Nonce
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600333 m_nonce = m_wire.get(tlv::Nonce);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700334
335 // Scope
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600336 val = m_wire.find(tlv::Scope);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700337 if (val != m_wire.elements_end())
338 {
339 m_scope = readNonNegativeInteger(*val);
340 }
341 else
342 m_scope = -1;
343
344 // InterestLifetime
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600345 val = m_wire.find(tlv::InterestLifetime);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700346 if (val != m_wire.elements_end())
347 {
348 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
349 }
350 else
351 {
352 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
353 }
354}
355
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700356std::ostream&
357operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700358{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800359 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700360
Alexander Afanasyev84681982014-01-03 13:26:09 -0800361 char delim = '?';
362
363 if (interest.getMinSuffixComponents() >= 0) {
364 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
365 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700366 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800367 if (interest.getMaxSuffixComponents() >= 0) {
368 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
369 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700370 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800371 if (interest.getChildSelector() >= 0) {
372 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
373 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800374 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800375 if (interest.getMustBeFresh()) {
376 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
377 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800378 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800379 if (interest.getScope() >= 0) {
380 os << delim << "ndn.Scope=" << interest.getScope();
381 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800382 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700383 if (interest.getInterestLifetime() >= time::milliseconds::zero()
384 && interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700385 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800386 delim = '&';
387 }
388
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300389 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800390 os << delim << "ndn.Nonce=" << interest.getNonce();
391 delim = '&';
392 }
393 if (!interest.getExclude().empty()) {
394 os << delim << "ndn.Exclude=" << interest.getExclude();
395 delim = '&';
396 }
397
398 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800399}
400
Junxiao Shi08d07082014-12-03 11:31:44 -0700401} // namespace ndn