blob: 26b564efd5500f88c20bd1695a2705da41172a3e [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi899277a2017-07-07 22:12:12 +00002/*
Alexander Afanasyev1013fd02017-01-03 13:19:03 -08003 * Copyright (c) 2013-2017 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 Shiaf8eeea2014-03-31 20:10:56 -070024#include "data.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080025
Davide Pesaventoe1789892017-02-26 15:50:52 -050026#include <cstring>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040027#include <sstream>
Davide Pesaventoe1789892017-02-26 15:50:52 -050028
Jeff Thompsonb7f95562013-07-03 18:36:42 -070029namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080030
Junxiao Shic2b8d242014-11-04 08:35:29 -070031BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
32BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070033BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Interest>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070034BOOST_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 Shi899277a2017-07-07 22:12:12 +000038Interest::Interest(const Name& name, time::milliseconds interestLifetime)
Junxiao Shi2af905b2014-11-27 13:10:54 -070039 : m_name(name)
Junxiao Shi2af905b2014-11-27 13:10:54 -070040 , m_interestLifetime(interestLifetime)
41{
Junxiao Shi899277a2017-07-07 22:12:12 +000042 if (interestLifetime < time::milliseconds::zero()) {
43 BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
44 }
Junxiao Shi2af905b2014-11-27 13:10:54 -070045}
46
Junxiao Shi2af905b2014-11-27 13:10:54 -070047Interest::Interest(const Block& wire)
48{
49 wireDecode(wire);
50}
51
Junxiao Shi899277a2017-07-07 22:12:12 +000052// ---- encode and decode ----
Alexander Afanasyev840139f2013-12-28 15:02:50 -080053
Junxiao Shi899277a2017-07-07 22:12:12 +000054template<encoding::Tag TAG>
55size_t
56Interest::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?
Junxiao Shi9c154cb2017-07-07 22:14:54 +000065 // ForwardingHint?
Junxiao Shi899277a2017-07-07 22:12:12 +000066
67 // (reverse encoding)
68
Junxiao Shi9c154cb2017-07-07 22:14:54 +000069 // ForwardingHint
70 if (m_forwardingHint.size() > 0) {
71 totalLength += m_forwardingHint.wireEncode(encoder);
72 }
73
Junxiao Shi899277a2017-07-07 22:12:12 +000074 // InterestLifetime
75 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
76 totalLength += prependNonNegativeIntegerBlock(encoder,
77 tlv::InterestLifetime,
78 getInterestLifetime().count());
79 }
80
81 // Nonce
Junxiao Shi2dd711d2017-07-21 13:40:52 +000082 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);
Junxiao Shi899277a2017-07-07 22:12:12 +000086
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;
Alexander Afanasyev840139f2013-12-28 15:02:50 -080098}
99
Junxiao Shi899277a2017-07-07 22:12:12 +0000100template size_t
101Interest::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
102
103template size_t
104Interest::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
105
106const Block&
107Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300108{
Junxiao Shi899277a2017-07-07 22:12:12 +0000109 if (m_wire.hasWire())
110 return m_wire;
111
112 EncodingEstimator estimator;
113 size_t estimatedSize = wireEncode(estimator);
114
115 EncodingBuffer buffer(estimatedSize, 0);
116 wireEncode(buffer);
117
Junxiao Shi899277a2017-07-07 22:12:12 +0000118 const_cast<Interest*>(this)->wireDecode(buffer.block());
Junxiao Shi899277a2017-07-07 22:12:12 +0000119 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300120}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800121
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700122void
Junxiao Shi899277a2017-07-07 22:12:12 +0000123Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700124{
Junxiao Shi899277a2017-07-07 22:12:12 +0000125 m_wire = wire;
126 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700127
Junxiao Shi899277a2017-07-07 22:12:12 +0000128 if (m_wire.type() != tlv::Interest)
129 BOOST_THROW_EXCEPTION(Error("Unexpected TLV number when decoding Interest"));
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700130
Junxiao Shi899277a2017-07-07 22:12:12 +0000131 // Name
132 m_name.wireDecode(m_wire.get(tlv::Name));
133
134 // Selectors
135 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
136 if (val != m_wire.elements_end()) {
137 m_selectors.wireDecode(*val);
138 }
139 else
140 m_selectors = Selectors();
141
142 // Nonce
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000143 val = m_wire.find(tlv::Nonce);
144 if (val == m_wire.elements_end()) {
145 BOOST_THROW_EXCEPTION(Error("Nonce element is missing"));
146 }
147 uint32_t nonce = 0;
148 if (val->value_size() != sizeof(nonce)) {
149 BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
150 }
151 std::memcpy(&nonce, val->value(), sizeof(nonce));
152 m_nonce = nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000153
154 // InterestLifetime
155 val = m_wire.find(tlv::InterestLifetime);
156 if (val != m_wire.elements_end()) {
157 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
158 }
159 else {
160 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
161 }
162
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000163 // ForwardingHint
164 val = m_wire.find(tlv::ForwardingHint);
165 if (val != m_wire.elements_end()) {
166 m_forwardingHint.wireDecode(*val, false);
167 }
168 else {
169 m_forwardingHint = DelegationList();
170 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700171}
172
Davide Pesaventoa84f4642017-08-23 16:14:51 -0400173std::string
174Interest::toUri() const
175{
176 std::ostringstream os;
177 os << *this;
178 return os.str();
179}
180
Junxiao Shi899277a2017-07-07 22:12:12 +0000181// ---- matching ----
182
Alexander Afanasyev84681982014-01-03 13:26:09 -0800183bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700184Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -0700185{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700186 if (name.size() < m_name.size())
187 return false;
188
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800189 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800190 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700191
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800192 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700193 // name must include implicit digest
194 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800195 return false;
196
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800197 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700198 // name must include implicit digest
199 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800200 return false;
201
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700202 if (!getExclude().empty() &&
203 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800204 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800205 return false;
206
207 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700208}
209
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700210bool
211Interest::matchesData(const Data& data) const
212{
Junxiao Shi42c23622014-07-03 00:55:11 -0700213 size_t interestNameLength = m_name.size();
214 const Name& dataName = data.getName();
215 size_t fullNameLength = dataName.size() + 1;
216
217 // check MinSuffixComponents
218 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
219 size_t minSuffixComponents = hasMinSuffixComponents ?
220 static_cast<size_t>(getMinSuffixComponents()) : 0;
221 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700222 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700223
224 // check MaxSuffixComponents
225 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
226 if (hasMaxSuffixComponents &&
227 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
228 return false;
229
230 // check prefix
231 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800232 if (m_name.get(-1).isImplicitSha256Digest()) {
233 if (m_name != data.getFullName())
Junxiao Shi42c23622014-07-03 00:55:11 -0700234 return false;
235 }
236 else {
237 // Interest Name is same length as Data full Name, but last component isn't digest
238 // so there's no possibility of matching
239 return false;
240 }
241 }
242 else {
243 // Interest Name is a strict prefix of Data full Name
244 if (!m_name.isPrefixOf(dataName))
245 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700246 }
247
Junxiao Shi42c23622014-07-03 00:55:11 -0700248 // check Exclude
249 // Exclude won't be violated if Interest Name is same as Data full Name
250 if (!getExclude().empty() && fullNameLength > interestNameLength) {
251 if (interestNameLength == fullNameLength - 1) {
252 // component to exclude is the digest
253 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
254 return false;
255 // There's opportunity to inspect the Exclude filter and determine whether
256 // the digest would make a difference.
Junxiao Shi08d07082014-12-03 11:31:44 -0700257 // eg. "<NameComponent>AA</NameComponent><Any/>" doesn't exclude any digest -
258 // fullName not needed;
259 // "<Any/><NameComponent>AA</NameComponent>" and
260 // "<Any/><ImplicitSha256DigestComponent>ffffffffffffffffffffffffffffffff
261 // </ImplicitSha256DigestComponent>"
262 // excludes all digests - fullName not needed;
263 // "<Any/><ImplicitSha256DigestComponent>80000000000000000000000000000000
264 // </ImplicitSha256DigestComponent>"
265 // excludes some digests - fullName required
Junxiao Shi42c23622014-07-03 00:55:11 -0700266 // But Interests that contain the exact Data Name before digest and also
267 // contain Exclude filter is too rare to optimize for, so we request
Junxiao Shi68247832017-07-03 22:06:49 +0000268 // fullName no matter what's in the Exclude filter.
Junxiao Shi42c23622014-07-03 00:55:11 -0700269 }
270 else {
271 // component to exclude is not the digest
272 if (getExclude().isExcluded(dataName.get(interestNameLength)))
273 return false;
274 }
275 }
276
277 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700278 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
279 if (!publisherPublicKeyLocator.empty()) {
280 const Signature& signature = data.getSignature();
281 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600282 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700283 if (it == signatureInfo.elements_end()) {
284 return false;
285 }
286 if (publisherPublicKeyLocator.wireEncode() != *it) {
287 return false;
288 }
289 }
290
291 return true;
292}
293
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800294bool
295Interest::matchesInterest(const Interest& other) const
296{
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000297 /// @todo #3162 match ForwardingHint field
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800298 return (this->getName() == other.getName() &&
299 this->getSelectors() == other.getSelectors());
300}
301
Junxiao Shi899277a2017-07-07 22:12:12 +0000302// ---- field accessors ----
303
304uint32_t
305Interest::getNonce() const
306{
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000307 if (!m_nonce) {
308 m_nonce = random::generateWord32();
Junxiao Shic2ac5d22017-07-17 22:18:31 +0000309 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000310 return *m_nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000311}
312
313Interest&
314Interest::setNonce(uint32_t nonce)
315{
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000316 m_nonce = nonce;
317 m_wire.reset();
Junxiao Shi899277a2017-07-07 22:12:12 +0000318 return *this;
319}
320
321void
322Interest::refreshNonce()
323{
324 if (!hasNonce())
325 return;
326
327 uint32_t oldNonce = getNonce();
328 uint32_t newNonce = oldNonce;
329 while (newNonce == oldNonce)
330 newNonce = random::generateWord32();
331
332 setNonce(newNonce);
333}
334
Eric Newberryb555b002017-05-17 00:30:44 -0700335Interest&
336Interest::setInterestLifetime(time::milliseconds interestLifetime)
337{
338 if (interestLifetime < time::milliseconds::zero()) {
339 BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
340 }
341 m_interestLifetime = interestLifetime;
342 m_wire.reset();
343 return *this;
344}
345
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000346Interest&
347Interest::setForwardingHint(const DelegationList& value)
348{
349 m_forwardingHint = value;
350 m_wire.reset();
351 return *this;
352}
353
Junxiao Shi899277a2017-07-07 22:12:12 +0000354// ---- operators ----
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 }
Eric Newberryb555b002017-05-17 00:30:44 -0700371 if (interest.getChildSelector() != DEFAULT_CHILD_SELECTOR) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800372 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 }
Eric Newberryb555b002017-05-17 00:30:44 -0700379 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700380 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800381 delim = '&';
382 }
383
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300384 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800385 os << delim << "ndn.Nonce=" << interest.getNonce();
386 delim = '&';
387 }
388 if (!interest.getExclude().empty()) {
389 os << delim << "ndn.Exclude=" << interest.getExclude();
390 delim = '&';
391 }
392
393 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800394}
395
Junxiao Shi08d07082014-12-03 11:31:44 -0700396} // namespace ndn