blob: 8bf60e39185b16f149bcd5826631ba097ef6a1f5 [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 Shiaf8eeea2014-03-31 20:10:56 -070027#include "data.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080028
Jeff Thompsonb7f95562013-07-03 18:36:42 -070029namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080030
Alexander Afanasyeve881e932014-06-08 14:47:03 +030031uint32_t
Alexander Afanasyev840139f2013-12-28 15:02:50 -080032Interest::getNonce() const
33{
Alexander Afanasyeve881e932014-06-08 14:47:03 +030034 if (!m_nonce.hasWire())
35 const_cast<Interest*>(this)->setNonce(random::generateWord32());
Alexander Afanasyev840139f2013-12-28 15:02:50 -080036
Alexander Afanasyeve881e932014-06-08 14:47:03 +030037 if (m_nonce.value_size() == sizeof(uint32_t))
38 return *reinterpret_cast<const uint32_t*>(m_nonce.value());
39 else {
40 // for compatibility reasons. Should be removed eventually
41 return readNonNegativeInteger(m_nonce);
42 }
Alexander Afanasyev840139f2013-12-28 15:02:50 -080043}
44
Alexander Afanasyeve881e932014-06-08 14:47:03 +030045Interest&
46Interest::setNonce(uint32_t nonce)
47{
48 if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) {
49 std::memcpy(const_cast<uint8_t*>(m_nonce.value()), &nonce, sizeof(nonce));
50 }
51 else {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060052 m_nonce = dataBlock(tlv::Nonce,
Alexander Afanasyeve881e932014-06-08 14:47:03 +030053 reinterpret_cast<const uint8_t*>(&nonce),
54 sizeof(nonce));
55 m_wire.reset();
56 }
57 return *this;
58}
Alexander Afanasyev840139f2013-12-28 15:02:50 -080059
Alexander Afanasyevc3932172014-07-10 18:53:56 -070060void
61Interest::refreshNonce()
62{
63 if (!hasNonce())
64 return;
65
66 uint32_t oldNonce = getNonce();
67 uint32_t newNonce = oldNonce;
68 while (newNonce == oldNonce)
69 newNonce = random::generateWord32();
70
71 setNonce(newNonce);
72}
73
Alexander Afanasyev84681982014-01-03 13:26:09 -080074bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070075Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -070076{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070077 if (name.size() < m_name.size())
78 return false;
79
Alexander Afanasyevc348f832014-02-17 16:35:17 -080080 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -080081 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070082
Alexander Afanasyevc348f832014-02-17 16:35:17 -080083 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -070084 // name must include implicit digest
85 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -080086 return false;
87
Alexander Afanasyevc348f832014-02-17 16:35:17 -080088 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -070089 // name must include implicit digest
90 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -080091 return false;
92
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070093 if (!getExclude().empty() &&
94 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -080095 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -080096 return false;
97
98 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -070099}
100
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700101bool
102Interest::matchesData(const Data& data) const
103{
Junxiao Shi42c23622014-07-03 00:55:11 -0700104 size_t interestNameLength = m_name.size();
105 const Name& dataName = data.getName();
106 size_t fullNameLength = dataName.size() + 1;
107
108 // check MinSuffixComponents
109 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
110 size_t minSuffixComponents = hasMinSuffixComponents ?
111 static_cast<size_t>(getMinSuffixComponents()) : 0;
112 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700113 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700114
115 // check MaxSuffixComponents
116 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
117 if (hasMaxSuffixComponents &&
118 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
119 return false;
120
121 // check prefix
122 if (interestNameLength == fullNameLength) {
123 bool mightEndWithDigest = (interestNameLength > 0) &&
124 (m_name.get(-1).value_size() == crypto::SHA256_DIGEST_SIZE);
125 if (mightEndWithDigest) {
126 // Interest Name is same length as Data full Name, last component could match digest
127 if (!m_name.isPrefixOf(data.getFullName()))
128 return false;
129 }
130 else {
131 // Interest Name is same length as Data full Name, but last component isn't digest
132 // so there's no possibility of matching
133 return false;
134 }
135 }
136 else {
137 // Interest Name is a strict prefix of Data full Name
138 if (!m_name.isPrefixOf(dataName))
139 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700140 }
141
Junxiao Shi42c23622014-07-03 00:55:11 -0700142 // check Exclude
143 // Exclude won't be violated if Interest Name is same as Data full Name
144 if (!getExclude().empty() && fullNameLength > interestNameLength) {
145 if (interestNameLength == fullNameLength - 1) {
146 // component to exclude is the digest
147 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
148 return false;
149 // There's opportunity to inspect the Exclude filter and determine whether
150 // the digest would make a difference.
151 // eg. "Exclude=<Any>AA" won't exclude any digest - fullName not needed
152 // "Exclude=ZZ<Any>" excludes all digests - fullName not needed
153 // "Exclude=<Any>80000000000000000000000000000000"
154 // excludes half of the digests - fullName required
155 // But Interests that contain the exact Data Name before digest and also
156 // contain Exclude filter is too rare to optimize for, so we request
157 // fullName no mater what's in the Exclude filter.
158 }
159 else {
160 // component to exclude is not the digest
161 if (getExclude().isExcluded(dataName.get(interestNameLength)))
162 return false;
163 }
164 }
165
166 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700167 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
168 if (!publisherPublicKeyLocator.empty()) {
169 const Signature& signature = data.getSignature();
170 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600171 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700172 if (it == signatureInfo.elements_end()) {
173 return false;
174 }
175 if (publisherPublicKeyLocator.wireEncode() != *it) {
176 return false;
177 }
178 }
179
180 return true;
181}
182
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700183template<bool T>
184size_t
185Interest::wireEncode(EncodingImpl<T>& block) const
186{
187 size_t totalLength = 0;
188
189 // Interest ::= INTEREST-TYPE TLV-LENGTH
190 // Name
191 // Selectors?
192 // Nonce
193 // Scope?
194 // InterestLifetime?
195
196 // (reverse encoding)
197
198 // InterestLifetime
199 if (getInterestLifetime() >= time::milliseconds::zero() &&
200 getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
201 {
202 totalLength += prependNonNegativeIntegerBlock(block,
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600203 tlv::InterestLifetime,
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700204 getInterestLifetime().count());
205 }
206
207 // Scope
208 if (getScope() >= 0)
209 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600210 totalLength += prependNonNegativeIntegerBlock(block, tlv::Scope, getScope());
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700211 }
212
213 // Nonce
214 getNonce(); // to ensure that Nonce is properly set
215 totalLength += block.prependBlock(m_nonce);
216
217 // Selectors
218 if (hasSelectors())
219 {
220 totalLength += getSelectors().wireEncode(block);
221 }
222
223 // Name
224 totalLength += getName().wireEncode(block);
225
226 totalLength += block.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600227 totalLength += block.prependVarNumber(tlv::Interest);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700228 return totalLength;
229}
230
231const Block&
232Interest::wireEncode() const
233{
234 if (m_wire.hasWire())
235 return m_wire;
236
237 EncodingEstimator estimator;
238 size_t estimatedSize = wireEncode(estimator);
239
240 EncodingBuffer buffer(estimatedSize, 0);
241 wireEncode(buffer);
242
243 // to ensure that Nonce block points to the right memory location
244 const_cast<Interest*>(this)->wireDecode(buffer.block());
245
246 return m_wire;
247}
248
249void
250Interest::wireDecode(const Block& wire)
251{
252 m_wire = wire;
253 m_wire.parse();
254
255 // Interest ::= INTEREST-TYPE TLV-LENGTH
256 // Name
257 // Selectors?
258 // Nonce
259 // Scope?
260 // InterestLifetime?
261
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600262 if (m_wire.type() != tlv::Interest)
263 throw tlv::Error("Unexpected TLV number when decoding Interest");
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700264
265 // Name
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600266 m_name.wireDecode(m_wire.get(tlv::Name));
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700267
268 // Selectors
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600269 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700270 if (val != m_wire.elements_end())
271 {
272 m_selectors.wireDecode(*val);
273 }
274 else
275 m_selectors = Selectors();
276
277 // Nonce
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600278 m_nonce = m_wire.get(tlv::Nonce);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700279
280 // Scope
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600281 val = m_wire.find(tlv::Scope);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700282 if (val != m_wire.elements_end())
283 {
284 m_scope = readNonNegativeInteger(*val);
285 }
286 else
287 m_scope = -1;
288
289 // InterestLifetime
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600290 val = m_wire.find(tlv::InterestLifetime);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700291 if (val != m_wire.elements_end())
292 {
293 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
294 }
295 else
296 {
297 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
298 }
299}
300
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700301std::ostream&
302operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700303{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800304 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700305
Alexander Afanasyev84681982014-01-03 13:26:09 -0800306 char delim = '?';
307
308 if (interest.getMinSuffixComponents() >= 0) {
309 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
310 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700311 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800312 if (interest.getMaxSuffixComponents() >= 0) {
313 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
314 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700315 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800316 if (interest.getChildSelector() >= 0) {
317 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
318 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800319 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800320 if (interest.getMustBeFresh()) {
321 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
322 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800323 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800324 if (interest.getScope() >= 0) {
325 os << delim << "ndn.Scope=" << interest.getScope();
326 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800327 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700328 if (interest.getInterestLifetime() >= time::milliseconds::zero()
329 && interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700330 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800331 delim = '&';
332 }
333
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300334 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800335 os << delim << "ndn.Nonce=" << interest.getNonce();
336 delim = '&';
337 }
338 if (!interest.getExclude().empty()) {
339 os << delim << "ndn.Exclude=" << interest.getExclude();
340 delim = '&';
341 }
342
343 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800344}
345
Jeff Thompsonb7f95562013-07-03 18:36:42 -0700346}