blob: 34ebd4a0cf5ca109302c5b3efdc8faf61451b267 [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 Shi42c23622014-07-03 00:55:11 -070024#include "util/crypto.hpp"
Junxiao Shiaf8eeea2014-03-31 20:10:56 -070025#include "data.hpp"
Alexander Afanasyev840139f2013-12-28 15:02:50 -080026
Davide Pesaventoe1789892017-02-26 15:50:52 -050027#include <cstring>
28
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)
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -070041 , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX)
Junxiao Shi2af905b2014-11-27 13:10:54 -070042{
Junxiao Shi899277a2017-07-07 22:12:12 +000043 if (interestLifetime < time::milliseconds::zero()) {
44 BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
45 }
Junxiao Shi2af905b2014-11-27 13:10:54 -070046}
47
Junxiao Shi2af905b2014-11-27 13:10:54 -070048Interest::Interest(const Block& wire)
49{
50 wireDecode(wire);
51}
52
Junxiao Shi899277a2017-07-07 22:12:12 +000053// ---- encode and decode ----
Alexander Afanasyev840139f2013-12-28 15:02:50 -080054
Junxiao Shi899277a2017-07-07 22:12:12 +000055template<encoding::Tag TAG>
56size_t
57Interest::wireEncode(EncodingImpl<TAG>& encoder) const
58{
59 size_t totalLength = 0;
60
61 // Interest ::= INTEREST-TYPE TLV-LENGTH
62 // Name
63 // Selectors?
64 // Nonce
65 // InterestLifetime?
66 // Link?
67 // SelectedDelegation?
68
69 // (reverse encoding)
70
71 // Link and SelectedDelegation
72 if (hasLink()) {
73 if (hasSelectedDelegation()) {
74 totalLength += prependNonNegativeIntegerBlock(encoder,
75 tlv::SelectedDelegation,
76 m_selectedDelegationIndex);
77 }
78 totalLength += encoder.prependBlock(m_link);
Alexander Afanasyeve881e932014-06-08 14:47:03 +030079 }
Junxiao Shi899277a2017-07-07 22:12:12 +000080 else {
81 BOOST_ASSERT(!hasSelectedDelegation());
82 }
83
84 // InterestLifetime
85 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
86 totalLength += prependNonNegativeIntegerBlock(encoder,
87 tlv::InterestLifetime,
88 getInterestLifetime().count());
89 }
90
91 // Nonce
92 getNonce(); // to ensure that Nonce is properly set
93 totalLength += encoder.prependBlock(m_nonce);
94
95 // Selectors
96 if (hasSelectors()) {
97 totalLength += getSelectors().wireEncode(encoder);
98 }
99
100 // Name
101 totalLength += getName().wireEncode(encoder);
102
103 totalLength += encoder.prependVarNumber(totalLength);
104 totalLength += encoder.prependVarNumber(tlv::Interest);
105 return totalLength;
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800106}
107
Junxiao Shi899277a2017-07-07 22:12:12 +0000108template size_t
109Interest::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
110
111template size_t
112Interest::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
113
114const Block&
115Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300116{
Junxiao Shi899277a2017-07-07 22:12:12 +0000117 if (m_wire.hasWire())
118 return m_wire;
119
120 EncodingEstimator estimator;
121 size_t estimatedSize = wireEncode(estimator);
122
123 EncodingBuffer buffer(estimatedSize, 0);
124 wireEncode(buffer);
125
126 // to ensure that Nonce block points to the right memory location
127 const_cast<Interest*>(this)->wireDecode(buffer.block());
128
129 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300130}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800131
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700132void
Junxiao Shi899277a2017-07-07 22:12:12 +0000133Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700134{
Junxiao Shi899277a2017-07-07 22:12:12 +0000135 m_wire = wire;
136 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700137
Junxiao Shi899277a2017-07-07 22:12:12 +0000138 if (m_wire.type() != tlv::Interest)
139 BOOST_THROW_EXCEPTION(Error("Unexpected TLV number when decoding Interest"));
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700140
Junxiao Shi899277a2017-07-07 22:12:12 +0000141 // Name
142 m_name.wireDecode(m_wire.get(tlv::Name));
143
144 // Selectors
145 Block::element_const_iterator val = m_wire.find(tlv::Selectors);
146 if (val != m_wire.elements_end()) {
147 m_selectors.wireDecode(*val);
148 }
149 else
150 m_selectors = Selectors();
151
152 // Nonce
153 m_nonce = m_wire.get(tlv::Nonce);
154
155 // InterestLifetime
156 val = m_wire.find(tlv::InterestLifetime);
157 if (val != m_wire.elements_end()) {
158 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
159 }
160 else {
161 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
162 }
163
164 // Link
165 m_linkCached.reset();
166 val = m_wire.find(tlv::Data);
167 if (val != m_wire.elements_end()) {
168 m_link = (*val);
169 }
170 else {
171 m_link = Block();
172 }
173
174 // SelectedDelegation
175 val = m_wire.find(tlv::SelectedDelegation);
176 if (val != m_wire.elements_end()) {
177 if (!this->hasLink()) {
178 BOOST_THROW_EXCEPTION(Error("Interest contains SelectedDelegation, but no LINK object"));
179 }
180 uint64_t selectedDelegation = readNonNegativeInteger(*val);
181 if (selectedDelegation < uint64_t(Link::countDelegationsFromWire(m_link))) {
182 m_selectedDelegationIndex = static_cast<size_t>(selectedDelegation);
183 }
184 else {
185 BOOST_THROW_EXCEPTION(Error("Invalid selected delegation index when decoding Interest"));
186 }
187 }
188 else {
189 m_selectedDelegationIndex = INVALID_SELECTED_DELEGATION_INDEX;
190 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700191}
192
Junxiao Shi899277a2017-07-07 22:12:12 +0000193// ---- matching ----
194
Alexander Afanasyev84681982014-01-03 13:26:09 -0800195bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700196Interest::matchesName(const Name& name) const
Jeff Thompson25b4e612013-10-10 16:03:24 -0700197{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700198 if (name.size() < m_name.size())
199 return false;
200
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800201 if (!m_name.isPrefixOf(name))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800202 return false;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700203
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800204 if (getMinSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700205 // name must include implicit digest
206 !(name.size() - m_name.size() >= static_cast<size_t>(getMinSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800207 return false;
208
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800209 if (getMaxSuffixComponents() >= 0 &&
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700210 // name must include implicit digest
211 !(name.size() - m_name.size() <= static_cast<size_t>(getMaxSuffixComponents())))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800212 return false;
213
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700214 if (!getExclude().empty() &&
215 name.size() > m_name.size() &&
Alexander Afanasyevc348f832014-02-17 16:35:17 -0800216 getExclude().isExcluded(name[m_name.size()]))
Alexander Afanasyev84681982014-01-03 13:26:09 -0800217 return false;
218
219 return true;
Jeff Thompson25b4e612013-10-10 16:03:24 -0700220}
221
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700222bool
223Interest::matchesData(const Data& data) const
224{
Junxiao Shi42c23622014-07-03 00:55:11 -0700225 size_t interestNameLength = m_name.size();
226 const Name& dataName = data.getName();
227 size_t fullNameLength = dataName.size() + 1;
228
229 // check MinSuffixComponents
230 bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
231 size_t minSuffixComponents = hasMinSuffixComponents ?
232 static_cast<size_t>(getMinSuffixComponents()) : 0;
233 if (!(interestNameLength + minSuffixComponents <= fullNameLength))
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700234 return false;
Junxiao Shi42c23622014-07-03 00:55:11 -0700235
236 // check MaxSuffixComponents
237 bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
238 if (hasMaxSuffixComponents &&
239 !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
240 return false;
241
242 // check prefix
243 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800244 if (m_name.get(-1).isImplicitSha256Digest()) {
245 if (m_name != data.getFullName())
Junxiao Shi42c23622014-07-03 00:55:11 -0700246 return false;
247 }
248 else {
249 // Interest Name is same length as Data full Name, but last component isn't digest
250 // so there's no possibility of matching
251 return false;
252 }
253 }
254 else {
255 // Interest Name is a strict prefix of Data full Name
256 if (!m_name.isPrefixOf(dataName))
257 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700258 }
259
Junxiao Shi42c23622014-07-03 00:55:11 -0700260 // check Exclude
261 // Exclude won't be violated if Interest Name is same as Data full Name
262 if (!getExclude().empty() && fullNameLength > interestNameLength) {
263 if (interestNameLength == fullNameLength - 1) {
264 // component to exclude is the digest
265 if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
266 return false;
267 // There's opportunity to inspect the Exclude filter and determine whether
268 // the digest would make a difference.
Junxiao Shi08d07082014-12-03 11:31:44 -0700269 // eg. "<NameComponent>AA</NameComponent><Any/>" doesn't exclude any digest -
270 // fullName not needed;
271 // "<Any/><NameComponent>AA</NameComponent>" and
272 // "<Any/><ImplicitSha256DigestComponent>ffffffffffffffffffffffffffffffff
273 // </ImplicitSha256DigestComponent>"
274 // excludes all digests - fullName not needed;
275 // "<Any/><ImplicitSha256DigestComponent>80000000000000000000000000000000
276 // </ImplicitSha256DigestComponent>"
277 // excludes some digests - fullName required
Junxiao Shi42c23622014-07-03 00:55:11 -0700278 // But Interests that contain the exact Data Name before digest and also
279 // contain Exclude filter is too rare to optimize for, so we request
Junxiao Shi68247832017-07-03 22:06:49 +0000280 // fullName no matter what's in the Exclude filter.
Junxiao Shi42c23622014-07-03 00:55:11 -0700281 }
282 else {
283 // component to exclude is not the digest
284 if (getExclude().isExcluded(dataName.get(interestNameLength)))
285 return false;
286 }
287 }
288
289 // check PublisherPublicKeyLocator
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700290 const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
291 if (!publisherPublicKeyLocator.empty()) {
292 const Signature& signature = data.getSignature();
293 const Block& signatureInfo = signature.getInfo();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600294 Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator);
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700295 if (it == signatureInfo.elements_end()) {
296 return false;
297 }
298 if (publisherPublicKeyLocator.wireEncode() != *it) {
299 return false;
300 }
301 }
302
303 return true;
304}
305
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800306bool
307Interest::matchesInterest(const Interest& other) const
308{
309 /// @todo #3162 match Link field
310 return (this->getName() == other.getName() &&
311 this->getSelectors() == other.getSelectors());
312}
313
Junxiao Shi899277a2017-07-07 22:12:12 +0000314// ---- field accessors ----
315
316uint32_t
317Interest::getNonce() const
318{
319 if (!m_nonce.hasWire())
320 const_cast<Interest*>(this)->setNonce(random::generateWord32());
321
322 if (m_nonce.value_size() == sizeof(uint32_t))
323 return *reinterpret_cast<const uint32_t*>(m_nonce.value());
324 else {
325 // for compatibility reasons. Should be removed eventually
326 return readNonNegativeInteger(m_nonce);
327 }
328}
329
330Interest&
331Interest::setNonce(uint32_t nonce)
332{
333 if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) {
334 std::memcpy(const_cast<uint8_t*>(m_nonce.value()), &nonce, sizeof(nonce));
335 }
336 else {
337 m_nonce = makeBinaryBlock(tlv::Nonce,
338 reinterpret_cast<const uint8_t*>(&nonce),
339 sizeof(nonce));
340 m_wire.reset();
341 }
342 return *this;
343}
344
345void
346Interest::refreshNonce()
347{
348 if (!hasNonce())
349 return;
350
351 uint32_t oldNonce = getNonce();
352 uint32_t newNonce = oldNonce;
353 while (newNonce == oldNonce)
354 newNonce = random::generateWord32();
355
356 setNonce(newNonce);
357}
358
Eric Newberryb555b002017-05-17 00:30:44 -0700359Interest&
360Interest::setInterestLifetime(time::milliseconds interestLifetime)
361{
362 if (interestLifetime < time::milliseconds::zero()) {
363 BOOST_THROW_EXCEPTION(std::invalid_argument("InterestLifetime must be >= 0"));
364 }
365 m_interestLifetime = interestLifetime;
366 m_wire.reset();
367 return *this;
368}
369
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700370bool
371Interest::hasLink() const
372{
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700373 return m_link.hasWire();
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700374}
375
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700376const Link&
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700377Interest::getLink() const
378{
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700379 if (hasLink()) {
380 if (!m_linkCached) {
381 m_linkCached = make_shared<Link>(m_link);
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700382 }
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700383 return *m_linkCached;
384 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700385 BOOST_THROW_EXCEPTION(Error("There is no encapsulated link object"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700386}
387
388void
389Interest::setLink(const Block& link)
390{
391 m_link = link;
392 if (!link.hasWire()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700393 BOOST_THROW_EXCEPTION(Error("The given link does not have a wire format"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700394 }
395 m_wire.reset();
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700396 m_linkCached.reset();
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700397 this->unsetSelectedDelegation();
398}
399
400void
401Interest::unsetLink()
402{
403 m_link.reset();
404 m_wire.reset();
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700405 m_linkCached.reset();
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700406 this->unsetSelectedDelegation();
407}
408
409bool
410Interest::hasSelectedDelegation() const
411{
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700412 return m_selectedDelegationIndex != INVALID_SELECTED_DELEGATION_INDEX;
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700413}
414
415Name
416Interest::getSelectedDelegation() const
417{
418 if (!hasSelectedDelegation()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700419 BOOST_THROW_EXCEPTION(Error("There is no encapsulated selected delegation"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700420 }
421 return std::get<1>(Link::getDelegationFromWire(m_link, m_selectedDelegationIndex));
422}
423
424void
425Interest::setSelectedDelegation(const Name& delegationName)
426{
427 size_t delegationIndex = Link::findDelegationFromWire(m_link, delegationName);
428 if (delegationIndex != INVALID_SELECTED_DELEGATION_INDEX) {
429 m_selectedDelegationIndex = delegationIndex;
430 }
431 else {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700432 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid selected delegation name"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700433 }
434 m_wire.reset();
435}
436
437void
438Interest::setSelectedDelegation(size_t delegationIndex)
439{
440 if (delegationIndex >= Link(m_link).getDelegations().size()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700441 BOOST_THROW_EXCEPTION(Error("Invalid selected delegation index"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700442 }
443 m_selectedDelegationIndex = delegationIndex;
444 m_wire.reset();
445}
446
447void
448Interest::unsetSelectedDelegation()
449{
450 m_selectedDelegationIndex = INVALID_SELECTED_DELEGATION_INDEX;
451 m_wire.reset();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700452}
453
Junxiao Shi899277a2017-07-07 22:12:12 +0000454// ---- operators ----
455
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700456std::ostream&
457operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700458{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800459 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700460
Alexander Afanasyev84681982014-01-03 13:26:09 -0800461 char delim = '?';
462
463 if (interest.getMinSuffixComponents() >= 0) {
464 os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents();
465 delim = '&';
Jeff Thompsonfe556862013-07-09 13:52:55 -0700466 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800467 if (interest.getMaxSuffixComponents() >= 0) {
468 os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents();
469 delim = '&';
Jeff Thompson37527d62013-08-21 11:15:54 -0700470 }
Eric Newberryb555b002017-05-17 00:30:44 -0700471 if (interest.getChildSelector() != DEFAULT_CHILD_SELECTOR) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800472 os << delim << "ndn.ChildSelector=" << interest.getChildSelector();
473 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800474 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800475 if (interest.getMustBeFresh()) {
476 os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh();
477 delim = '&';
Jeff Thompson13e280b2013-12-03 13:12:23 -0800478 }
Eric Newberryb555b002017-05-17 00:30:44 -0700479 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700480 os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count();
Alexander Afanasyev84681982014-01-03 13:26:09 -0800481 delim = '&';
482 }
483
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300484 if (interest.hasNonce()) {
Alexander Afanasyev84681982014-01-03 13:26:09 -0800485 os << delim << "ndn.Nonce=" << interest.getNonce();
486 delim = '&';
487 }
488 if (!interest.getExclude().empty()) {
489 os << delim << "ndn.Exclude=" << interest.getExclude();
490 delim = '&';
491 }
492
493 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800494}
495
Junxiao Shi08d07082014-12-03 11:31:44 -0700496} // namespace ndn