blob: 66e240add916233d43068cdd26f6ea279687934d [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/*
Junxiao Shie4603e12022-01-05 19:12:25 +00003 * Copyright (c) 2013-2022 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
Junxiao Shie4603e12022-01-05 19:12:25 +0000113 if (!m_forwardingHint.empty()) {
114 totalLength += prependNestedBlock(encoder, tlv::ForwardingHint,
115 m_forwardingHint.begin(), m_forwardingHint.end());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700116 }
117
118 // MustBeFresh
119 if (getMustBeFresh()) {
120 totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh);
121 }
122
123 // CanBePrefix
124 if (getCanBePrefix()) {
125 totalLength += prependEmptyBlock(encoder, tlv::CanBePrefix);
126 }
127
128 // Name
129 totalLength += getName().wireEncode(encoder);
130
131 totalLength += encoder.prependVarNumber(totalLength);
132 totalLength += encoder.prependVarNumber(tlv::Interest);
133 return totalLength;
134}
135
Davide Pesavento88a0d812017-08-19 21:31:42 -0400136NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Interest);
Junxiao Shi899277a2017-07-07 22:12:12 +0000137
138const Block&
139Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300140{
Junxiao Shi899277a2017-07-07 22:12:12 +0000141 if (m_wire.hasWire())
142 return m_wire;
143
144 EncodingEstimator estimator;
145 size_t estimatedSize = wireEncode(estimator);
146
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400147 EncodingBuffer encoder(estimatedSize, 0);
148 wireEncode(encoder);
Junxiao Shi899277a2017-07-07 22:12:12 +0000149
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400150 const_cast<Interest*>(this)->wireDecode(encoder.block());
Junxiao Shi899277a2017-07-07 22:12:12 +0000151 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300152}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800153
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700154void
Junxiao Shi899277a2017-07-07 22:12:12 +0000155Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700156{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400157 if (wire.type() != tlv::Interest) {
158 NDN_THROW(Error("Interest", wire.type()));
159 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000160 m_wire = wire;
161 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700162
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400163 // Interest = INTEREST-TYPE TLV-LENGTH
164 // Name
165 // [CanBePrefix]
166 // [MustBeFresh]
167 // [ForwardingHint]
168 // [Nonce]
169 // [InterestLifetime]
170 // [HopLimit]
171 // [ApplicationParameters [InterestSignature]]
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000172
Junxiao Shi8b753a22018-10-24 01:51:40 +0000173 auto element = m_wire.elements_begin();
174 if (element == m_wire.elements_end() || element->type() != tlv::Name) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500175 NDN_THROW(Error("Name element is missing or out of order"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000176 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400177 // decode into a temporary object until we determine that the name is valid, in order
178 // to maintain class invariants and thus provide a basic form of exception safety
179 Name tempName(*element);
180 if (tempName.empty()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500181 NDN_THROW(Error("Name has zero name components"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000182 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400183 ssize_t digestIndex = findParametersDigestComponent(tempName);
184 if (digestIndex == -2) {
185 NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
186 }
187 m_name = std::move(tempName);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000188
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400189 m_canBePrefix = m_mustBeFresh = false;
Junxiao Shie4603e12022-01-05 19:12:25 +0000190 m_forwardingHint.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000191 m_nonce.reset();
192 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400193 m_hopLimit.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400194 m_parameters.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000195
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400196 int lastElement = 1; // last recognized element index, in spec order
Junxiao Shi8b753a22018-10-24 01:51:40 +0000197 for (++element; element != m_wire.elements_end(); ++element) {
198 switch (element->type()) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000199 case tlv::CanBePrefix: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700200 if (lastElement >= 2) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500201 NDN_THROW(Error("CanBePrefix element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000202 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000203 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500204 NDN_THROW(Error("CanBePrefix element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000205 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400206 m_canBePrefix = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700207 lastElement = 2;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000208 break;
209 }
210 case tlv::MustBeFresh: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700211 if (lastElement >= 3) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500212 NDN_THROW(Error("MustBeFresh element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000213 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000214 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500215 NDN_THROW(Error("MustBeFresh element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000216 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400217 m_mustBeFresh = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700218 lastElement = 3;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000219 break;
220 }
221 case tlv::ForwardingHint: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700222 if (lastElement >= 4) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500223 NDN_THROW(Error("ForwardingHint element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000224 }
Junxiao Shie4603e12022-01-05 19:12:25 +0000225 // ForwardingHint = FORWARDING-HINT-TYPE TLV-LENGTH 1*Name
226 // [previous format]
227 // ForwardingHint = FORWARDING-HINT-TYPE TLV-LENGTH 1*Delegation
228 // Delegation = DELEGATION-TYPE TLV-LENGTH Preference Name
229 element->parse();
230 for (const auto& del : element->elements()) {
231 switch (del.type()) {
232 case tlv::Name:
233 try {
234 m_forwardingHint.emplace_back(del);
235 }
236 catch (const tlv::Error&) {
237 NDN_THROW_NESTED(Error("Invalid Name in ForwardingHint"));
238 }
239 break;
240 case tlv::LinkDelegation:
241 try {
242 del.parse();
243 m_forwardingHint.emplace_back(del.get(tlv::Name));
244 }
245 catch (const tlv::Error&) {
246 NDN_THROW_NESTED(Error("Invalid Name in ForwardingHint.Delegation"));
247 }
248 break;
249 default:
250 if (tlv::isCriticalType(del.type())) {
251 NDN_THROW(Error("Unexpected TLV-TYPE " + to_string(del.type()) + " while decoding ForwardingHint"));
252 }
253 break;
254 }
255 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700256 lastElement = 4;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000257 break;
258 }
259 case tlv::Nonce: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700260 if (lastElement >= 5) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500261 NDN_THROW(Error("Nonce element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000262 }
Davide Pesavento53533942020-03-04 23:10:06 -0500263 if (element->value_size() != Nonce().size()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500264 NDN_THROW(Error("Nonce element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000265 }
Davide Pesavento53533942020-03-04 23:10:06 -0500266 m_nonce.emplace();
267 std::memcpy(m_nonce->data(), element->value(), m_nonce->size());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700268 lastElement = 5;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000269 break;
270 }
271 case tlv::InterestLifetime: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700272 if (lastElement >= 6) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500273 NDN_THROW(Error("InterestLifetime element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000274 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000275 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700276 lastElement = 6;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000277 break;
278 }
279 case tlv::HopLimit: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700280 if (lastElement >= 7) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000281 break; // HopLimit is non-critical, ignore out-of-order appearance
282 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000283 if (element->value_size() != 1) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500284 NDN_THROW(Error("HopLimit element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000285 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400286 m_hopLimit = *element->value();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700287 lastElement = 7;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000288 break;
289 }
Davide Pesavento9c19a392019-04-06 15:07:54 -0400290 case tlv::ApplicationParameters: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700291 if (lastElement >= 8) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400292 break; // ApplicationParameters is non-critical, ignore out-of-order appearance
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000293 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400294 BOOST_ASSERT(!hasApplicationParameters());
295 m_parameters.push_back(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700296 lastElement = 8;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000297 break;
298 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400299 default: { // unrecognized element
300 // if the TLV-TYPE is critical, abort decoding
Junxiao Shi8b753a22018-10-24 01:51:40 +0000301 if (tlv::isCriticalType(element->type())) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500302 NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000303 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400304 // if we already encountered ApplicationParameters, store this element as parameter
305 if (hasApplicationParameters()) {
306 m_parameters.push_back(*element);
307 }
308 // otherwise, ignore it
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000309 break;
310 }
311 }
312 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400313
314 if (s_autoCheckParametersDigest && !isParametersDigestValid()) {
315 NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters"));
316 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700317}
318
Davide Pesaventoa84f4642017-08-23 16:14:51 -0400319std::string
320Interest::toUri() const
321{
322 std::ostringstream os;
323 os << *this;
324 return os.str();
325}
326
Junxiao Shi899277a2017-07-07 22:12:12 +0000327// ---- matching ----
328
Alexander Afanasyev84681982014-01-03 13:26:09 -0800329bool
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700330Interest::matchesData(const Data& data) const
331{
Junxiao Shi42c23622014-07-03 00:55:11 -0700332 size_t interestNameLength = m_name.size();
333 const Name& dataName = data.getName();
334 size_t fullNameLength = dataName.size() + 1;
335
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000336 // check Name and CanBePrefix
Junxiao Shi42c23622014-07-03 00:55:11 -0700337 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800338 if (m_name.get(-1).isImplicitSha256Digest()) {
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000339 if (m_name != data.getFullName()) {
Junxiao Shi42c23622014-07-03 00:55:11 -0700340 return false;
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000341 }
Junxiao Shi42c23622014-07-03 00:55:11 -0700342 }
343 else {
344 // Interest Name is same length as Data full Name, but last component isn't digest
345 // so there's no possibility of matching
346 return false;
347 }
348 }
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000349 else if (getCanBePrefix() ? !m_name.isPrefixOf(dataName) : (m_name != dataName)) {
350 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700351 }
352
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000353 // check MustBeFresh
354 if (getMustBeFresh() && data.getFreshnessPeriod() <= 0_ms) {
355 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700356 }
357
358 return true;
359}
360
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800361bool
362Interest::matchesInterest(const Interest& other) const
363{
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000364 return getName() == other.getName() &&
365 getCanBePrefix() == other.getCanBePrefix() &&
366 getMustBeFresh() == other.getMustBeFresh();
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800367}
368
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400369// ---- field accessors and modifiers ----
370
371Interest&
372Interest::setName(const Name& name)
373{
374 ssize_t digestIndex = findParametersDigestComponent(name);
375 if (digestIndex == -2) {
376 NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent"));
377 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400378
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400379 if (name != m_name) {
380 m_name = name;
381 if (hasApplicationParameters()) {
382 addOrReplaceParametersDigestComponent();
383 }
384 m_wire.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400385 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400386 return *this;
387}
388
389Interest&
Junxiao Shie4603e12022-01-05 19:12:25 +0000390Interest::setForwardingHint(std::vector<Name> value)
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400391{
Junxiao Shie4603e12022-01-05 19:12:25 +0000392 m_forwardingHint = std::move(value);
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400393 m_wire.reset();
394 return *this;
395}
Junxiao Shi899277a2017-07-07 22:12:12 +0000396
Davide Pesavento53533942020-03-04 23:10:06 -0500397static auto
398generateNonce()
399{
400 uint32_t r = random::generateWord32();
401 Interest::Nonce n;
402 std::memcpy(n.data(), &r, sizeof(r));
403 return n;
404}
405
406Interest::Nonce
Junxiao Shi899277a2017-07-07 22:12:12 +0000407Interest::getNonce() const
408{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400409 if (!hasNonce()) {
Davide Pesavento53533942020-03-04 23:10:06 -0500410 m_nonce = generateNonce();
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400411 m_wire.reset();
Junxiao Shic2ac5d22017-07-17 22:18:31 +0000412 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000413 return *m_nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000414}
415
416Interest&
Davide Pesavento53533942020-03-04 23:10:06 -0500417Interest::setNonce(optional<Interest::Nonce> nonce)
Junxiao Shi899277a2017-07-07 22:12:12 +0000418{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400419 if (nonce != m_nonce) {
420 m_nonce = nonce;
421 m_wire.reset();
422 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000423 return *this;
424}
425
426void
427Interest::refreshNonce()
428{
429 if (!hasNonce())
430 return;
431
Davide Pesavento53533942020-03-04 23:10:06 -0500432 auto oldNonce = *m_nonce;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400433 while (m_nonce == oldNonce)
Davide Pesavento53533942020-03-04 23:10:06 -0500434 m_nonce = generateNonce();
Junxiao Shi899277a2017-07-07 22:12:12 +0000435
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400436 m_wire.reset();
Junxiao Shi899277a2017-07-07 22:12:12 +0000437}
438
Eric Newberryb555b002017-05-17 00:30:44 -0700439Interest&
Junxiao Shi8d3f8342018-04-04 12:46:37 +0000440Interest::setInterestLifetime(time::milliseconds lifetime)
Eric Newberryb555b002017-05-17 00:30:44 -0700441{
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500442 if (lifetime < 0_ms) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500443 NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0"));
Eric Newberryb555b002017-05-17 00:30:44 -0700444 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400445
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400446 if (lifetime != m_interestLifetime) {
447 m_interestLifetime = lifetime;
448 m_wire.reset();
449 }
Eric Newberryb555b002017-05-17 00:30:44 -0700450 return *this;
451}
452
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000453Interest&
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400454Interest::setHopLimit(optional<uint8_t> hopLimit)
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000455{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400456 if (hopLimit != m_hopLimit) {
457 m_hopLimit = hopLimit;
458 m_wire.reset();
459 }
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000460 return *this;
461}
462
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400463void
464Interest::setApplicationParametersInternal(Block parameters)
465{
466 parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest()
467 if (m_parameters.empty()) {
468 m_parameters.push_back(std::move(parameters));
469 }
470 else {
471 BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters);
472 m_parameters[0] = std::move(parameters);
473 }
474}
475
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700476Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400477Interest::setApplicationParameters(const Block& parameters)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700478{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400479 if (!parameters.isValid()) {
Davide Pesavento81bd6962020-06-17 16:03:23 -0400480 NDN_THROW(std::invalid_argument("ApplicationParameters block must be valid"));
Davide Pesavento38912442019-04-06 22:03:39 -0400481 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400482
483 if (parameters.type() == tlv::ApplicationParameters) {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400484 setApplicationParametersInternal(parameters);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700485 }
486 else {
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400487 setApplicationParametersInternal(Block(tlv::ApplicationParameters, parameters));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700488 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400489 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700490 m_wire.reset();
491 return *this;
492}
493
494Interest&
Davide Pesaventoa3d809e2022-02-06 11:55:02 -0500495Interest::setApplicationParameters(span<const uint8_t> value)
496{
497 setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value.data(), value.size()));
498 addOrReplaceParametersDigestComponent();
499 m_wire.reset();
500 return *this;
501}
502
503Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400504Interest::setApplicationParameters(const uint8_t* value, size_t length)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700505{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400506 if (value == nullptr && length != 0) {
Davide Pesavento38912442019-04-06 22:03:39 -0400507 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
508 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400509
Davide Pesaventoa3d809e2022-02-06 11:55:02 -0500510 return setApplicationParameters(make_span(value, length));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700511}
512
513Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400514Interest::setApplicationParameters(ConstBufferPtr value)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700515{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400516 if (value == nullptr) {
Davide Pesavento38912442019-04-06 22:03:39 -0400517 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
518 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400519
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400520 setApplicationParametersInternal(Block(tlv::ApplicationParameters, std::move(value)));
521 addOrReplaceParametersDigestComponent();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700522 m_wire.reset();
523 return *this;
524}
525
526Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400527Interest::unsetApplicationParameters()
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700528{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400529 m_parameters.clear();
530 ssize_t digestIndex = findParametersDigestComponent(getName());
531 if (digestIndex >= 0) {
532 m_name.erase(digestIndex);
533 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700534 m_wire.reset();
535 return *this;
536}
537
Eric Newberry6e262f02020-05-29 23:11:25 -0700538bool
539Interest::isSigned() const noexcept
540{
541 return m_parameters.size() >= 3 &&
542 getSignatureInfo().has_value() &&
543 getSignatureValue().isValid() &&
544 !m_name.empty() &&
545 m_name[-1].type() == tlv::ParametersSha256DigestComponent;
546}
547
548optional<SignatureInfo>
549Interest::getSignatureInfo() const
550{
551 auto blockIt = findFirstParameter(tlv::InterestSignatureInfo);
552 if (blockIt != m_parameters.end()) {
553 return make_optional<SignatureInfo>(*blockIt, SignatureInfo::Type::Interest);
554 }
555 return nullopt;
556}
557
558Interest&
559Interest::setSignatureInfo(const SignatureInfo& info)
560{
561 // Prepend empty ApplicationParameters element if none present
562 if (m_parameters.empty()) {
563 m_parameters.push_back(makeEmptyBlock(tlv::ApplicationParameters));
564 }
565
566 // Find first existing InterestSignatureInfo (if any)
567 auto infoIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
568 return block.type() == tlv::InterestSignatureInfo;
569 });
570
571 Block encodedInfo = info.wireEncode(SignatureInfo::Type::Interest);
572 if (infoIt != m_parameters.end()) {
573 if (*infoIt == encodedInfo) {
574 // New InterestSignatureInfo is the same as the old InterestSignatureInfo
575 return *this;
576 }
577
578 // Replace existing InterestSignatureInfo
579 *infoIt = std::move(encodedInfo);
580 }
581 else {
582 // Place before first InterestSignatureValue element (if any), else at end
583 auto valueIt = findFirstParameter(tlv::InterestSignatureValue);
584 m_parameters.insert(valueIt, std::move(encodedInfo));
585 }
586
587 addOrReplaceParametersDigestComponent();
588 m_wire.reset();
589 return *this;
590}
591
592Block
593Interest::getSignatureValue() const
594{
595 auto blockIt = findFirstParameter(tlv::InterestSignatureValue);
596 if (blockIt != m_parameters.end()) {
597 return *blockIt;
598 }
599 return {};
600}
601
602Interest&
603Interest::setSignatureValue(ConstBufferPtr value)
604{
605 if (value == nullptr) {
606 NDN_THROW(std::invalid_argument("InterestSignatureValue buffer cannot be nullptr"));
607 }
608
609 // Ensure presence of InterestSignatureInfo
610 auto infoIt = findFirstParameter(tlv::InterestSignatureInfo);
611 if (infoIt == m_parameters.end()) {
612 NDN_THROW(Error("InterestSignatureInfo must be present to set InterestSignatureValue"));
613 }
614
615 auto valueIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
616 return block.type() == tlv::InterestSignatureValue;
617 });
618
619 Block valueBlock(tlv::InterestSignatureValue, std::move(value));
620 if (valueIt != m_parameters.end()) {
621 if (*valueIt == valueBlock) {
622 // New InterestSignatureValue is the same as the old InterestSignatureValue
623 return *this;
624 }
625
626 // Replace existing InterestSignatureValue
627 *valueIt = std::move(valueBlock);
628 }
629 else {
630 // Place after first InterestSignatureInfo element
631 valueIt = m_parameters.insert(std::next(infoIt), std::move(valueBlock));
632 }
633
634 // computeParametersDigest needs encoded SignatureValue
635 valueIt->encode();
636
637 addOrReplaceParametersDigestComponent();
638 m_wire.reset();
639 return *this;
640}
641
Eric Newberryb74bbda2020-06-18 19:33:58 -0700642InputBuffers
643Interest::extractSignedRanges() const
644{
645 InputBuffers bufs;
646 bufs.reserve(2); // For Name range and parameters range
647
648 wireEncode();
649
650 // Get Interest name minus any ParametersSha256DigestComponent
Davide Pesavento765abc92021-12-27 00:44:04 -0500651 // Name is guaranteed to be non-empty if wireEncode() does not throw
Eric Newberryb74bbda2020-06-18 19:33:58 -0700652 BOOST_ASSERT(!m_name.empty());
653 if (m_name[-1].type() != tlv::ParametersSha256DigestComponent) {
654 NDN_THROW(Error("Interest Name must end with a ParametersSha256DigestComponent"));
655 }
656
Davide Pesavento765abc92021-12-27 00:44:04 -0500657 bufs.emplace_back(m_name[0].wire(), m_name[-1].wire());
Eric Newberryb74bbda2020-06-18 19:33:58 -0700658
Davide Pesavento765abc92021-12-27 00:44:04 -0500659 // Ensure InterestSignatureInfo element is present
Eric Newberryb74bbda2020-06-18 19:33:58 -0700660 auto sigInfoIt = findFirstParameter(tlv::InterestSignatureInfo);
661 if (sigInfoIt == m_parameters.end()) {
662 NDN_THROW(Error("Interest missing InterestSignatureInfo"));
663 }
664
665 // Get range from ApplicationParameters to InterestSignatureValue
666 // or end of parameters (whichever is first)
667 BOOST_ASSERT(!m_parameters.empty() && m_parameters.begin()->type() == tlv::ApplicationParameters);
Davide Pesavento765abc92021-12-27 00:44:04 -0500668 auto lastSignedIt = std::prev(findFirstParameter(tlv::InterestSignatureValue));
669 // Note: we assume that both iterators point to the same underlying buffer
670 bufs.emplace_back(m_parameters.front().begin(), lastSignedIt->end());
671
Eric Newberryb74bbda2020-06-18 19:33:58 -0700672 return bufs;
673}
674
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400675// ---- ParametersSha256DigestComponent support ----
676
677bool
678Interest::isParametersDigestValid() const
679{
680 ssize_t digestIndex = findParametersDigestComponent(getName());
681 if (digestIndex == -1) {
682 return !hasApplicationParameters();
683 }
684 // cannot be -2 because of the checks in setName() and wireDecode()
685 BOOST_ASSERT(digestIndex >= 0);
686
687 if (!hasApplicationParameters()) {
688 return false;
689 }
690
691 const auto& digestComponent = getName()[digestIndex];
692 auto digest = computeParametersDigest();
693
694 return std::equal(digestComponent.value_begin(), digestComponent.value_end(),
695 digest->begin(), digest->end());
696}
697
698shared_ptr<Buffer>
699Interest::computeParametersDigest() const
700{
701 using namespace security::transform;
702
703 StepSource in;
704 OBufferStream out;
705 in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out);
706
Eric Newberry6e262f02020-05-29 23:11:25 -0700707 for (const auto& block : m_parameters) {
Davide Pesavento765abc92021-12-27 00:44:04 -0500708 in.write({block.wire(), block.size()});
Eric Newberry6e262f02020-05-29 23:11:25 -0700709 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400710 in.end();
711
712 return out.buf();
713}
714
715void
716Interest::addOrReplaceParametersDigestComponent()
717{
718 BOOST_ASSERT(hasApplicationParameters());
719
720 ssize_t digestIndex = findParametersDigestComponent(getName());
721 auto digestComponent = name::Component::fromParametersSha256Digest(computeParametersDigest());
722
723 if (digestIndex == -1) {
724 // no existing digest components, append one
725 m_name.append(std::move(digestComponent));
726 }
727 else {
728 // cannot be -2 because of the checks in setName() and wireDecode()
729 BOOST_ASSERT(digestIndex >= 0);
730 // replace the existing digest component
731 m_name.set(digestIndex, std::move(digestComponent));
732 }
733}
734
735ssize_t
736Interest::findParametersDigestComponent(const Name& name)
737{
738 ssize_t pos = -1;
739 for (ssize_t i = 0; i < static_cast<ssize_t>(name.size()); i++) {
740 if (name[i].isParametersSha256Digest()) {
741 if (pos != -1)
742 return -2;
743 pos = i;
744 }
745 }
746 return pos;
747}
748
Eric Newberry6e262f02020-05-29 23:11:25 -0700749std::vector<Block>::const_iterator
750Interest::findFirstParameter(uint32_t type) const
751{
752 return std::find_if(m_parameters.begin(), m_parameters.end(), [type] (const Block& block) {
753 return block.type() == type;
754 });
755}
756
Junxiao Shi899277a2017-07-07 22:12:12 +0000757// ---- operators ----
758
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700759std::ostream&
760operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700761{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800762 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700763
Alexander Afanasyev84681982014-01-03 13:26:09 -0800764 char delim = '?';
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400765 auto printOne = [&] (const auto&... args) {
766 os << delim;
Alexander Afanasyev84681982014-01-03 13:26:09 -0800767 delim = '&';
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400768 using expand = int[];
769 (void)expand{(os << args, 0)...}; // use a fold expression when we switch to C++17
770 };
771
772 if (interest.getCanBePrefix()) {
773 printOne("CanBePrefix");
Jeff Thompson13e280b2013-12-03 13:12:23 -0800774 }
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400775 if (interest.getMustBeFresh()) {
776 printOne("MustBeFresh");
Alexander Afanasyev84681982014-01-03 13:26:09 -0800777 }
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300778 if (interest.hasNonce()) {
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400779 printOne("Nonce=", interest.getNonce());
780 }
781 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
782 printOne("Lifetime=", interest.getInterestLifetime().count());
783 }
784 if (interest.getHopLimit()) {
785 printOne("HopLimit=", static_cast<unsigned>(*interest.getHopLimit()));
Alexander Afanasyev84681982014-01-03 13:26:09 -0800786 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800787
788 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800789}
790
Junxiao Shi08d07082014-12-03 11:31:44 -0700791} // namespace ndn