blob: 0ae085213dddea7787790460c52da3e96a6f88aa [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 Afanasyev74633892015-02-08 18:08:46 -08003 * Copyright (c) 2013-2015 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.
Jeff Thompsonb7f95562013-07-03 18:36:42 -070020 */
21
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080022#include "interest.hpp"
Alexander Afanasyeve9fdb802014-02-05 17:36:51 -080023#include "util/random.hpp"
Junxiao Shi42c23622014-07-03 00:55:11 -070024#include "util/crypto.hpp"
Junxiao Shic2b8d242014-11-04 08:35:29 -070025#include "util/concepts.hpp"
Junxiao Shiaf8eeea2014-03-31 20:10:56 -070026#include "data.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080027
Jeff Thompsonb7f95562013-07-03 18:36:42 -070028namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080029
Junxiao Shic2b8d242014-11-04 08:35:29 -070030BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
31BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
32BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
33static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
34 "Interest::Error must inherit from tlv::Error");
35
Junxiao Shi2af905b2014-11-27 13:10:54 -070036Interest::Interest()
37 : m_scope(-1)
38 , m_interestLifetime(time::milliseconds::min())
39{
40}
41
42Interest::Interest(const Name& name)
43 : m_name(name)
44 , m_scope(-1)
45 , m_interestLifetime(time::milliseconds::min())
46{
47}
48
49Interest::Interest(const Name& name, const time::milliseconds& interestLifetime)
50 : m_name(name)
51 , m_scope(-1)
52 , m_interestLifetime(interestLifetime)
53{
54}
55
56Interest::Interest(const Name& name,
57 const Selectors& selectors,
58 int scope,
59 const time::milliseconds& interestLifetime,
60 uint32_t nonce)
61 : m_name(name)
62 , m_selectors(selectors)
63 , m_scope(scope)
64 , m_interestLifetime(interestLifetime)
65{
66 if (nonce > 0) {
67 setNonce(nonce);
68 }
69}
70
71Interest::Interest(const Block& wire)
72{
73 wireDecode(wire);
74}
75
Alexander Afanasyeve881e932014-06-08 14:47:03 +030076uint32_t
Alexander Afanasyev840139f2013-12-28 15:02:50 -080077Interest::getNonce() const
78{
Alexander Afanasyeve881e932014-06-08 14:47:03 +030079 if (!m_nonce.hasWire())
80 const_cast<Interest*>(this)->setNonce(random::generateWord32());
Alexander Afanasyev840139f2013-12-28 15:02:50 -080081
Alexander Afanasyeve881e932014-06-08 14:47:03 +030082 if (m_nonce.value_size() == sizeof(uint32_t))
83 return *reinterpret_cast<const uint32_t*>(m_nonce.value());
84 else {
85 // for compatibility reasons. Should be removed eventually
86 return readNonNegativeInteger(m_nonce);
87 }
Alexander Afanasyev840139f2013-12-28 15:02:50 -080088}
89
Alexander Afanasyeve881e932014-06-08 14:47:03 +030090Interest&
91Interest::setNonce(uint32_t nonce)
92{
93 if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) {
94 std::memcpy(const_cast<uint8_t*>(m_nonce.value()), &nonce, sizeof(nonce));
95 }
96 else {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060097 m_nonce = dataBlock(tlv::Nonce,
Alexander Afanasyeve881e932014-06-08 14:47:03 +030098 reinterpret_cast<const uint8_t*>(&nonce),
99 sizeof(nonce));
100 m_wire.reset();
101 }
102 return *this;
103}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800104
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700105void
106Interest::refreshNonce()
107{
108 if (!hasNonce())
109 return;
110
111 uint32_t oldNonce = getNonce();
112 uint32_t newNonce = oldNonce;
113 while (newNonce == oldNonce)
114 newNonce = random::generateWord32();
115
116 setNonce(newNonce);
117}
118
Alexander Afanasyev84681982014-01-03 13:26:09 -0800119bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700120Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -0700121{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700122 if (name.size() < m_name.size())
123 return false;
124
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800125 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800126 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700127
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800128 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700129 // name must include implicit digest
130 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800131 return false;
132
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800133 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700134 // name must include implicit digest
135 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800136 return false;
137
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700138 if (!getExclude().empty() &&
139 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800140 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800141 return false;
142
143 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700144}
145
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700146bool
147Interest::matchesData(const Data& data) const
148{
Junxiao Shi42c23622014-07-03 00:55:11 -0700149 size_t interestNameLength = m_name.size();
150 const Name& dataName = data.getName();
151 size_t fullNameLength = dataName.size() + 1;
152
153 // check MinSuffixComponents
154 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
155 size_t minSuffixComponents = hasMinSuffixComponents ?
156 static_cast<size_t>(getMinSuffixComponents()) : 0;
157 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700158 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700159
160 // check MaxSuffixComponents
161 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
162 if (hasMaxSuffixComponents &&
163 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
164 return false;
165
166 // check prefix
167 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800168 if (m_name.get(-1).isImplicitSha256Digest()) {
169 if (m_name != data.getFullName())
Junxiao Shi42c23622014-07-03 00:55:11 -0700170 return false;
171 }
172 else {
173 // Interest Name is same length as Data full Name, but last component isn't digest
174 // so there's no possibility of matching
175 return false;
176 }
177 }
178 else {
179 // Interest Name is a strict prefix of Data full Name
180 if (!m_name.isPrefixOf(dataName))
181 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700182 }
183
Junxiao Shi42c23622014-07-03 00:55:11 -0700184 // check Exclude
185 // Exclude won't be violated if Interest Name is same as Data full Name
186 if (!getExclude().empty() && fullNameLength > interestNameLength) {
187 if (interestNameLength == fullNameLength - 1) {
188 // component to exclude is the digest
189 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
190 return false;
191 // There's opportunity to inspect the Exclude filter and determine whether
192 // the digest would make a difference.
Junxiao Shi08d07082014-12-03 11:31:44 -0700193 // eg. "<NameComponent>AA</NameComponent><Any/>" doesn't exclude any digest -
194 // fullName not needed;
195 // "<Any/><NameComponent>AA</NameComponent>" and
196 // "<Any/><ImplicitSha256DigestComponent>ffffffffffffffffffffffffffffffff
197 // </ImplicitSha256DigestComponent>"
198 // excludes all digests - fullName not needed;
199 // "<Any/><ImplicitSha256DigestComponent>80000000000000000000000000000000
200 // </ImplicitSha256DigestComponent>"
201 // excludes some digests - fullName required
Junxiao Shi42c23622014-07-03 00:55:11 -0700202 // But Interests that contain the exact Data Name before digest and also
203 // contain Exclude filter is too rare to optimize for, so we request
204 // fullName no mater what's in the Exclude filter.
205 }
206 else {
207 // component to exclude is not the digest
208 if (getExclude().isExcluded(dataName.get(interestNameLength)))
209 return false;
210 }
211 }
212
213 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700214 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
215 if (!publisherPublicKeyLocator.empty()) {
216 const Signature& signature = data.getSignature();
217 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600218 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700219 if (it == signatureInfo.elements_end()) {
220 return false;
221 }
222 if (publisherPublicKeyLocator.wireEncode() != *it) {
223 return false;
224 }
225 }
226
227 return true;
228}
229
Alexander Afanasyev74633892015-02-08 18:08:46 -0800230template<encoding::Tag TAG>
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700231size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800232Interest::wireEncode(EncodingImpl<TAG>& block) const
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700233{
234 size_t totalLength = 0;
235
236 // Interest ::= INTEREST-TYPE TLV-LENGTH
237 // Name
238 // Selectors?
239 // Nonce
240 // Scope?
241 // InterestLifetime?
242
243 // (reverse encoding)
244
245 // InterestLifetime
246 if (getInterestLifetime() >= time::milliseconds::zero() &&
247 getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
248 {
249 totalLength += prependNonNegativeIntegerBlock(block,
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600250 tlv::InterestLifetime,
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700251 getInterestLifetime().count());
252 }
253
254 // Scope
255 if (getScope() >= 0)
256 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600257 totalLength += prependNonNegativeIntegerBlock(block, tlv::Scope, getScope());
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700258 }
259
260 // Nonce
261 getNonce(); // to ensure that Nonce is properly set
262 totalLength += block.prependBlock(m_nonce);
263
264 // Selectors
265 if (hasSelectors())
266 {
267 totalLength += getSelectors().wireEncode(block);
268 }
269
270 // Name
271 totalLength += getName().wireEncode(block);
272
273 totalLength += block.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600274 totalLength += block.prependVarNumber(tlv::Interest);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700275 return totalLength;
276}
277
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700278template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800279Interest::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700280
281template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800282Interest::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700283
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700284const Block&
285Interest::wireEncode() const
286{
287 if (m_wire.hasWire())
288 return m_wire;
289
290 EncodingEstimator estimator;
291 size_t estimatedSize = wireEncode(estimator);
292
293 EncodingBuffer buffer(estimatedSize, 0);
294 wireEncode(buffer);
295
296 // to ensure that Nonce block points to the right memory location
297 const_cast<Interest*>(this)->wireDecode(buffer.block());
298
299 return m_wire;
300}
301
302void
303Interest::wireDecode(const Block& wire)
304{
305 m_wire = wire;
306 m_wire.parse();
307
308 // Interest ::= INTEREST-TYPE TLV-LENGTH
309 // Name
310 // Selectors?
311 // Nonce
312 // Scope?
313 // InterestLifetime?
314
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600315 if (m_wire.type() != tlv::Interest)
Junxiao Shic2b8d242014-11-04 08:35:29 -0700316 throw Error("Unexpected TLV number when decoding Interest");
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700317
318 // Name
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600319 m_name.wireDecode(m_wire.get(tlv::Name));
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700320
321 // Selectors
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600322 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700323 if (val != m_wire.elements_end())
324 {
325 m_selectors.wireDecode(*val);
326 }
327 else
328 m_selectors = Selectors();
329
330 // Nonce
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600331 m_nonce = m_wire.get(tlv::Nonce);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700332
333 // Scope
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600334 val = m_wire.find(tlv::Scope);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700335 if (val != m_wire.elements_end())
336 {
337 m_scope = readNonNegativeInteger(*val);
338 }
339 else
340 m_scope = -1;
341
342 // InterestLifetime
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600343 val = m_wire.find(tlv::InterestLifetime);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700344 if (val != m_wire.elements_end())
345 {
346 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
347 }
348 else
349 {
350 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
351 }
352}
353
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700354std::ostream&
355operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700356{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800357 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700358
Alexander Afanasyev84681982014-01-03 13:26:09 -0800359 char delim = '?';
360
361 if (interest.getMinSuffixComponents() >= 0) {
362 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
363 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700364 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800365 if (interest.getMaxSuffixComponents() >= 0) {
366 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
367 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700368 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800369 if (interest.getChildSelector() >= 0) {
370 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
371 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800372 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800373 if (interest.getMustBeFresh()) {
374 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
375 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800376 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800377 if (interest.getScope() >= 0) {
378 os << delim << "ndn.Scope=" << interest.getScope();
379 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800380 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700381 if (interest.getInterestLifetime() >= time::milliseconds::zero()
382 && interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700383 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800384 delim = '&';
385 }
386
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300387 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800388 os << delim << "ndn.Nonce=" << interest.getNonce();
389 delim = '&';
390 }
391 if (!interest.getExclude().empty()) {
392 os << delim << "ndn.Exclude=" << interest.getExclude();
393 delim = '&';
394 }
395
396 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800397}
398
Junxiao Shi08d07082014-12-03 11:31:44 -0700399} // namespace ndn