blob: cd802cda9ea0158e0ea9dc8212d34c631bb57827 [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 Pesaventofcd3e442023-03-10 18:44:11 -05003 * Copyright (c) 2013-2023 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
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040043bool Interest::s_autoCheckParametersDigest = true;
Junxiao Shib55e5d32018-07-18 13:32:00 -060044
Junxiao Shi8d3f8342018-04-04 12:46:37 +000045Interest::Interest(const Name& name, time::milliseconds lifetime)
Junxiao Shi2af905b2014-11-27 13:10:54 -070046{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040047 setName(name);
48 setInterestLifetime(lifetime);
Junxiao Shi2af905b2014-11-27 13:10:54 -070049}
50
Junxiao Shi2af905b2014-11-27 13:10:54 -070051Interest::Interest(const Block& wire)
52{
53 wireDecode(wire);
54}
55
Junxiao Shi899277a2017-07-07 22:12:12 +000056// ---- encode and decode ----
Alexander Afanasyev840139f2013-12-28 15:02:50 -080057
Junxiao Shi899277a2017-07-07 22:12:12 +000058template<encoding::Tag TAG>
59size_t
60Interest::wireEncode(EncodingImpl<TAG>& encoder) const
61{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040062 // Interest = INTEREST-TYPE TLV-LENGTH
63 // Name
64 // [CanBePrefix]
65 // [MustBeFresh]
66 // [ForwardingHint]
67 // [Nonce]
68 // [InterestLifetime]
69 // [HopLimit]
70 // [ApplicationParameters [InterestSignature]]
71 // (elements are encoded in reverse order)
72
73 // sanity check of ApplicationParameters and ParametersSha256DigestComponent
74 ssize_t digestIndex = findParametersDigestComponent(getName());
75 BOOST_ASSERT(digestIndex != -2); // guaranteed by the checks in setName() and wireDecode()
76 if (digestIndex == -1) {
77 if (hasApplicationParameters())
78 NDN_THROW(Error("Interest with parameters must have a ParametersSha256DigestComponent"));
79 }
80 else if (!hasApplicationParameters()) {
81 NDN_THROW(Error("Interest without parameters must not have a ParametersSha256DigestComponent"));
82 }
83
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070084 size_t totalLength = 0;
85
Davide Pesaventoadc9aa22019-06-30 19:00:20 -040086 // ApplicationParameters and following elements (in reverse order)
Eric Newberry6e262f02020-05-29 23:11:25 -070087 for (const auto& block : m_parameters | boost::adaptors::reversed) {
Davide Pesaventofbea4fc2022-02-08 07:26:04 -050088 totalLength += prependBlock(encoder, block);
Eric Newberry6e262f02020-05-29 23:11:25 -070089 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070090
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -040091 // HopLimit
92 if (getHopLimit()) {
Davide Pesaventofbea4fc2022-02-08 07:26:04 -050093 totalLength += prependBinaryBlock(encoder, tlv::HopLimit, {*m_hopLimit});
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -040094 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -070095
96 // InterestLifetime
97 if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
Davide Pesavento9c19a392019-04-06 15:07:54 -040098 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::InterestLifetime,
99 static_cast<uint64_t>(getInterestLifetime().count()));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700100 }
101
102 // Nonce
Davide Pesavento53533942020-03-04 23:10:06 -0500103 getNonce(); // if nonce was unset, this generates a fresh nonce
104 BOOST_ASSERT(hasNonce());
Davide Pesaventofbea4fc2022-02-08 07:26:04 -0500105 totalLength += prependBinaryBlock(encoder, tlv::Nonce, *m_nonce);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700106
107 // ForwardingHint
Junxiao Shie4603e12022-01-05 19:12:25 +0000108 if (!m_forwardingHint.empty()) {
109 totalLength += prependNestedBlock(encoder, tlv::ForwardingHint,
110 m_forwardingHint.begin(), m_forwardingHint.end());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700111 }
112
113 // MustBeFresh
114 if (getMustBeFresh()) {
115 totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh);
116 }
117
118 // CanBePrefix
119 if (getCanBePrefix()) {
120 totalLength += prependEmptyBlock(encoder, tlv::CanBePrefix);
121 }
122
123 // Name
124 totalLength += getName().wireEncode(encoder);
125
126 totalLength += encoder.prependVarNumber(totalLength);
127 totalLength += encoder.prependVarNumber(tlv::Interest);
128 return totalLength;
129}
130
Davide Pesavento88a0d812017-08-19 21:31:42 -0400131NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Interest);
Junxiao Shi899277a2017-07-07 22:12:12 +0000132
133const Block&
134Interest::wireEncode() const
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300135{
Junxiao Shi899277a2017-07-07 22:12:12 +0000136 if (m_wire.hasWire())
137 return m_wire;
138
139 EncodingEstimator estimator;
140 size_t estimatedSize = wireEncode(estimator);
141
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400142 EncodingBuffer encoder(estimatedSize, 0);
143 wireEncode(encoder);
Junxiao Shi899277a2017-07-07 22:12:12 +0000144
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400145 const_cast<Interest*>(this)->wireDecode(encoder.block());
Junxiao Shi899277a2017-07-07 22:12:12 +0000146 return m_wire;
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300147}
Alexander Afanasyev840139f2013-12-28 15:02:50 -0800148
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700149void
Junxiao Shi899277a2017-07-07 22:12:12 +0000150Interest::wireDecode(const Block& wire)
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700151{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400152 if (wire.type() != tlv::Interest) {
153 NDN_THROW(Error("Interest", wire.type()));
154 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000155 m_wire = wire;
156 m_wire.parse();
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700157
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400158 // Interest = INTEREST-TYPE TLV-LENGTH
159 // Name
160 // [CanBePrefix]
161 // [MustBeFresh]
162 // [ForwardingHint]
163 // [Nonce]
164 // [InterestLifetime]
165 // [HopLimit]
166 // [ApplicationParameters [InterestSignature]]
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000167
Junxiao Shi8b753a22018-10-24 01:51:40 +0000168 auto element = m_wire.elements_begin();
169 if (element == m_wire.elements_end() || element->type() != tlv::Name) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500170 NDN_THROW(Error("Name element is missing or out of order"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000171 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400172 // decode into a temporary object until we determine that the name is valid, in order
173 // to maintain class invariants and thus provide a basic form of exception safety
174 Name tempName(*element);
175 if (tempName.empty()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500176 NDN_THROW(Error("Name has zero name components"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000177 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400178 ssize_t digestIndex = findParametersDigestComponent(tempName);
179 if (digestIndex == -2) {
180 NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
181 }
182 m_name = std::move(tempName);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000183
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400184 m_canBePrefix = m_mustBeFresh = false;
Junxiao Shie4603e12022-01-05 19:12:25 +0000185 m_forwardingHint.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000186 m_nonce.reset();
187 m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400188 m_hopLimit.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400189 m_parameters.clear();
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000190
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400191 int lastElement = 1; // last recognized element index, in spec order
Junxiao Shi8b753a22018-10-24 01:51:40 +0000192 for (++element; element != m_wire.elements_end(); ++element) {
193 switch (element->type()) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000194 case tlv::CanBePrefix: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700195 if (lastElement >= 2) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500196 NDN_THROW(Error("CanBePrefix element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000197 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000198 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500199 NDN_THROW(Error("CanBePrefix element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000200 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400201 m_canBePrefix = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700202 lastElement = 2;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000203 break;
204 }
205 case tlv::MustBeFresh: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700206 if (lastElement >= 3) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500207 NDN_THROW(Error("MustBeFresh element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000208 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000209 if (element->value_size() != 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500210 NDN_THROW(Error("MustBeFresh element has non-zero TLV-LENGTH"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000211 }
Davide Pesavento0e0b3892019-07-30 21:05:05 -0400212 m_mustBeFresh = true;
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700213 lastElement = 3;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000214 break;
215 }
216 case tlv::ForwardingHint: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700217 if (lastElement >= 4) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500218 NDN_THROW(Error("ForwardingHint element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000219 }
Davide Pesavento90795be2022-11-30 16:26:52 -0500220 // Current format:
221 // ForwardingHint = FORWARDING-HINT-TYPE TLV-LENGTH 1*Name
222 // Previous format, partially supported for backward compatibility:
223 // ForwardingHint = FORWARDING-HINT-TYPE TLV-LENGTH 1*Delegation
224 // Delegation = DELEGATION-TYPE TLV-LENGTH Preference Name
Junxiao Shie4603e12022-01-05 19:12:25 +0000225 element->parse();
226 for (const auto& del : element->elements()) {
227 switch (del.type()) {
228 case tlv::Name:
229 try {
230 m_forwardingHint.emplace_back(del);
231 }
232 catch (const tlv::Error&) {
233 NDN_THROW_NESTED(Error("Invalid Name in ForwardingHint"));
234 }
235 break;
Davide Pesavento90795be2022-11-30 16:26:52 -0500236 case 31: // Delegation
237 // old ForwardingHint format, try to parse the nested Name for compatibility
Junxiao Shie4603e12022-01-05 19:12:25 +0000238 try {
239 del.parse();
240 m_forwardingHint.emplace_back(del.get(tlv::Name));
241 }
242 catch (const tlv::Error&) {
243 NDN_THROW_NESTED(Error("Invalid Name in ForwardingHint.Delegation"));
244 }
245 break;
246 default:
247 if (tlv::isCriticalType(del.type())) {
248 NDN_THROW(Error("Unexpected TLV-TYPE " + to_string(del.type()) + " while decoding ForwardingHint"));
249 }
250 break;
251 }
252 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700253 lastElement = 4;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000254 break;
255 }
256 case tlv::Nonce: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700257 if (lastElement >= 5) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500258 NDN_THROW(Error("Nonce element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000259 }
Davide Pesavento53533942020-03-04 23:10:06 -0500260 if (element->value_size() != Nonce().size()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500261 NDN_THROW(Error("Nonce element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000262 }
Davide Pesavento53533942020-03-04 23:10:06 -0500263 m_nonce.emplace();
264 std::memcpy(m_nonce->data(), element->value(), m_nonce->size());
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700265 lastElement = 5;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000266 break;
267 }
268 case tlv::InterestLifetime: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700269 if (lastElement >= 6) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500270 NDN_THROW(Error("InterestLifetime element is out of order"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000271 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000272 m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700273 lastElement = 6;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000274 break;
275 }
276 case tlv::HopLimit: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700277 if (lastElement >= 7) {
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000278 break; // HopLimit is non-critical, ignore out-of-order appearance
279 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000280 if (element->value_size() != 1) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500281 NDN_THROW(Error("HopLimit element is malformed"));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000282 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400283 m_hopLimit = *element->value();
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700284 lastElement = 7;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000285 break;
286 }
Davide Pesavento9c19a392019-04-06 15:07:54 -0400287 case tlv::ApplicationParameters: {
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700288 if (lastElement >= 8) {
Davide Pesavento9c19a392019-04-06 15:07:54 -0400289 break; // ApplicationParameters is non-critical, ignore out-of-order appearance
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000290 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400291 BOOST_ASSERT(!hasApplicationParameters());
292 m_parameters.push_back(*element);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700293 lastElement = 8;
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000294 break;
295 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400296 default: { // unrecognized element
297 // if the TLV-TYPE is critical, abort decoding
Junxiao Shi8b753a22018-10-24 01:51:40 +0000298 if (tlv::isCriticalType(element->type())) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500299 NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000300 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400301 // if we already encountered ApplicationParameters, store this element as parameter
302 if (hasApplicationParameters()) {
303 m_parameters.push_back(*element);
304 }
305 // otherwise, ignore it
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000306 break;
307 }
308 }
309 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400310
311 if (s_autoCheckParametersDigest && !isParametersDigestValid()) {
312 NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters"));
313 }
Alexander Afanasyevc3932172014-07-10 18:53:56 -0700314}
315
Davide Pesaventoa84f4642017-08-23 16:14:51 -0400316std::string
317Interest::toUri() const
318{
319 std::ostringstream os;
320 os << *this;
321 return os.str();
322}
323
Junxiao Shi899277a2017-07-07 22:12:12 +0000324// ---- matching ----
325
Alexander Afanasyev84681982014-01-03 13:26:09 -0800326bool
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700327Interest::matchesData(const Data& data) const
328{
Junxiao Shi42c23622014-07-03 00:55:11 -0700329 size_t interestNameLength = m_name.size();
330 const Name& dataName = data.getName();
331 size_t fullNameLength = dataName.size() + 1;
332
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000333 // check Name and CanBePrefix
Junxiao Shi42c23622014-07-03 00:55:11 -0700334 if (interestNameLength == fullNameLength) {
Alexander Afanasyev56860f52014-11-07 11:51:17 -0800335 if (m_name.get(-1).isImplicitSha256Digest()) {
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000336 if (m_name != data.getFullName()) {
Junxiao Shi42c23622014-07-03 00:55:11 -0700337 return false;
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000338 }
Junxiao Shi42c23622014-07-03 00:55:11 -0700339 }
340 else {
341 // Interest Name is same length as Data full Name, but last component isn't digest
342 // so there's no possibility of matching
343 return false;
344 }
345 }
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000346 else if (getCanBePrefix() ? !m_name.isPrefixOf(dataName) : (m_name != dataName)) {
347 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700348 }
349
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000350 // check MustBeFresh
351 if (getMustBeFresh() && data.getFreshnessPeriod() <= 0_ms) {
352 return false;
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700353 }
354
355 return true;
356}
357
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800358bool
359Interest::matchesInterest(const Interest& other) const
360{
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000361 return getName() == other.getName() &&
362 getCanBePrefix() == other.getCanBePrefix() &&
363 getMustBeFresh() == other.getMustBeFresh();
Alexander Afanasyev1013fd02017-01-03 13:19:03 -0800364}
365
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400366// ---- field accessors and modifiers ----
367
368Interest&
369Interest::setName(const Name& name)
370{
371 ssize_t digestIndex = findParametersDigestComponent(name);
372 if (digestIndex == -2) {
373 NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent"));
374 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400375
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400376 if (name != m_name) {
377 m_name = name;
378 if (hasApplicationParameters()) {
379 addOrReplaceParametersDigestComponent();
380 }
381 m_wire.reset();
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400382 }
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400383 return *this;
384}
385
386Interest&
Junxiao Shie4603e12022-01-05 19:12:25 +0000387Interest::setForwardingHint(std::vector<Name> value)
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400388{
Junxiao Shie4603e12022-01-05 19:12:25 +0000389 m_forwardingHint = std::move(value);
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400390 m_wire.reset();
391 return *this;
392}
Junxiao Shi899277a2017-07-07 22:12:12 +0000393
Davide Pesavento53533942020-03-04 23:10:06 -0500394static auto
395generateNonce()
396{
397 uint32_t r = random::generateWord32();
398 Interest::Nonce n;
399 std::memcpy(n.data(), &r, sizeof(r));
400 return n;
401}
402
403Interest::Nonce
Junxiao Shi899277a2017-07-07 22:12:12 +0000404Interest::getNonce() const
405{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400406 if (!hasNonce()) {
Davide Pesavento53533942020-03-04 23:10:06 -0500407 m_nonce = generateNonce();
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400408 m_wire.reset();
Junxiao Shic2ac5d22017-07-17 22:18:31 +0000409 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000410 return *m_nonce;
Junxiao Shi899277a2017-07-07 22:12:12 +0000411}
412
413Interest&
Davide Pesaventof6b45892023-03-13 15:00:51 -0400414Interest::setNonce(std::optional<Interest::Nonce> nonce)
Junxiao Shi899277a2017-07-07 22:12:12 +0000415{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400416 if (nonce != m_nonce) {
417 m_nonce = nonce;
418 m_wire.reset();
419 }
Junxiao Shi899277a2017-07-07 22:12:12 +0000420 return *this;
421}
422
423void
424Interest::refreshNonce()
425{
426 if (!hasNonce())
427 return;
428
Davide Pesavento53533942020-03-04 23:10:06 -0500429 auto oldNonce = *m_nonce;
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400430 while (m_nonce == oldNonce)
Davide Pesavento53533942020-03-04 23:10:06 -0500431 m_nonce = generateNonce();
Junxiao Shi899277a2017-07-07 22:12:12 +0000432
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400433 m_wire.reset();
Junxiao Shi899277a2017-07-07 22:12:12 +0000434}
435
Eric Newberryb555b002017-05-17 00:30:44 -0700436Interest&
Junxiao Shi8d3f8342018-04-04 12:46:37 +0000437Interest::setInterestLifetime(time::milliseconds lifetime)
Eric Newberryb555b002017-05-17 00:30:44 -0700438{
Davide Pesaventofccb2dc2019-02-09 01:02:35 -0500439 if (lifetime < 0_ms) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500440 NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0"));
Eric Newberryb555b002017-05-17 00:30:44 -0700441 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400442
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400443 if (lifetime != m_interestLifetime) {
444 m_interestLifetime = lifetime;
445 m_wire.reset();
446 }
Eric Newberryb555b002017-05-17 00:30:44 -0700447 return *this;
448}
449
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000450Interest&
Davide Pesaventof6b45892023-03-13 15:00:51 -0400451Interest::setHopLimit(std::optional<uint8_t> hopLimit)
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000452{
Davide Pesavento2b0cc7b2019-07-14 16:50:04 -0400453 if (hopLimit != m_hopLimit) {
454 m_hopLimit = hopLimit;
455 m_wire.reset();
456 }
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000457 return *this;
458}
459
Davide Pesavento487e3d32022-05-05 18:06:23 -0400460Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400461Interest::setApplicationParametersInternal(Block parameters)
462{
463 parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest()
464 if (m_parameters.empty()) {
465 m_parameters.push_back(std::move(parameters));
466 }
467 else {
468 BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters);
469 m_parameters[0] = std::move(parameters);
470 }
Davide Pesavento487e3d32022-05-05 18:06:23 -0400471
472 addOrReplaceParametersDigestComponent();
473 m_wire.reset();
474 return *this;
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400475}
476
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700477Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400478Interest::setApplicationParameters(const Block& parameters)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700479{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400480 if (!parameters.isValid()) {
Davide Pesavento81bd6962020-06-17 16:03:23 -0400481 NDN_THROW(std::invalid_argument("ApplicationParameters block must be valid"));
Davide Pesavento38912442019-04-06 22:03:39 -0400482 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400483
484 if (parameters.type() == tlv::ApplicationParameters) {
Davide Pesavento487e3d32022-05-05 18:06:23 -0400485 return setApplicationParametersInternal(parameters);
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700486 }
487 else {
Davide Pesavento487e3d32022-05-05 18:06:23 -0400488 return setApplicationParametersInternal({tlv::ApplicationParameters, parameters});
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700489 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700490}
491
492Interest&
Davide Pesaventoa3d809e2022-02-06 11:55:02 -0500493Interest::setApplicationParameters(span<const uint8_t> value)
494{
Davide Pesavento487e3d32022-05-05 18:06:23 -0400495 return setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value));
Davide Pesaventoa3d809e2022-02-06 11:55:02 -0500496}
497
498Interest&
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400499Interest::setApplicationParameters(ConstBufferPtr value)
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700500{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400501 if (value == nullptr) {
Davide Pesavento38912442019-04-06 22:03:39 -0400502 NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
503 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400504
Davide Pesavento487e3d32022-05-05 18:06:23 -0400505 return setApplicationParametersInternal({tlv::ApplicationParameters, std::move(value)});
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700506}
507
508Interest&
Davide Pesavento9c19a392019-04-06 15:07:54 -0400509Interest::unsetApplicationParameters()
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700510{
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400511 m_parameters.clear();
512 ssize_t digestIndex = findParametersDigestComponent(getName());
513 if (digestIndex >= 0) {
514 m_name.erase(digestIndex);
515 }
Arthi Padmanabhanb38664e2018-07-18 11:13:12 -0700516 m_wire.reset();
517 return *this;
518}
519
Eric Newberry6e262f02020-05-29 23:11:25 -0700520bool
521Interest::isSigned() const noexcept
522{
523 return m_parameters.size() >= 3 &&
524 getSignatureInfo().has_value() &&
525 getSignatureValue().isValid() &&
526 !m_name.empty() &&
527 m_name[-1].type() == tlv::ParametersSha256DigestComponent;
528}
529
Davide Pesaventof6b45892023-03-13 15:00:51 -0400530std::optional<SignatureInfo>
Eric Newberry6e262f02020-05-29 23:11:25 -0700531Interest::getSignatureInfo() const
532{
533 auto blockIt = findFirstParameter(tlv::InterestSignatureInfo);
534 if (blockIt != m_parameters.end()) {
Davide Pesaventof6b45892023-03-13 15:00:51 -0400535 return std::make_optional<SignatureInfo>(*blockIt, SignatureInfo::Type::Interest);
Eric Newberry6e262f02020-05-29 23:11:25 -0700536 }
Davide Pesaventof6b45892023-03-13 15:00:51 -0400537 return std::nullopt;
Eric Newberry6e262f02020-05-29 23:11:25 -0700538}
539
540Interest&
541Interest::setSignatureInfo(const SignatureInfo& info)
542{
543 // Prepend empty ApplicationParameters element if none present
544 if (m_parameters.empty()) {
545 m_parameters.push_back(makeEmptyBlock(tlv::ApplicationParameters));
546 }
547
548 // Find first existing InterestSignatureInfo (if any)
549 auto infoIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
550 return block.type() == tlv::InterestSignatureInfo;
551 });
552
553 Block encodedInfo = info.wireEncode(SignatureInfo::Type::Interest);
554 if (infoIt != m_parameters.end()) {
555 if (*infoIt == encodedInfo) {
556 // New InterestSignatureInfo is the same as the old InterestSignatureInfo
557 return *this;
558 }
559
560 // Replace existing InterestSignatureInfo
561 *infoIt = std::move(encodedInfo);
562 }
563 else {
564 // Place before first InterestSignatureValue element (if any), else at end
565 auto valueIt = findFirstParameter(tlv::InterestSignatureValue);
566 m_parameters.insert(valueIt, std::move(encodedInfo));
567 }
568
569 addOrReplaceParametersDigestComponent();
570 m_wire.reset();
571 return *this;
572}
573
574Block
575Interest::getSignatureValue() const
576{
577 auto blockIt = findFirstParameter(tlv::InterestSignatureValue);
578 if (blockIt != m_parameters.end()) {
579 return *blockIt;
580 }
581 return {};
582}
583
584Interest&
Davide Pesavento487e3d32022-05-05 18:06:23 -0400585Interest::setSignatureValueInternal(Block sigValue)
Eric Newberry6e262f02020-05-29 23:11:25 -0700586{
Eric Newberry6e262f02020-05-29 23:11:25 -0700587 // Ensure presence of InterestSignatureInfo
588 auto infoIt = findFirstParameter(tlv::InterestSignatureInfo);
589 if (infoIt == m_parameters.end()) {
590 NDN_THROW(Error("InterestSignatureInfo must be present to set InterestSignatureValue"));
591 }
592
593 auto valueIt = std::find_if(m_parameters.begin(), m_parameters.end(), [] (const Block& block) {
594 return block.type() == tlv::InterestSignatureValue;
595 });
596
Eric Newberry6e262f02020-05-29 23:11:25 -0700597 if (valueIt != m_parameters.end()) {
Davide Pesavento487e3d32022-05-05 18:06:23 -0400598 if (*valueIt == sigValue) {
Eric Newberry6e262f02020-05-29 23:11:25 -0700599 // New InterestSignatureValue is the same as the old InterestSignatureValue
600 return *this;
601 }
602
603 // Replace existing InterestSignatureValue
Davide Pesavento487e3d32022-05-05 18:06:23 -0400604 *valueIt = std::move(sigValue);
Eric Newberry6e262f02020-05-29 23:11:25 -0700605 }
606 else {
607 // Place after first InterestSignatureInfo element
Davide Pesavento487e3d32022-05-05 18:06:23 -0400608 valueIt = m_parameters.insert(std::next(infoIt), std::move(sigValue));
Eric Newberry6e262f02020-05-29 23:11:25 -0700609 }
610
Davide Pesavento487e3d32022-05-05 18:06:23 -0400611 // computeParametersDigest needs encoded InterestSignatureValue
Eric Newberry6e262f02020-05-29 23:11:25 -0700612 valueIt->encode();
613
614 addOrReplaceParametersDigestComponent();
615 m_wire.reset();
616 return *this;
617}
618
Davide Pesavento487e3d32022-05-05 18:06:23 -0400619Interest&
620Interest::setSignatureValue(span<const uint8_t> value)
621{
622 return setSignatureValueInternal(makeBinaryBlock(tlv::InterestSignatureValue, value));
623}
624
625Interest&
626Interest::setSignatureValue(ConstBufferPtr value)
627{
628 if (value == nullptr) {
629 NDN_THROW(std::invalid_argument("InterestSignatureValue buffer cannot be nullptr"));
630 }
631
632 return setSignatureValueInternal({tlv::InterestSignatureValue, std::move(value)});
633}
634
Eric Newberryb74bbda2020-06-18 19:33:58 -0700635InputBuffers
636Interest::extractSignedRanges() const
637{
638 InputBuffers bufs;
639 bufs.reserve(2); // For Name range and parameters range
640
641 wireEncode();
642
643 // Get Interest name minus any ParametersSha256DigestComponent
Davide Pesavento765abc92021-12-27 00:44:04 -0500644 // Name is guaranteed to be non-empty if wireEncode() does not throw
Eric Newberryb74bbda2020-06-18 19:33:58 -0700645 BOOST_ASSERT(!m_name.empty());
646 if (m_name[-1].type() != tlv::ParametersSha256DigestComponent) {
647 NDN_THROW(Error("Interest Name must end with a ParametersSha256DigestComponent"));
648 }
649
Davide Pesavento258d51a2022-02-27 21:26:28 -0500650 bufs.emplace_back(m_name[0].data(), m_name[-1].data());
Eric Newberryb74bbda2020-06-18 19:33:58 -0700651
Davide Pesavento765abc92021-12-27 00:44:04 -0500652 // Ensure InterestSignatureInfo element is present
Eric Newberryb74bbda2020-06-18 19:33:58 -0700653 auto sigInfoIt = findFirstParameter(tlv::InterestSignatureInfo);
654 if (sigInfoIt == m_parameters.end()) {
655 NDN_THROW(Error("Interest missing InterestSignatureInfo"));
656 }
657
658 // Get range from ApplicationParameters to InterestSignatureValue
659 // or end of parameters (whichever is first)
660 BOOST_ASSERT(!m_parameters.empty() && m_parameters.begin()->type() == tlv::ApplicationParameters);
Davide Pesavento765abc92021-12-27 00:44:04 -0500661 auto lastSignedIt = std::prev(findFirstParameter(tlv::InterestSignatureValue));
662 // Note: we assume that both iterators point to the same underlying buffer
663 bufs.emplace_back(m_parameters.front().begin(), lastSignedIt->end());
664
Eric Newberryb74bbda2020-06-18 19:33:58 -0700665 return bufs;
666}
667
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400668// ---- ParametersSha256DigestComponent support ----
669
670bool
671Interest::isParametersDigestValid() const
672{
673 ssize_t digestIndex = findParametersDigestComponent(getName());
674 if (digestIndex == -1) {
675 return !hasApplicationParameters();
676 }
677 // cannot be -2 because of the checks in setName() and wireDecode()
678 BOOST_ASSERT(digestIndex >= 0);
679
680 if (!hasApplicationParameters()) {
681 return false;
682 }
683
684 const auto& digestComponent = getName()[digestIndex];
685 auto digest = computeParametersDigest();
686
687 return std::equal(digestComponent.value_begin(), digestComponent.value_end(),
688 digest->begin(), digest->end());
689}
690
691shared_ptr<Buffer>
692Interest::computeParametersDigest() const
693{
694 using namespace security::transform;
695
696 StepSource in;
697 OBufferStream out;
698 in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out);
699
Eric Newberry6e262f02020-05-29 23:11:25 -0700700 for (const auto& block : m_parameters) {
Davide Pesavento258d51a2022-02-27 21:26:28 -0500701 in.write(block);
Eric Newberry6e262f02020-05-29 23:11:25 -0700702 }
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400703 in.end();
704
705 return out.buf();
706}
707
708void
709Interest::addOrReplaceParametersDigestComponent()
710{
711 BOOST_ASSERT(hasApplicationParameters());
712
713 ssize_t digestIndex = findParametersDigestComponent(getName());
Davide Pesavento21ee8992022-02-25 20:46:04 -0500714 name::Component digestComponent(tlv::ParametersSha256DigestComponent, computeParametersDigest());
Davide Pesaventoadc9aa22019-06-30 19:00:20 -0400715
716 if (digestIndex == -1) {
717 // no existing digest components, append one
718 m_name.append(std::move(digestComponent));
719 }
720 else {
721 // cannot be -2 because of the checks in setName() and wireDecode()
722 BOOST_ASSERT(digestIndex >= 0);
723 // replace the existing digest component
724 m_name.set(digestIndex, std::move(digestComponent));
725 }
726}
727
728ssize_t
729Interest::findParametersDigestComponent(const Name& name)
730{
731 ssize_t pos = -1;
732 for (ssize_t i = 0; i < static_cast<ssize_t>(name.size()); i++) {
733 if (name[i].isParametersSha256Digest()) {
734 if (pos != -1)
735 return -2;
736 pos = i;
737 }
738 }
739 return pos;
740}
741
Eric Newberry6e262f02020-05-29 23:11:25 -0700742std::vector<Block>::const_iterator
743Interest::findFirstParameter(uint32_t type) const
744{
745 return std::find_if(m_parameters.begin(), m_parameters.end(), [type] (const Block& block) {
746 return block.type() == type;
747 });
748}
749
Junxiao Shi899277a2017-07-07 22:12:12 +0000750// ---- operators ----
751
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700752std::ostream&
753operator<<(std::ostream& os, const Interest& interest)
Jeff Thompsonfe556862013-07-09 13:52:55 -0700754{
Alexander Afanasyev84681982014-01-03 13:26:09 -0800755 os << interest.getName();
Jeff Thompsonfe556862013-07-09 13:52:55 -0700756
Alexander Afanasyev84681982014-01-03 13:26:09 -0800757 char delim = '?';
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400758 auto printOne = [&] (const auto&... args) {
759 os << delim;
Alexander Afanasyev84681982014-01-03 13:26:09 -0800760 delim = '&';
Davide Pesaventofcd3e442023-03-10 18:44:11 -0500761 (os << ... << args);
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400762 };
763
764 if (interest.getCanBePrefix()) {
765 printOne("CanBePrefix");
Jeff Thompson13e280b2013-12-03 13:12:23 -0800766 }
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400767 if (interest.getMustBeFresh()) {
768 printOne("MustBeFresh");
Alexander Afanasyev84681982014-01-03 13:26:09 -0800769 }
Alexander Afanasyeve881e932014-06-08 14:47:03 +0300770 if (interest.hasNonce()) {
Davide Pesavento2fdb2742019-07-31 23:03:35 -0400771 printOne("Nonce=", interest.getNonce());
772 }
773 if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
774 printOne("Lifetime=", interest.getInterestLifetime().count());
775 }
776 if (interest.getHopLimit()) {
777 printOne("HopLimit=", static_cast<unsigned>(*interest.getHopLimit()));
Alexander Afanasyev84681982014-01-03 13:26:09 -0800778 }
Alexander Afanasyev84681982014-01-03 13:26:09 -0800779
780 return os;
Jeff Thompson13e280b2013-12-03 13:12:23 -0800781}
782
Junxiao Shi08d07082014-12-03 11:31:44 -0700783} // namespace ndn