blob: a25147b791d4909b0f656dc5c3f138c6fe97f00c [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/*
Davide Pesaventofccb2dc2019-02-09 01:02:35 -05003 * Copyright (c) 2013-2019 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
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/interest.hpp"
23#include "ndn-cxx/data.hpp"
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040024#include "ndn-cxx/encoding/buffer-stream.hpp"
25#include "ndn-cxx/security/transform/digest-filter.hpp"
26#include "ndn-cxx/security/transform/step-source.hpp"
27#include "ndn-cxx/security/transform/stream-sink.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050028#include "ndn-cxx/util/random.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080029
Junxiao Shib55e5d32018-07-18 13:32:00 -060030#include <boost/scope_exit.hpp>
31
Davide Pesavento4bb06bc2019-04-06 13:59:10 -040032#ifdef NDN_CXX_HAVE_STACKTRACE
33#include <boost/stacktrace/stacktrace.hpp>
34#endif
35
Davide Pesaventoe1789892017-02-26 15:50:52 -050036#include <cstring>
Junxiao Shib55e5d32018-07-18 13:32:00 -060037#include <iostream>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040038#include <sstream>
Davide Pesaventoe1789892017-02-26 15:50:52 -050039
Jeff Thompsonb7f95562013-07-03 18:36:42 -070040namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080041
Junxiao Shic2b8d242014-11-04 08:35:29 -070042BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
43BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070044BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Interest>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070045BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
46static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
47 "Interest::Error must inherit from tlv::Error");
48
Junxiao Shib55e5d32018-07-18 13:32:00 -060049#ifdef NDN_CXX_HAVE_TESTS
50bool Interest::s_errorIfCanBePrefixUnset = true;
51#endif // NDN_CXX_HAVE_TESTS
52boost::logic::tribool Interest::s_defaultCanBePrefix = boost::logic::indeterminate;
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040053bool Interest::s_autoCheckParametersDigest = true;
Junxiao Shib55e5d32018-07-18 13:32:00 -060054
Junxiao Shi8d3f8342018-04-04 12:46:37 +000055Interest::Interest(const Name& name, time::milliseconds lifetime)
Junxiao Shi2af905b2014-11-27 13:10:54 -070056{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040057 setName(name);
58 setInterestLifetime(lifetime);
Junxiao Shib55e5d32018-07-18 13:32:00 -060059
60 if (!boost::logic::indeterminate(s_defaultCanBePrefix)) {
Davide Pesavento4bb06bc2019-04-06 13:59:10 -040061 setCanBePrefix(bool(s_defaultCanBePrefix));
Junxiao Shib55e5d32018-07-18 13:32:00 -060062 }
Junxiao Shi2af905b2014-11-27 13:10:54 -070063}
64
Junxiao Shi2af905b2014-11-27 13:10:54 -070065Interest::Interest(const Block& wire)
66{
67 wireDecode(wire);
68}
69
Junxiao Shi899277a2017-07-07 22:12:12 +000070// ---- encode and decode ----
Alexander Afanasyev840139f2013-12-28 15:02:50 -080071
Davide Pesavento4bb06bc2019-04-06 13:59:10 -040072static void
73warnOnceCanBePrefixUnset()
74{
75 static bool didWarn = false;
76 if (!didWarn) {
77 didWarn = true;
78 std::cerr << "WARNING: Interest.CanBePrefix will be set to false in the near future. "
79 << "Please declare a preferred setting via Interest::setDefaultCanBePrefix.\n";
80#ifdef NDN_CXX_HAVE_STACKTRACE
81 if (std::getenv("NDN_CXX_VERBOSE_CANBEPREFIX_UNSET_WARNING") != nullptr) {
82 std::cerr << boost::stacktrace::stacktrace(2, 64);
83 }
84#endif
85 }
86}
87
Junxiao Shi899277a2017-07-07 22:12:12 +000088template<encoding::Tag TAG>
89size_t
90Interest::wireEncode(EncodingImpl<TAG>& encoder) const
91{
Junxiao Shib55e5d32018-07-18 13:32:00 -060092 if (!m_isCanBePrefixSet) {
Davide Pesavento4bb06bc2019-04-06 13:59:10 -040093 warnOnceCanBePrefixUnset();
Junxiao Shib55e5d32018-07-18 13:32:00 -060094#ifdef NDN_CXX_HAVE_TESTS
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070095 if (s_errorIfCanBePrefixUnset) {
Davide Pesavento923ba442019-02-12 22:00:38 -050096 NDN_THROW(std::logic_error("Interest.CanBePrefix is unset"));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070097 }
Junxiao Shib55e5d32018-07-18 13:32:00 -060098#endif // NDN_CXX_HAVE_TESTS
99 }
100
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400101 if (getHopLimit() || hasApplicationParameters()) {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700102 return encode03(encoder);
103 }
104 else {
105 return encode02(encoder);
106 }
107}
108
109template<encoding::Tag TAG>
110size_t
111Interest::encode02(EncodingImpl<TAG>& encoder) const
112{
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700113 // Encode as NDN Packet Format v0.2
Junxiao Shi899277a2017-07-07 22:12:12 +0000114 // Interest ::= INTEREST-TYPE TLV-LENGTH
115 // Name
116 // Selectors?
117 // Nonce
118 // InterestLifetime?
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000119 // ForwardingHint?
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400120 // (elements are encoded in reverse order)
Junxiao Shi899277a2017-07-07 22:12:12 +0000121
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400122 size_t totalLength = 0;
Junxiao Shi899277a2017-07-07 22:12:12 +0000123
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000124 // ForwardingHint
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700125 if (getForwardingHint().size() > 0) {
126 totalLength += getForwardingHint().wireEncode(encoder);
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000127 }
128
Junxiao Shi899277a2017-07-07 22:12:12 +0000129 // InterestLifetime
130 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500131 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::InterestLifetime,
132 static_cast<uint64_t>(getInterestLifetime().count()));
Junxiao Shi899277a2017-07-07 22:12:12 +0000133 }
134
135 // Nonce
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400136 uint32_t nonce = getNonce(); // if nonce was unset, this generates a fresh nonce
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700137 totalLength += encoder.prependByteArrayBlock(tlv::Nonce, reinterpret_cast<uint8_t*>(&nonce), sizeof(nonce));
Junxiao Shi899277a2017-07-07 22:12:12 +0000138
139 // Selectors
140 if (hasSelectors()) {
141 totalLength += getSelectors().wireEncode(encoder);
142 }
143
144 // Name
145 totalLength += getName().wireEncode(encoder);
146
147 totalLength += encoder.prependVarNumber(totalLength);
148 totalLength += encoder.prependVarNumber(tlv::Interest);
149 return totalLength;
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800150}
151
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700152template<encoding::Tag TAG>
153size_t
154Interest::encode03(EncodingImpl<TAG>& encoder) const
155{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400156 // Encode as NDN Packet Format v0.3
157 // Interest = INTEREST-TYPE TLV-LENGTH
158 // Name
159 // [CanBePrefix]
160 // [MustBeFresh]
161 // [ForwardingHint]
162 // [Nonce]
163 // [InterestLifetime]
164 // [HopLimit]
165 // [ApplicationParameters [InterestSignature]]
166 // (elements are encoded in reverse order)
167
168 // sanity check of ApplicationParameters and ParametersSha256DigestComponent
169 ssize_t digestIndex = findParametersDigestComponent(getName());
170 BOOST_ASSERT(digestIndex != -2); // guaranteed by the checks in setName() and wireDecode()
171 if (digestIndex == -1) {
172 if (hasApplicationParameters())
173 NDN_THROW(Error("Interest with parameters must have a ParametersSha256DigestComponent"));
174 }
175 else if (!hasApplicationParameters()) {
176 NDN_THROW(Error("Interest without parameters must not have a ParametersSha256DigestComponent"));
177 }
178
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700179 size_t totalLength = 0;
180
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400181 // ApplicationParameters and following elements (in reverse order)
182 std::for_each(m_parameters.rbegin(), m_parameters.rend(), [&] (const Block& b) {
183 totalLength += encoder.prependBlock(b);
184 });
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700185
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400186 // HopLimit
187 if (getHopLimit()) {
188 uint8_t hopLimit = *getHopLimit();
189 totalLength += encoder.prependByteArrayBlock(tlv::HopLimit, &hopLimit, sizeof(hopLimit));
190 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700191
192 // InterestLifetime
193 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400194 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::InterestLifetime,
195 static_cast<uint64_t>(getInterestLifetime().count()));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700196 }
197
198 // Nonce
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400199 uint32_t nonce = getNonce(); // if nonce was unset, this generates a fresh nonce
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700200 totalLength += encoder.prependByteArrayBlock(tlv::Nonce, reinterpret_cast<uint8_t*>(&nonce), sizeof(nonce));
201
202 // ForwardingHint
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500203 if (!getForwardingHint().empty()) {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700204 totalLength += getForwardingHint().wireEncode(encoder);
205 }
206
207 // MustBeFresh
208 if (getMustBeFresh()) {
209 totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh);
210 }
211
212 // CanBePrefix
213 if (getCanBePrefix()) {
214 totalLength += prependEmptyBlock(encoder, tlv::CanBePrefix);
215 }
216
217 // Name
218 totalLength += getName().wireEncode(encoder);
219
220 totalLength += encoder.prependVarNumber(totalLength);
221 totalLength += encoder.prependVarNumber(tlv::Interest);
222 return totalLength;
223}
224
Davide Pesavento88a0d812017-08-19 21:31:42 -0400225NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Interest);
Junxiao Shi899277a2017-07-07 22:12:12 +0000226
227const Block&
228Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300229{
Junxiao Shi899277a2017-07-07 22:12:12 +0000230 if (m_wire.hasWire())
231 return m_wire;
232
233 EncodingEstimator estimator;
234 size_t estimatedSize = wireEncode(estimator);
235
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400236 EncodingBuffer encoder(estimatedSize, 0);
237 wireEncode(encoder);
Junxiao Shi899277a2017-07-07 22:12:12 +0000238
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400239 const_cast<Interest*>(this)->wireDecode(encoder.block());
Junxiao Shi899277a2017-07-07 22:12:12 +0000240 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300241}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800242
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700243void
Junxiao Shi899277a2017-07-07 22:12:12 +0000244Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700245{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400246 if (wire.type() != tlv::Interest) {
247 NDN_THROW(Error("Interest", wire.type()));
248 }
249
Junxiao Shi899277a2017-07-07 22:12:12 +0000250 m_wire = wire;
251 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700252
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000253 if (!decode02()) {
254 decode03();
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400255 getNonce(); // force generation of nonce
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000256 }
Junxiao Shib55e5d32018-07-18 13:32:00 -0600257
258 m_isCanBePrefixSet = true; // don't trigger warning from decoded packet
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000259}
260
261bool
262Interest::decode02()
263{
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700264 auto element = m_wire.elements_begin();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700265
Junxiao Shi899277a2017-07-07 22:12:12 +0000266 // Name
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700267 if (element != m_wire.elements_end() && element->type() == tlv::Name) {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400268 // decode into a temporary object until we determine that the name is valid, in order
269 // to maintain class invariants and thus provide a basic form of exception safety
270 Name tempName(*element);
271 ssize_t digestIndex = findParametersDigestComponent(tempName);
272 if (digestIndex == -2) {
273 NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
274 }
275 m_name = std::move(tempName);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700276 ++element;
Junxiao Shi899277a2017-07-07 22:12:12 +0000277 }
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000278 else {
279 return false;
280 }
281
282 // Selectors?
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700283 if (element != m_wire.elements_end() && element->type() == tlv::Selectors) {
284 m_selectors.wireDecode(*element);
285 ++element;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000286 }
287 else {
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500288 m_selectors = {};
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000289 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000290
291 // Nonce
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700292 if (element != m_wire.elements_end() && element->type() == tlv::Nonce) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000293 uint32_t nonce = 0;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700294 if (element->value_size() != sizeof(nonce)) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500295 NDN_THROW(Error("Nonce element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000296 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700297 std::memcpy(&nonce, element->value(), sizeof(nonce));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000298 m_nonce = nonce;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700299 ++element;
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000300 }
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000301 else {
302 return false;
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000303 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000304
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000305 // InterestLifetime?
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700306 if (element != m_wire.elements_end() && element->type() == tlv::InterestLifetime) {
307 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
308 ++element;
Junxiao Shi899277a2017-07-07 22:12:12 +0000309 }
310 else {
311 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
312 }
313
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000314 // ForwardingHint?
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700315 if (element != m_wire.elements_end() && element->type() == tlv::ForwardingHint) {
316 m_forwardingHint.wireDecode(*element, false);
317 ++element;
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000318 }
319 else {
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500320 m_forwardingHint = {};
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000321 }
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000322
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700323 return element == m_wire.elements_end();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000324}
325
326void
327Interest::decode03()
328{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400329 // Interest = INTEREST-TYPE TLV-LENGTH
330 // Name
331 // [CanBePrefix]
332 // [MustBeFresh]
333 // [ForwardingHint]
334 // [Nonce]
335 // [InterestLifetime]
336 // [HopLimit]
337 // [ApplicationParameters [InterestSignature]]
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000338
Junxiao Shi8b753a22018-10-24 01:51:40 +0000339 auto element = m_wire.elements_begin();
340 if (element == m_wire.elements_end() || element->type() != tlv::Name) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500341 NDN_THROW(Error("Name element is missing or out of order"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000342 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400343 // decode into a temporary object until we determine that the name is valid, in order
344 // to maintain class invariants and thus provide a basic form of exception safety
345 Name tempName(*element);
346 if (tempName.empty()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500347 NDN_THROW(Error("Name has zero name components"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000348 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400349 ssize_t digestIndex = findParametersDigestComponent(tempName);
350 if (digestIndex == -2) {
351 NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
352 }
353 m_name = std::move(tempName);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000354
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000355 m_selectors = Selectors().setMaxSuffixComponents(1); // CanBePrefix=0
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400356 m_forwardingHint = {};
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000357 m_nonce.reset();
358 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400359 m_hopLimit.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400360 m_parameters.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000361
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400362 int lastElement = 1; // last recognized element index, in spec order
Junxiao Shi8b753a22018-10-24 01:51:40 +0000363 for (++element; element != m_wire.elements_end(); ++element) {
364 switch (element->type()) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000365 case tlv::CanBePrefix: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700366 if (lastElement >= 2) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500367 NDN_THROW(Error("CanBePrefix element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000368 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000369 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500370 NDN_THROW(Error("CanBePrefix element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000371 }
372 m_selectors.setMaxSuffixComponents(-1);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700373 lastElement = 2;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000374 break;
375 }
376 case tlv::MustBeFresh: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700377 if (lastElement >= 3) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500378 NDN_THROW(Error("MustBeFresh element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000379 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000380 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500381 NDN_THROW(Error("MustBeFresh element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000382 }
383 m_selectors.setMustBeFresh(true);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700384 lastElement = 3;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000385 break;
386 }
387 case tlv::ForwardingHint: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700388 if (lastElement >= 4) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500389 NDN_THROW(Error("ForwardingHint element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000390 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000391 m_forwardingHint.wireDecode(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700392 lastElement = 4;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000393 break;
394 }
395 case tlv::Nonce: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700396 if (lastElement >= 5) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500397 NDN_THROW(Error("Nonce element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000398 }
399 uint32_t nonce = 0;
Junxiao Shi8b753a22018-10-24 01:51:40 +0000400 if (element->value_size() != sizeof(nonce)) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500401 NDN_THROW(Error("Nonce element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000402 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000403 std::memcpy(&nonce, element->value(), sizeof(nonce));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000404 m_nonce = nonce;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700405 lastElement = 5;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000406 break;
407 }
408 case tlv::InterestLifetime: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700409 if (lastElement >= 6) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500410 NDN_THROW(Error("InterestLifetime element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000411 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000412 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700413 lastElement = 6;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000414 break;
415 }
416 case tlv::HopLimit: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700417 if (lastElement >= 7) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000418 break; // HopLimit is non-critical, ignore out-of-order appearance
419 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000420 if (element->value_size() != 1) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500421 NDN_THROW(Error("HopLimit element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000422 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400423 m_hopLimit = *element->value();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700424 lastElement = 7;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000425 break;
426 }
Davide Pesavento9c19a392019-04-06 15:07:54 -0400427 case tlv::ApplicationParameters: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700428 if (lastElement >= 8) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400429 break; // ApplicationParameters is non-critical, ignore out-of-order appearance
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000430 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400431 BOOST_ASSERT(!hasApplicationParameters());
432 m_parameters.push_back(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700433 lastElement = 8;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000434 break;
435 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400436 default: { // unrecognized element
437 // if the TLV-TYPE is critical, abort decoding
Junxiao Shi8b753a22018-10-24 01:51:40 +0000438 if (tlv::isCriticalType(element->type())) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500439 NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000440 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400441 // if we already encountered ApplicationParameters, store this element as parameter
442 if (hasApplicationParameters()) {
443 m_parameters.push_back(*element);
444 }
445 // otherwise, ignore it
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000446 break;
447 }
448 }
449 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400450
451 if (s_autoCheckParametersDigest && !isParametersDigestValid()) {
452 NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters"));
453 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700454}
455
Davide Pesaventoa84f4642017-08-23 16:14:51 -0400456std::string
457Interest::toUri() const
458{
459 std::ostringstream os;
460 os << *this;
461 return os.str();
462}
463
Junxiao Shi899277a2017-07-07 22:12:12 +0000464// ---- matching ----
465
Alexander Afanasyev84681982014-01-03 13:26:09 -0800466bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700467Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -0700468{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700469 if (name.size() < m_name.size())
470 return false;
471
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800472 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800473 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700474
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800475 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700476 // name must include implicit digest
477 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800478 return false;
479
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800480 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700481 // name must include implicit digest
482 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800483 return false;
484
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700485 if (!getExclude().empty() &&
486 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800487 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800488 return false;
489
490 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700491}
492
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700493bool
494Interest::matchesData(const Data& data) const
495{
Junxiao Shi42c23622014-07-03 00:55:11 -0700496 size_t interestNameLength = m_name.size();
497 const Name& dataName = data.getName();
498 size_t fullNameLength = dataName.size() + 1;
499
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000500 // check Name and CanBePrefix
Junxiao Shi42c23622014-07-03 00:55:11 -0700501 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800502 if (m_name.get(-1).isImplicitSha256Digest()) {
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000503 if (m_name != data.getFullName()) {
Junxiao Shi42c23622014-07-03 00:55:11 -0700504 return false;
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000505 }
Junxiao Shi42c23622014-07-03 00:55:11 -0700506 }
507 else {
508 // Interest Name is same length as Data full Name, but last component isn't digest
509 // so there's no possibility of matching
510 return false;
511 }
512 }
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000513 else if (getCanBePrefix() ? !m_name.isPrefixOf(dataName) : (m_name != dataName)) {
514 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700515 }
516
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000517 // check MustBeFresh
518 if (getMustBeFresh() && data.getFreshnessPeriod() <= 0_ms) {
519 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700520 }
521
522 return true;
523}
524
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800525bool
526Interest::matchesInterest(const Interest& other) const
527{
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000528 return getName() == other.getName() &&
529 getCanBePrefix() == other.getCanBePrefix() &&
530 getMustBeFresh() == other.getMustBeFresh();
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800531}
532
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400533// ---- field accessors and modifiers ----
534
535Interest&
536Interest::setName(const Name& name)
537{
538 ssize_t digestIndex = findParametersDigestComponent(name);
539 if (digestIndex == -2) {
540 NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent"));
541 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400542 if (name != m_name) {
543 m_name = name;
544 if (hasApplicationParameters()) {
545 addOrReplaceParametersDigestComponent();
546 }
547 m_wire.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400548 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400549 return *this;
550}
551
552Interest&
553Interest::setForwardingHint(const DelegationList& value)
554{
555 m_forwardingHint = value;
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400556 m_wire.reset();
557 return *this;
558}
Junxiao Shi899277a2017-07-07 22:12:12 +0000559
560uint32_t
561Interest::getNonce() const
562{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400563 if (!hasNonce()) {
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000564 m_nonce = random::generateWord32();
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400565 m_wire.reset();
Junxiao Shic2ac5d22017-07-17 22:18:31 +0000566 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000567 return *m_nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000568}
569
570Interest&
571Interest::setNonce(uint32_t nonce)
572{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400573 if (nonce != m_nonce) {
574 m_nonce = nonce;
575 m_wire.reset();
576 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000577 return *this;
578}
579
580void
581Interest::refreshNonce()
582{
583 if (!hasNonce())
584 return;
585
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400586 uint32_t oldNonce = *m_nonce;
587 while (m_nonce == oldNonce)
588 m_nonce = random::generateWord32();
Junxiao Shi899277a2017-07-07 22:12:12 +0000589
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400590 m_wire.reset();
Junxiao Shi899277a2017-07-07 22:12:12 +0000591}
592
Eric Newberryb555b002017-05-17 00:30:44 -0700593Interest&
Junxiao Shi8d3f8342018-04-04 12:46:37 +0000594Interest::setInterestLifetime(time::milliseconds lifetime)
Eric Newberryb555b002017-05-17 00:30:44 -0700595{
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500596 if (lifetime < 0_ms) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500597 NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0"));
Eric Newberryb555b002017-05-17 00:30:44 -0700598 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400599 if (lifetime != m_interestLifetime) {
600 m_interestLifetime = lifetime;
601 m_wire.reset();
602 }
Eric Newberryb555b002017-05-17 00:30:44 -0700603 return *this;
604}
605
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000606Interest&
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400607Interest::setHopLimit(optional<uint8_t> hopLimit)
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000608{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400609 if (hopLimit != m_hopLimit) {
610 m_hopLimit = hopLimit;
611 m_wire.reset();
612 }
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000613 return *this;
614}
615
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400616void
617Interest::setApplicationParametersInternal(Block parameters)
618{
619 parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest()
620 if (m_parameters.empty()) {
621 m_parameters.push_back(std::move(parameters));
622 }
623 else {
624 BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters);
625 m_parameters[0] = std::move(parameters);
626 }
627}
628
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700629Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400630Interest::setApplicationParameters(const Block& parameters)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700631{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400632 if (!parameters.isValid()) {
633 setApplicationParametersInternal(Block(tlv::ApplicationParameters));
Davide Pesavento38912442019-04-06 22:03:39 -0400634 }
635 else if (parameters.type() == tlv::ApplicationParameters) {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400636 setApplicationParametersInternal(parameters);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700637 }
638 else {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400639 setApplicationParametersInternal(Block(tlv::ApplicationParameters, parameters));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700640 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400641 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700642 m_wire.reset();
643 return *this;
644}
645
646Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400647Interest::setApplicationParameters(const uint8_t* value, size_t length)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700648{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400649 if (value == nullptr && length != 0) {
Davide Pesavento38912442019-04-06 22:03:39 -0400650 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
651 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400652 setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value, length));
653 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700654 m_wire.reset();
655 return *this;
656}
657
658Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400659Interest::setApplicationParameters(ConstBufferPtr value)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700660{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400661 if (value == nullptr) {
Davide Pesavento38912442019-04-06 22:03:39 -0400662 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
663 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400664 setApplicationParametersInternal(Block(tlv::ApplicationParameters, std::move(value)));
665 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700666 m_wire.reset();
667 return *this;
668}
669
670Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400671Interest::unsetApplicationParameters()
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700672{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400673 m_parameters.clear();
674 ssize_t digestIndex = findParametersDigestComponent(getName());
675 if (digestIndex >= 0) {
676 m_name.erase(digestIndex);
677 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700678 m_wire.reset();
679 return *this;
680}
681
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400682// ---- ParametersSha256DigestComponent support ----
683
684bool
685Interest::isParametersDigestValid() const
686{
687 ssize_t digestIndex = findParametersDigestComponent(getName());
688 if (digestIndex == -1) {
689 return !hasApplicationParameters();
690 }
691 // cannot be -2 because of the checks in setName() and wireDecode()
692 BOOST_ASSERT(digestIndex >= 0);
693
694 if (!hasApplicationParameters()) {
695 return false;
696 }
697
698 const auto& digestComponent = getName()[digestIndex];
699 auto digest = computeParametersDigest();
700
701 return std::equal(digestComponent.value_begin(), digestComponent.value_end(),
702 digest->begin(), digest->end());
703}
704
705shared_ptr<Buffer>
706Interest::computeParametersDigest() const
707{
708 using namespace security::transform;
709
710 StepSource in;
711 OBufferStream out;
712 in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out);
713
714 std::for_each(m_parameters.begin(), m_parameters.end(), [&] (const Block& b) {
715 in.write(b.wire(), b.size());
716 });
717 in.end();
718
719 return out.buf();
720}
721
722void
723Interest::addOrReplaceParametersDigestComponent()
724{
725 BOOST_ASSERT(hasApplicationParameters());
726
727 ssize_t digestIndex = findParametersDigestComponent(getName());
728 auto digestComponent = name::Component::fromParametersSha256Digest(computeParametersDigest());
729
730 if (digestIndex == -1) {
731 // no existing digest components, append one
732 m_name.append(std::move(digestComponent));
733 }
734 else {
735 // cannot be -2 because of the checks in setName() and wireDecode()
736 BOOST_ASSERT(digestIndex >= 0);
737 // replace the existing digest component
738 m_name.set(digestIndex, std::move(digestComponent));
739 }
740}
741
742ssize_t
743Interest::findParametersDigestComponent(const Name& name)
744{
745 ssize_t pos = -1;
746 for (ssize_t i = 0; i < static_cast<ssize_t>(name.size()); i++) {
747 if (name[i].isParametersSha256Digest()) {
748 if (pos != -1)
749 return -2;
750 pos = i;
751 }
752 }
753 return pos;
754}
755
Junxiao Shi899277a2017-07-07 22:12:12 +0000756// ---- operators ----
757
Junxiao Shib55e5d32018-07-18 13:32:00 -0600758bool
759operator==(const Interest& lhs, const Interest& rhs)
760{
761 bool wasCanBePrefixSetOnLhs = lhs.m_isCanBePrefixSet;
762 bool wasCanBePrefixSetOnRhs = rhs.m_isCanBePrefixSet;
763 lhs.m_isCanBePrefixSet = true;
764 rhs.m_isCanBePrefixSet = true;
765 BOOST_SCOPE_EXIT_ALL(&) {
766 lhs.m_isCanBePrefixSet = wasCanBePrefixSetOnLhs;
767 rhs.m_isCanBePrefixSet = wasCanBePrefixSetOnRhs;
768 };
769
770 return lhs.wireEncode() == rhs.wireEncode();
771}
772
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700773std::ostream&
774operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700775{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800776 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700777
Alexander Afanasyev84681982014-01-03 13:26:09 -0800778 char delim = '?';
779
780 if (interest.getMinSuffixComponents() >= 0) {
781 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
782 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700783 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800784 if (interest.getMaxSuffixComponents() >= 0) {
785 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
786 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700787 }
Eric Newberryb555b002017-05-17 00:30:44 -0700788 if (interest.getChildSelector() != DEFAULT_CHILD_SELECTOR) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800789 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
790 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800791 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800792 if (interest.getMustBeFresh()) {
793 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
794 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800795 }
Eric Newberryb555b002017-05-17 00:30:44 -0700796 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700797 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800798 delim = '&';
799 }
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300800 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800801 os << delim << "ndn.Nonce=" << interest.getNonce();
802 delim = '&';
803 }
804 if (!interest.getExclude().empty()) {
805 os << delim << "ndn.Exclude=" << interest.getExclude();
806 delim = '&';
807 }
808
809 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800810}
811
Junxiao Shi08d07082014-12-03 11:31:44 -0700812} // namespace ndn