blob: f1b3171e6f2e91d1dc589e34e791b687eb029cf9 [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 Pesavento478d3382021-03-17 12:46:08 -04003 * Copyright (c) 2013-2021 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
Eric Newberry6e262f02020-05-29 23:11:25 -070030#include <boost/range/adaptor/reversed.hpp>
31
Davide Pesaventoe1789892017-02-26 15:50:52 -050032#include <cstring>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040033#include <sstream>
Davide Pesaventoe1789892017-02-26 15:50:52 -050034
Jeff Thompsonb7f95562013-07-03 18:36:42 -070035namespace ndn {
Alexander Afanasyev84681982014-01-03 13:26:09 -080036
Junxiao Shic2b8d242014-11-04 08:35:29 -070037BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070038BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Interest>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070039BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
40static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
41 "Interest::Error must inherit from tlv::Error");
42
Junxiao Shib55e5d32018-07-18 13:32:00 -060043boost::logic::tribool Interest::s_defaultCanBePrefix = boost::logic::indeterminate;
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040044bool Interest::s_autoCheckParametersDigest = true;
Junxiao Shib55e5d32018-07-18 13:32:00 -060045
Junxiao Shi8d3f8342018-04-04 12:46:37 +000046Interest::Interest(const Name& name, time::milliseconds lifetime)
Junxiao Shi2af905b2014-11-27 13:10:54 -070047{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040048 setName(name);
49 setInterestLifetime(lifetime);
Junxiao Shib55e5d32018-07-18 13:32:00 -060050
51 if (!boost::logic::indeterminate(s_defaultCanBePrefix)) {
Davide Pesavento4bb06bc2019-04-06 13:59:10 -040052 setCanBePrefix(bool(s_defaultCanBePrefix));
Junxiao Shib55e5d32018-07-18 13:32:00 -060053 }
Junxiao Shi2af905b2014-11-27 13:10:54 -070054}
55
Junxiao Shi2af905b2014-11-27 13:10:54 -070056Interest::Interest(const Block& wire)
57{
58 wireDecode(wire);
59}
60
Junxiao Shi899277a2017-07-07 22:12:12 +000061// ---- encode and decode ----
Alexander Afanasyev840139f2013-12-28 15:02:50 -080062
Junxiao Shi899277a2017-07-07 22:12:12 +000063template<encoding::Tag TAG>
64size_t
65Interest::wireEncode(EncodingImpl<TAG>& encoder) const
66{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040067 // Interest = INTEREST-TYPE TLV-LENGTH
68 // Name
69 // [CanBePrefix]
70 // [MustBeFresh]
71 // [ForwardingHint]
72 // [Nonce]
73 // [InterestLifetime]
74 // [HopLimit]
75 // [ApplicationParameters [InterestSignature]]
76 // (elements are encoded in reverse order)
77
78 // sanity check of ApplicationParameters and ParametersSha256DigestComponent
79 ssize_t digestIndex = findParametersDigestComponent(getName());
80 BOOST_ASSERT(digestIndex != -2); // guaranteed by the checks in setName() and wireDecode()
81 if (digestIndex == -1) {
82 if (hasApplicationParameters())
83 NDN_THROW(Error("Interest with parameters must have a ParametersSha256DigestComponent"));
84 }
85 else if (!hasApplicationParameters()) {
86 NDN_THROW(Error("Interest without parameters must not have a ParametersSha256DigestComponent"));
87 }
88
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070089 size_t totalLength = 0;
90
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040091 // ApplicationParameters and following elements (in reverse order)
Eric Newberry6e262f02020-05-29 23:11:25 -070092 for (const auto& block : m_parameters | boost::adaptors::reversed) {
93 totalLength += encoder.prependBlock(block);
94 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070095
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -040096 // HopLimit
97 if (getHopLimit()) {
Davide Pesavento53533942020-03-04 23:10:06 -050098 totalLength += encoder.prependByteArrayBlock(tlv::HopLimit, &*m_hopLimit, 1);
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -040099 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700100
101 // InterestLifetime
102 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400103 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::InterestLifetime,
104 static_cast<uint64_t>(getInterestLifetime().count()));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700105 }
106
107 // Nonce
Davide Pesavento53533942020-03-04 23:10:06 -0500108 getNonce(); // if nonce was unset, this generates a fresh nonce
109 BOOST_ASSERT(hasNonce());
110 totalLength += encoder.prependByteArrayBlock(tlv::Nonce, m_nonce->data(), m_nonce->size());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700111
112 // ForwardingHint
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500113 if (!getForwardingHint().empty()) {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700114 totalLength += getForwardingHint().wireEncode(encoder);
115 }
116
117 // MustBeFresh
118 if (getMustBeFresh()) {
119 totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh);
120 }
121
122 // CanBePrefix
123 if (getCanBePrefix()) {
124 totalLength += prependEmptyBlock(encoder, tlv::CanBePrefix);
125 }
126
127 // Name
128 totalLength += getName().wireEncode(encoder);
129
130 totalLength += encoder.prependVarNumber(totalLength);
131 totalLength += encoder.prependVarNumber(tlv::Interest);
132 return totalLength;
133}
134
Davide Pesavento88a0d812017-08-19 21:31:42 -0400135NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Interest);
Junxiao Shi899277a2017-07-07 22:12:12 +0000136
137const Block&
138Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300139{
Junxiao Shi899277a2017-07-07 22:12:12 +0000140 if (m_wire.hasWire())
141 return m_wire;
142
143 EncodingEstimator estimator;
144 size_t estimatedSize = wireEncode(estimator);
145
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400146 EncodingBuffer encoder(estimatedSize, 0);
147 wireEncode(encoder);
Junxiao Shi899277a2017-07-07 22:12:12 +0000148
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400149 const_cast<Interest*>(this)->wireDecode(encoder.block());
Junxiao Shi899277a2017-07-07 22:12:12 +0000150 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300151}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800152
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700153void
Junxiao Shi899277a2017-07-07 22:12:12 +0000154Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700155{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400156 if (wire.type() != tlv::Interest) {
157 NDN_THROW(Error("Interest", wire.type()));
158 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000159 m_wire = wire;
160 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700161
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400162 // Interest = INTEREST-TYPE TLV-LENGTH
163 // Name
164 // [CanBePrefix]
165 // [MustBeFresh]
166 // [ForwardingHint]
167 // [Nonce]
168 // [InterestLifetime]
169 // [HopLimit]
170 // [ApplicationParameters [InterestSignature]]
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000171
Junxiao Shi8b753a22018-10-24 01:51:40 +0000172 auto element = m_wire.elements_begin();
173 if (element == m_wire.elements_end() || element->type() != tlv::Name) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500174 NDN_THROW(Error("Name element is missing or out of order"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000175 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400176 // decode into a temporary object until we determine that the name is valid, in order
177 // to maintain class invariants and thus provide a basic form of exception safety
178 Name tempName(*element);
179 if (tempName.empty()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500180 NDN_THROW(Error("Name has zero name components"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000181 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400182 ssize_t digestIndex = findParametersDigestComponent(tempName);
183 if (digestIndex == -2) {
184 NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
185 }
186 m_name = std::move(tempName);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000187
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400188 m_canBePrefix = m_mustBeFresh = false;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400189 m_forwardingHint = {};
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000190 m_nonce.reset();
191 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400192 m_hopLimit.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400193 m_parameters.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000194
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400195 int lastElement = 1; // last recognized element index, in spec order
Junxiao Shi8b753a22018-10-24 01:51:40 +0000196 for (++element; element != m_wire.elements_end(); ++element) {
197 switch (element->type()) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000198 case tlv::CanBePrefix: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700199 if (lastElement >= 2) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500200 NDN_THROW(Error("CanBePrefix element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000201 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000202 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500203 NDN_THROW(Error("CanBePrefix element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000204 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400205 m_canBePrefix = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700206 lastElement = 2;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000207 break;
208 }
209 case tlv::MustBeFresh: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700210 if (lastElement >= 3) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500211 NDN_THROW(Error("MustBeFresh element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000212 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000213 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500214 NDN_THROW(Error("MustBeFresh element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000215 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400216 m_mustBeFresh = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700217 lastElement = 3;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000218 break;
219 }
220 case tlv::ForwardingHint: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700221 if (lastElement >= 4) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500222 NDN_THROW(Error("ForwardingHint element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000223 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000224 m_forwardingHint.wireDecode(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700225 lastElement = 4;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000226 break;
227 }
228 case tlv::Nonce: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700229 if (lastElement >= 5) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500230 NDN_THROW(Error("Nonce element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000231 }
Davide Pesavento53533942020-03-04 23:10:06 -0500232 if (element->value_size() != Nonce().size()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500233 NDN_THROW(Error("Nonce element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000234 }
Davide Pesavento53533942020-03-04 23:10:06 -0500235 m_nonce.emplace();
236 std::memcpy(m_nonce->data(), element->value(), m_nonce->size());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700237 lastElement = 5;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000238 break;
239 }
240 case tlv::InterestLifetime: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700241 if (lastElement >= 6) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500242 NDN_THROW(Error("InterestLifetime element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000243 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000244 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700245 lastElement = 6;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000246 break;
247 }
248 case tlv::HopLimit: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700249 if (lastElement >= 7) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000250 break; // HopLimit is non-critical, ignore out-of-order appearance
251 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000252 if (element->value_size() != 1) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500253 NDN_THROW(Error("HopLimit element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000254 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400255 m_hopLimit = *element->value();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700256 lastElement = 7;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000257 break;
258 }
Davide Pesavento9c19a392019-04-06 15:07:54 -0400259 case tlv::ApplicationParameters: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700260 if (lastElement >= 8) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400261 break; // ApplicationParameters is non-critical, ignore out-of-order appearance
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000262 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400263 BOOST_ASSERT(!hasApplicationParameters());
264 m_parameters.push_back(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700265 lastElement = 8;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000266 break;
267 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400268 default: { // unrecognized element
269 // if the TLV-TYPE is critical, abort decoding
Junxiao Shi8b753a22018-10-24 01:51:40 +0000270 if (tlv::isCriticalType(element->type())) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500271 NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000272 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400273 // if we already encountered ApplicationParameters, store this element as parameter
274 if (hasApplicationParameters()) {
275 m_parameters.push_back(*element);
276 }
277 // otherwise, ignore it
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000278 break;
279 }
280 }
281 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400282
283 if (s_autoCheckParametersDigest && !isParametersDigestValid()) {
284 NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters"));
285 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700286}
287
Davide Pesaventoa84f4642017-08-23 16:14:51 -0400288std::string
289Interest::toUri() const
290{
291 std::ostringstream os;
292 os << *this;
293 return os.str();
294}
295
Junxiao Shi899277a2017-07-07 22:12:12 +0000296// ---- matching ----
297
Alexander Afanasyev84681982014-01-03 13:26:09 -0800298bool
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700299Interest::matchesData(const Data& data) const
300{
Junxiao Shi42c23622014-07-03 00:55:11 -0700301 size_t interestNameLength = m_name.size();
302 const Name& dataName = data.getName();
303 size_t fullNameLength = dataName.size() + 1;
304
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000305 // check Name and CanBePrefix
Junxiao Shi42c23622014-07-03 00:55:11 -0700306 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800307 if (m_name.get(-1).isImplicitSha256Digest()) {
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000308 if (m_name != data.getFullName()) {
Junxiao Shi42c23622014-07-03 00:55:11 -0700309 return false;
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000310 }
Junxiao Shi42c23622014-07-03 00:55:11 -0700311 }
312 else {
313 // Interest Name is same length as Data full Name, but last component isn't digest
314 // so there's no possibility of matching
315 return false;
316 }
317 }
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000318 else if (getCanBePrefix() ? !m_name.isPrefixOf(dataName) : (m_name != dataName)) {
319 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700320 }
321
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000322 // check MustBeFresh
323 if (getMustBeFresh() && data.getFreshnessPeriod() <= 0_ms) {
324 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700325 }
326
327 return true;
328}
329
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800330bool
331Interest::matchesInterest(const Interest& other) const
332{
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000333 return getName() == other.getName() &&
334 getCanBePrefix() == other.getCanBePrefix() &&
335 getMustBeFresh() == other.getMustBeFresh();
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800336}
337
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400338// ---- field accessors and modifiers ----
339
340Interest&
341Interest::setName(const Name& name)
342{
343 ssize_t digestIndex = findParametersDigestComponent(name);
344 if (digestIndex == -2) {
345 NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent"));
346 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400347
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400348 if (name != m_name) {
349 m_name = name;
350 if (hasApplicationParameters()) {
351 addOrReplaceParametersDigestComponent();
352 }
353 m_wire.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400354 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400355 return *this;
356}
357
358Interest&
359Interest::setForwardingHint(const DelegationList& value)
360{
361 m_forwardingHint = value;
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400362 m_wire.reset();
363 return *this;
364}
Junxiao Shi899277a2017-07-07 22:12:12 +0000365
Davide Pesavento53533942020-03-04 23:10:06 -0500366static auto
367generateNonce()
368{
369 uint32_t r = random::generateWord32();
370 Interest::Nonce n;
371 std::memcpy(n.data(), &r, sizeof(r));
372 return n;
373}
374
375Interest::Nonce
Junxiao Shi899277a2017-07-07 22:12:12 +0000376Interest::getNonce() const
377{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400378 if (!hasNonce()) {
Davide Pesavento53533942020-03-04 23:10:06 -0500379 m_nonce = generateNonce();
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400380 m_wire.reset();
Junxiao Shic2ac5d22017-07-17 22:18:31 +0000381 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000382 return *m_nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000383}
384
385Interest&
Davide Pesavento53533942020-03-04 23:10:06 -0500386Interest::setNonce(optional<Interest::Nonce> nonce)
Junxiao Shi899277a2017-07-07 22:12:12 +0000387{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400388 if (nonce != m_nonce) {
389 m_nonce = nonce;
390 m_wire.reset();
391 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000392 return *this;
393}
394
395void
396Interest::refreshNonce()
397{
398 if (!hasNonce())
399 return;
400
Davide Pesavento53533942020-03-04 23:10:06 -0500401 auto oldNonce = *m_nonce;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400402 while (m_nonce == oldNonce)
Davide Pesavento53533942020-03-04 23:10:06 -0500403 m_nonce = generateNonce();
Junxiao Shi899277a2017-07-07 22:12:12 +0000404
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400405 m_wire.reset();
Junxiao Shi899277a2017-07-07 22:12:12 +0000406}
407
Eric Newberryb555b002017-05-17 00:30:44 -0700408Interest&
Junxiao Shi8d3f8342018-04-04 12:46:37 +0000409Interest::setInterestLifetime(time::milliseconds lifetime)
Eric Newberryb555b002017-05-17 00:30:44 -0700410{
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500411 if (lifetime < 0_ms) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500412 NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0"));
Eric Newberryb555b002017-05-17 00:30:44 -0700413 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400414
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400415 if (lifetime != m_interestLifetime) {
416 m_interestLifetime = lifetime;
417 m_wire.reset();
418 }
Eric Newberryb555b002017-05-17 00:30:44 -0700419 return *this;
420}
421
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000422Interest&
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400423Interest::setHopLimit(optional<uint8_t> hopLimit)
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000424{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400425 if (hopLimit != m_hopLimit) {
426 m_hopLimit = hopLimit;
427 m_wire.reset();
428 }
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000429 return *this;
430}
431
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400432void
433Interest::setApplicationParametersInternal(Block parameters)
434{
435 parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest()
436 if (m_parameters.empty()) {
437 m_parameters.push_back(std::move(parameters));
438 }
439 else {
440 BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters);
441 m_parameters[0] = std::move(parameters);
442 }
443}
444
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700445Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400446Interest::setApplicationParameters(const Block& parameters)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700447{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400448 if (!parameters.isValid()) {
Davide Pesavento81bd6962020-06-17 16:03:23 -0400449 NDN_THROW(std::invalid_argument("ApplicationParameters block must be valid"));
Davide Pesavento38912442019-04-06 22:03:39 -0400450 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400451
452 if (parameters.type() == tlv::ApplicationParameters) {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400453 setApplicationParametersInternal(parameters);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700454 }
455 else {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400456 setApplicationParametersInternal(Block(tlv::ApplicationParameters, parameters));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700457 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400458 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700459 m_wire.reset();
460 return *this;
461}
462
463Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400464Interest::setApplicationParameters(const uint8_t* value, size_t length)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700465{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400466 if (value == nullptr && length != 0) {
Davide Pesavento38912442019-04-06 22:03:39 -0400467 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
468 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400469
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400470 setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value, length));
471 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700472 m_wire.reset();
473 return *this;
474}
475
476Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400477Interest::setApplicationParameters(ConstBufferPtr value)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700478{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400479 if (value == nullptr) {
Davide Pesavento38912442019-04-06 22:03:39 -0400480 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
481 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400482
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400483 setApplicationParametersInternal(Block(tlv::ApplicationParameters, std::move(value)));
484 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700485 m_wire.reset();
486 return *this;
487}
488
489Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400490Interest::unsetApplicationParameters()
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700491{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400492 m_parameters.clear();
493 ssize_t digestIndex = findParametersDigestComponent(getName());
494 if (digestIndex >= 0) {
495 m_name.erase(digestIndex);
496 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700497 m_wire.reset();
498 return *this;
499}
500
Eric Newberry6e262f02020-05-29 23:11:25 -0700501bool
502Interest::isSigned() const noexcept
503{
504 return m_parameters.size() >= 3 &&
505 getSignatureInfo().has_value() &&
506 getSignatureValue().isValid() &&
507 !m_name.empty() &&
508 m_name[-1].type() == tlv::ParametersSha256DigestComponent;
509}
510
511optional<SignatureInfo>
512Interest::getSignatureInfo() const
513{
514 auto blockIt = findFirstParameter(tlv::InterestSignatureInfo);
515 if (blockIt != m_parameters.end()) {
516 return make_optional<SignatureInfo>(*blockIt, SignatureInfo::Type::Interest);
517 }
518 return nullopt;
519}
520
521Interest&
522Interest::setSignatureInfo(const SignatureInfo& info)
523{
524 // Prepend empty ApplicationParameters element if none present
525 if (m_parameters.empty()) {
526 m_parameters.push_back(makeEmptyBlock(tlv::ApplicationParameters));
527 }
528
529 // Find first existing InterestSignatureInfo (if any)
530 auto infoIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
531 return block.type() == tlv::InterestSignatureInfo;
532 });
533
534 Block encodedInfo = info.wireEncode(SignatureInfo::Type::Interest);
535 if (infoIt != m_parameters.end()) {
536 if (*infoIt == encodedInfo) {
537 // New InterestSignatureInfo is the same as the old InterestSignatureInfo
538 return *this;
539 }
540
541 // Replace existing InterestSignatureInfo
542 *infoIt = std::move(encodedInfo);
543 }
544 else {
545 // Place before first InterestSignatureValue element (if any), else at end
546 auto valueIt = findFirstParameter(tlv::InterestSignatureValue);
547 m_parameters.insert(valueIt, std::move(encodedInfo));
548 }
549
550 addOrReplaceParametersDigestComponent();
551 m_wire.reset();
552 return *this;
553}
554
555Block
556Interest::getSignatureValue() const
557{
558 auto blockIt = findFirstParameter(tlv::InterestSignatureValue);
559 if (blockIt != m_parameters.end()) {
560 return *blockIt;
561 }
562 return {};
563}
564
565Interest&
566Interest::setSignatureValue(ConstBufferPtr value)
567{
568 if (value == nullptr) {
569 NDN_THROW(std::invalid_argument("InterestSignatureValue buffer cannot be nullptr"));
570 }
571
572 // Ensure presence of InterestSignatureInfo
573 auto infoIt = findFirstParameter(tlv::InterestSignatureInfo);
574 if (infoIt == m_parameters.end()) {
575 NDN_THROW(Error("InterestSignatureInfo must be present to set InterestSignatureValue"));
576 }
577
578 auto valueIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
579 return block.type() == tlv::InterestSignatureValue;
580 });
581
582 Block valueBlock(tlv::InterestSignatureValue, std::move(value));
583 if (valueIt != m_parameters.end()) {
584 if (*valueIt == valueBlock) {
585 // New InterestSignatureValue is the same as the old InterestSignatureValue
586 return *this;
587 }
588
589 // Replace existing InterestSignatureValue
590 *valueIt = std::move(valueBlock);
591 }
592 else {
593 // Place after first InterestSignatureInfo element
594 valueIt = m_parameters.insert(std::next(infoIt), std::move(valueBlock));
595 }
596
597 // computeParametersDigest needs encoded SignatureValue
598 valueIt->encode();
599
600 addOrReplaceParametersDigestComponent();
601 m_wire.reset();
602 return *this;
603}
604
Eric Newberryb74bbda2020-06-18 19:33:58 -0700605InputBuffers
606Interest::extractSignedRanges() const
607{
608 InputBuffers bufs;
609 bufs.reserve(2); // For Name range and parameters range
610
611 wireEncode();
612
613 // Get Interest name minus any ParametersSha256DigestComponent
Davide Pesavento765abc92021-12-27 00:44:04 -0500614 // Name is guaranteed to be non-empty if wireEncode() does not throw
Eric Newberryb74bbda2020-06-18 19:33:58 -0700615 BOOST_ASSERT(!m_name.empty());
616 if (m_name[-1].type() != tlv::ParametersSha256DigestComponent) {
617 NDN_THROW(Error("Interest Name must end with a ParametersSha256DigestComponent"));
618 }
619
Davide Pesavento765abc92021-12-27 00:44:04 -0500620 bufs.emplace_back(m_name[0].wire(), m_name[-1].wire());
Eric Newberryb74bbda2020-06-18 19:33:58 -0700621
Davide Pesavento765abc92021-12-27 00:44:04 -0500622 // Ensure InterestSignatureInfo element is present
Eric Newberryb74bbda2020-06-18 19:33:58 -0700623 auto sigInfoIt = findFirstParameter(tlv::InterestSignatureInfo);
624 if (sigInfoIt == m_parameters.end()) {
625 NDN_THROW(Error("Interest missing InterestSignatureInfo"));
626 }
627
628 // Get range from ApplicationParameters to InterestSignatureValue
629 // or end of parameters (whichever is first)
630 BOOST_ASSERT(!m_parameters.empty() && m_parameters.begin()->type() == tlv::ApplicationParameters);
Davide Pesavento765abc92021-12-27 00:44:04 -0500631 auto lastSignedIt = std::prev(findFirstParameter(tlv::InterestSignatureValue));
632 // Note: we assume that both iterators point to the same underlying buffer
633 bufs.emplace_back(m_parameters.front().begin(), lastSignedIt->end());
634
Eric Newberryb74bbda2020-06-18 19:33:58 -0700635 return bufs;
636}
637
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400638// ---- ParametersSha256DigestComponent support ----
639
640bool
641Interest::isParametersDigestValid() const
642{
643 ssize_t digestIndex = findParametersDigestComponent(getName());
644 if (digestIndex == -1) {
645 return !hasApplicationParameters();
646 }
647 // cannot be -2 because of the checks in setName() and wireDecode()
648 BOOST_ASSERT(digestIndex >= 0);
649
650 if (!hasApplicationParameters()) {
651 return false;
652 }
653
654 const auto& digestComponent = getName()[digestIndex];
655 auto digest = computeParametersDigest();
656
657 return std::equal(digestComponent.value_begin(), digestComponent.value_end(),
658 digest->begin(), digest->end());
659}
660
661shared_ptr<Buffer>
662Interest::computeParametersDigest() const
663{
664 using namespace security::transform;
665
666 StepSource in;
667 OBufferStream out;
668 in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out);
669
Eric Newberry6e262f02020-05-29 23:11:25 -0700670 for (const auto& block : m_parameters) {
Davide Pesavento765abc92021-12-27 00:44:04 -0500671 in.write({block.wire(), block.size()});
Eric Newberry6e262f02020-05-29 23:11:25 -0700672 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400673 in.end();
674
675 return out.buf();
676}
677
678void
679Interest::addOrReplaceParametersDigestComponent()
680{
681 BOOST_ASSERT(hasApplicationParameters());
682
683 ssize_t digestIndex = findParametersDigestComponent(getName());
684 auto digestComponent = name::Component::fromParametersSha256Digest(computeParametersDigest());
685
686 if (digestIndex == -1) {
687 // no existing digest components, append one
688 m_name.append(std::move(digestComponent));
689 }
690 else {
691 // cannot be -2 because of the checks in setName() and wireDecode()
692 BOOST_ASSERT(digestIndex >= 0);
693 // replace the existing digest component
694 m_name.set(digestIndex, std::move(digestComponent));
695 }
696}
697
698ssize_t
699Interest::findParametersDigestComponent(const Name& name)
700{
701 ssize_t pos = -1;
702 for (ssize_t i = 0; i < static_cast<ssize_t>(name.size()); i++) {
703 if (name[i].isParametersSha256Digest()) {
704 if (pos != -1)
705 return -2;
706 pos = i;
707 }
708 }
709 return pos;
710}
711
Eric Newberry6e262f02020-05-29 23:11:25 -0700712std::vector<Block>::const_iterator
713Interest::findFirstParameter(uint32_t type) const
714{
715 return std::find_if(m_parameters.begin(), m_parameters.end(), [type] (const Block& block) {
716 return block.type() == type;
717 });
718}
719
Junxiao Shi899277a2017-07-07 22:12:12 +0000720// ---- operators ----
721
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700722std::ostream&
723operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700724{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800725 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700726
Alexander Afanasyev84681982014-01-03 13:26:09 -0800727 char delim = '?';
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400728 auto printOne = [&] (const auto&... args) {
729 os << delim;
Alexander Afanasyev84681982014-01-03 13:26:09 -0800730 delim = '&';
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400731 using expand = int[];
732 (void)expand{(os << args, 0)...}; // use a fold expression when we switch to C++17
733 };
734
735 if (interest.getCanBePrefix()) {
736 printOne("CanBePrefix");
Jeff Thompson13e280b2013-12-03 13:12:23 -0800737 }
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400738 if (interest.getMustBeFresh()) {
739 printOne("MustBeFresh");
Alexander Afanasyev84681982014-01-03 13:26:09 -0800740 }
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300741 if (interest.hasNonce()) {
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400742 printOne("Nonce=", interest.getNonce());
743 }
744 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
745 printOne("Lifetime=", interest.getInterestLifetime().count());
746 }
747 if (interest.getHopLimit()) {
748 printOne("HopLimit=", static_cast<unsigned>(*interest.getHopLimit()));
Alexander Afanasyev84681982014-01-03 13:26:09 -0800749 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800750
751 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800752}
753
Junxiao Shi08d07082014-12-03 11:31:44 -0700754} // namespace ndn