blob: eb80c4b41e80b4ea4780ff322ff5216b40860ff6 [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
Alexander Afanasyeve881e932014-06-08 14:47:03 +030038uint32_t
Alexander Afanasyev840139f2013-12-28 15:02:50 -080039Interest::getNonce() const
40{
Alexander Afanasyeve881e932014-06-08 14:47:03 +030041 if (!m_nonce.hasWire())
42 const_cast<Interest*>(this)->setNonce(random::generateWord32());
Alexander Afanasyev840139f2013-12-28 15:02:50 -080043
Alexander Afanasyeve881e932014-06-08 14:47:03 +030044 if (m_nonce.value_size() == sizeof(uint32_t))
45 return *reinterpret_cast<const uint32_t*>(m_nonce.value());
46 else {
47 // for compatibility reasons. Should be removed eventually
48 return readNonNegativeInteger(m_nonce);
49 }
Alexander Afanasyev840139f2013-12-28 15:02:50 -080050}
51
Alexander Afanasyeve881e932014-06-08 14:47:03 +030052Interest&
53Interest::setNonce(uint32_t nonce)
54{
55 if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) {
56 std::memcpy(const_cast<uint8_t*>(m_nonce.value()), &nonce, sizeof(nonce));
57 }
58 else {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060059 m_nonce = dataBlock(tlv::Nonce,
Alexander Afanasyeve881e932014-06-08 14:47:03 +030060 reinterpret_cast<const uint8_t*>(&nonce),
61 sizeof(nonce));
62 m_wire.reset();
63 }
64 return *this;
65}
Alexander Afanasyev840139f2013-12-28 15:02:50 -080066
Alexander Afanasyevc3932172014-07-10 18:53:56 -070067void
68Interest::refreshNonce()
69{
70 if (!hasNonce())
71 return;
72
73 uint32_t oldNonce = getNonce();
74 uint32_t newNonce = oldNonce;
75 while (newNonce == oldNonce)
76 newNonce = random::generateWord32();
77
78 setNonce(newNonce);
79}
80
Alexander Afanasyev84681982014-01-03 13:26:09 -080081bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070082Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -070083{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070084 if (name.size() < m_name.size())
85 return false;
86
Alexander Afanasyevc348f832014-02-17 16:35:17 -080087 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -080088 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070089
Alexander Afanasyevc348f832014-02-17 16:35:17 -080090 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -070091 // name must include implicit digest
92 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -080093 return false;
94
Alexander Afanasyevc348f832014-02-17 16:35:17 -080095 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -070096 // name must include implicit digest
97 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -080098 return false;
99
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700100 if (!getExclude().empty() &&
101 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800102 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800103 return false;
104
105 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700106}
107
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700108bool
109Interest::matchesData(const Data& data) const
110{
Junxiao Shi42c23622014-07-03 00:55:11 -0700111 size_t interestNameLength = m_name.size();
112 const Name& dataName = data.getName();
113 size_t fullNameLength = dataName.size() + 1;
114
115 // check MinSuffixComponents
116 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
117 size_t minSuffixComponents = hasMinSuffixComponents ?
118 static_cast<size_t>(getMinSuffixComponents()) : 0;
119 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700120 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700121
122 // check MaxSuffixComponents
123 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
124 if (hasMaxSuffixComponents &&
125 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
126 return false;
127
128 // check prefix
129 if (interestNameLength == fullNameLength) {
130 bool mightEndWithDigest = (interestNameLength > 0) &&
131 (m_name.get(-1).value_size() == crypto::SHA256_DIGEST_SIZE);
132 if (mightEndWithDigest) {
133 // Interest Name is same length as Data full Name, last component could match digest
134 if (!m_name.isPrefixOf(data.getFullName()))
135 return false;
136 }
137 else {
138 // Interest Name is same length as Data full Name, but last component isn't digest
139 // so there's no possibility of matching
140 return false;
141 }
142 }
143 else {
144 // Interest Name is a strict prefix of Data full Name
145 if (!m_name.isPrefixOf(dataName))
146 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700147 }
148
Junxiao Shi42c23622014-07-03 00:55:11 -0700149 // check Exclude
150 // Exclude won't be violated if Interest Name is same as Data full Name
151 if (!getExclude().empty() && fullNameLength > interestNameLength) {
152 if (interestNameLength == fullNameLength - 1) {
153 // component to exclude is the digest
154 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
155 return false;
156 // There's opportunity to inspect the Exclude filter and determine whether
157 // the digest would make a difference.
158 // eg. "Exclude=<Any>AA" won't exclude any digest - fullName not needed
159 // "Exclude=ZZ<Any>" excludes all digests - fullName not needed
160 // "Exclude=<Any>80000000000000000000000000000000"
161 // excludes half of the digests - fullName required
162 // But Interests that contain the exact Data Name before digest and also
163 // contain Exclude filter is too rare to optimize for, so we request
164 // fullName no mater what's in the Exclude filter.
165 }
166 else {
167 // component to exclude is not the digest
168 if (getExclude().isExcluded(dataName.get(interestNameLength)))
169 return false;
170 }
171 }
172
173 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700174 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
175 if (!publisherPublicKeyLocator.empty()) {
176 const Signature& signature = data.getSignature();
177 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600178 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700179 if (it == signatureInfo.elements_end()) {
180 return false;
181 }
182 if (publisherPublicKeyLocator.wireEncode() != *it) {
183 return false;
184 }
185 }
186
187 return true;
188}
189
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700190template<bool T>
191size_t
192Interest::wireEncode(EncodingImpl<T>& block) const
193{
194 size_t totalLength = 0;
195
196 // Interest ::= INTEREST-TYPE TLV-LENGTH
197 // Name
198 // Selectors?
199 // Nonce
200 // Scope?
201 // InterestLifetime?
202
203 // (reverse encoding)
204
205 // InterestLifetime
206 if (getInterestLifetime() >= time::milliseconds::zero() &&
207 getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
208 {
209 totalLength += prependNonNegativeIntegerBlock(block,
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600210 tlv::InterestLifetime,
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700211 getInterestLifetime().count());
212 }
213
214 // Scope
215 if (getScope() >= 0)
216 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600217 totalLength += prependNonNegativeIntegerBlock(block, tlv::Scope, getScope());
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700218 }
219
220 // Nonce
221 getNonce(); // to ensure that Nonce is properly set
222 totalLength += block.prependBlock(m_nonce);
223
224 // Selectors
225 if (hasSelectors())
226 {
227 totalLength += getSelectors().wireEncode(block);
228 }
229
230 // Name
231 totalLength += getName().wireEncode(block);
232
233 totalLength += block.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600234 totalLength += block.prependVarNumber(tlv::Interest);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700235 return totalLength;
236}
237
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700238template size_t
239Interest::wireEncode<true>(EncodingImpl<true>& block) const;
240
241template size_t
242Interest::wireEncode<false>(EncodingImpl<false>& block) const;
243
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700244const Block&
245Interest::wireEncode() const
246{
247 if (m_wire.hasWire())
248 return m_wire;
249
250 EncodingEstimator estimator;
251 size_t estimatedSize = wireEncode(estimator);
252
253 EncodingBuffer buffer(estimatedSize, 0);
254 wireEncode(buffer);
255
256 // to ensure that Nonce block points to the right memory location
257 const_cast<Interest*>(this)->wireDecode(buffer.block());
258
259 return m_wire;
260}
261
262void
263Interest::wireDecode(const Block& wire)
264{
265 m_wire = wire;
266 m_wire.parse();
267
268 // Interest ::= INTEREST-TYPE TLV-LENGTH
269 // Name
270 // Selectors?
271 // Nonce
272 // Scope?
273 // InterestLifetime?
274
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600275 if (m_wire.type() != tlv::Interest)
Junxiao Shic2b8d242014-11-04 08:35:29 -0700276 throw Error("Unexpected TLV number when decoding Interest");
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700277
278 // Name
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600279 m_name.wireDecode(m_wire.get(tlv::Name));
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700280
281 // Selectors
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600282 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700283 if (val != m_wire.elements_end())
284 {
285 m_selectors.wireDecode(*val);
286 }
287 else
288 m_selectors = Selectors();
289
290 // Nonce
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600291 m_nonce = m_wire.get(tlv::Nonce);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700292
293 // Scope
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600294 val = m_wire.find(tlv::Scope);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700295 if (val != m_wire.elements_end())
296 {
297 m_scope = readNonNegativeInteger(*val);
298 }
299 else
300 m_scope = -1;
301
302 // InterestLifetime
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600303 val = m_wire.find(tlv::InterestLifetime);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700304 if (val != m_wire.elements_end())
305 {
306 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
307 }
308 else
309 {
310 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
311 }
312}
313
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700314std::ostream&
315operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700316{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800317 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700318
Alexander Afanasyev84681982014-01-03 13:26:09 -0800319 char delim = '?';
320
321 if (interest.getMinSuffixComponents() >= 0) {
322 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
323 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700324 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800325 if (interest.getMaxSuffixComponents() >= 0) {
326 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
327 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700328 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800329 if (interest.getChildSelector() >= 0) {
330 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
331 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800332 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800333 if (interest.getMustBeFresh()) {
334 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
335 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800336 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800337 if (interest.getScope() >= 0) {
338 os << delim << "ndn.Scope=" << interest.getScope();
339 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800340 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700341 if (interest.getInterestLifetime() >= time::milliseconds::zero()
342 && interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700343 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800344 delim = '&';
345 }
346
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300347 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800348 os << delim << "ndn.Nonce=" << interest.getNonce();
349 delim = '&';
350 }
351 if (!interest.getExclude().empty()) {
352 os << delim << "ndn.Exclude=" << interest.getExclude();
353 delim = '&';
354 }
355
356 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800357}
358
Jeff Thompsonb7f95562013-07-03 18:36:42 -0700359}