blob: c1dc23d8b3c66176f3a4c793858b3d33147434f6 [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 Pesavento0f830802018-01-16 23:58:58 -05003 * Copyright (c) 2013-2018 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.
Alexander Afanasyev5fa9e9a2013-12-24 19:45:07 -080020 */
21
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080022#include "interest.hpp"
Junxiao Shiaf8eeea2014-03-31 20:10:56 -070023#include "data.hpp"
Yingdi Yubf6a2812014-06-17 15:32:11 -070024#include "security/digest-sha256.hpp"
Junxiao Shi899277a2017-07-07 22:12:12 +000025#include "security/signature-sha256-with-rsa.hpp"
Junxiao Shiaf8eeea2014-03-31 20:10:56 -070026
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070027#include "boost-test.hpp"
Alexander Afanasyeve4f8c3b2016-06-23 16:03:48 -070028#include "identity-management-fixture.hpp"
Alexander Afanasyev5fa9e9a2013-12-24 19:45:07 -080029
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -080030namespace ndn {
Alexander Afanasyev90164962014-03-06 08:29:59 +000031namespace tests {
Alexander Afanasyev5fa9e9a2013-12-24 19:45:07 -080032
Junxiao Shi899277a2017-07-07 22:12:12 +000033BOOST_AUTO_TEST_SUITE(TestInterest)
Alexander Afanasyev5fa9e9a2013-12-24 19:45:07 -080034
Junxiao Shi899277a2017-07-07 22:12:12 +000035// ---- constructor, encode, decode ----
36
37BOOST_AUTO_TEST_CASE(DefaultConstructor)
38{
39 Interest i;
40 BOOST_CHECK_EQUAL(i.getName(), "/");
41 BOOST_CHECK(i.getSelectors().empty());
Junxiao Shi2dd711d2017-07-21 13:40:52 +000042 BOOST_CHECK_EQUAL(i.hasNonce(), false);
Junxiao Shi899277a2017-07-07 22:12:12 +000043 BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
Junxiao Shi899277a2017-07-07 22:12:12 +000044}
45
46BOOST_AUTO_TEST_CASE(EncodeDecodeBasic)
47{
48 const uint8_t WIRE[] = {
49 0x05, 0x1c, // Interest
50 0x07, 0x14, // Name
51 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // NameComponent
52 0x08, 0x03, 0x6e, 0x64, 0x6e, // NameComponent
53 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // NameComponent
54 0x0a, 0x04, // Nonce
55 0x01, 0x00, 0x00, 0x00
56 };
57
58 Interest i1("/local/ndn/prefix");
59 i1.setNonce(1);
60 Block wire1 = i1.wireEncode();
61 BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
62
63 Interest i2(wire1);
64 BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix");
65 BOOST_CHECK(i2.getSelectors().empty());
66 BOOST_CHECK_EQUAL(i2.getNonce(), 1);
67 BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
68
69 BOOST_CHECK_EQUAL(i1, i2);
70}
71
72BOOST_AUTO_TEST_CASE(EncodeDecodeFull)
73{
74 const uint8_t WIRE[] = {
Junxiao Shi9c154cb2017-07-07 22:14:54 +000075 0x05, 0x31, // Interest
Junxiao Shi899277a2017-07-07 22:12:12 +000076 0x07, 0x14, // Name
77 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // NameComponent
78 0x08, 0x03, 0x6e, 0x64, 0x6e, // NameComponent
79 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // NameComponent
80 0x09, 0x03, // Selectors
81 0x0d, 0x01, 0x01, // MinSuffixComponents
82 0x0a, 0x04, // Nonce
83 0x01, 0x00, 0x00, 0x00,
84 0x0c, 0x02, // InterestLifetime
Junxiao Shi9c154cb2017-07-07 22:14:54 +000085 0x03, 0xe8,
86 0x1e, 0x0a, // ForwardingHint
87 0x1f, 0x08, // Delegation
88 0x1e, 0x01, 0x01, // Preference=1
89 0x07, 0x03, 0x08, 0x01, 0x41 // Name=/A
Junxiao Shi899277a2017-07-07 22:12:12 +000090 };
Junxiao Shi899277a2017-07-07 22:12:12 +000091
92 Interest i1;
93 i1.setName("/local/ndn/prefix");
94 i1.setMinSuffixComponents(1);
95 i1.setNonce(1);
Davide Pesavento0f830802018-01-16 23:58:58 -050096 i1.setInterestLifetime(1000_ms);
Junxiao Shi9c154cb2017-07-07 22:14:54 +000097 i1.setForwardingHint({{1, "/A"}});
Junxiao Shi899277a2017-07-07 22:12:12 +000098 Block wire1 = i1.wireEncode();
99 BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
100
101 Interest i2(wire1);
102 BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix");
103 BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), 1);
104 BOOST_CHECK_EQUAL(i2.getNonce(), 1);
Davide Pesavento0f830802018-01-16 23:58:58 -0500105 BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 1000_ms);
Junxiao Shi9c154cb2017-07-07 22:14:54 +0000106 BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{1, "/A"}}));
Junxiao Shi899277a2017-07-07 22:12:12 +0000107
108 BOOST_CHECK_EQUAL(i1, i2);
109}
110
Junxiao Shi899277a2017-07-07 22:12:12 +0000111BOOST_AUTO_TEST_CASE(WireDecodeReset) // checks wireDecode resets all fields
112{
113 Interest i1;
114 i1.setName("/test");
115 i1.setMinSuffixComponents(100);
116 i1.setNonce(10);
Davide Pesavento0f830802018-01-16 23:58:58 -0500117 i1.setInterestLifetime(10_s);
Junxiao Shi899277a2017-07-07 22:12:12 +0000118
119 Interest i2(i1.wireEncode());
120 BOOST_CHECK_EQUAL(i2.getName().toUri(), "/test");
Davide Pesavento0f830802018-01-16 23:58:58 -0500121 BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 10_s);
Junxiao Shi899277a2017-07-07 22:12:12 +0000122 BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), 100);
123 BOOST_CHECK_EQUAL(i2.getNonce(), 10);
Junxiao Shi899277a2017-07-07 22:12:12 +0000124
125 i2.wireDecode(Interest().wireEncode());
126 BOOST_CHECK_EQUAL(i2.getName().toUri(), "/");
127 BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
128 BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), -1);
129 BOOST_WARN_NE(i2.getNonce(), 10);
Junxiao Shi899277a2017-07-07 22:12:12 +0000130}
131
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000132BOOST_AUTO_TEST_CASE(DecodeNoName)
133{
134 Block b(tlv::Interest);
135 b.push_back(makeBinaryBlock(tlv::Nonce, "FISH", 4));
136 b.encode();
137
138 Interest i;
139 BOOST_CHECK_THROW(i.wireDecode(b), tlv::Error);
140}
141
142BOOST_AUTO_TEST_CASE(DecodeNoNonce)
143{
144 Block b(tlv::Interest);
145 b.push_back(Name("/YvzNKtPWh").wireEncode());
146 b.encode();
147
148 Interest i;
149 BOOST_CHECK_THROW(i.wireDecode(b), tlv::Error);
150}
151
152BOOST_AUTO_TEST_CASE(DecodeBadNonce)
153{
154 Block b(tlv::Interest);
155 b.push_back(Name("/BJzEHVxDJ").wireEncode());
156 b.push_back(makeBinaryBlock(tlv::Nonce, "SKY", 3));
157 b.encode();
158
159 Interest i;
160 BOOST_CHECK_THROW(i.wireDecode(b), tlv::Error);
161}
162
Junxiao Shi899277a2017-07-07 22:12:12 +0000163// ---- matching ----
164
165BOOST_AUTO_TEST_CASE(MatchesData)
166{
167 Interest interest;
168 interest.setName("ndn:/A")
169 .setMinSuffixComponents(2)
170 .setMaxSuffixComponents(2)
171 .setPublisherPublicKeyLocator(KeyLocator("ndn:/B"))
172 .setExclude(Exclude().excludeAfter(name::Component("J")));
173
174 Data data("ndn:/A/D");
175 SignatureSha256WithRsa signature(KeyLocator("ndn:/B"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000176 signature.setValue(encoding::makeEmptyBlock(tlv::SignatureValue));
Junxiao Shi899277a2017-07-07 22:12:12 +0000177 data.setSignature(signature);
178 data.wireEncode();
179 BOOST_CHECK_EQUAL(interest.matchesData(data), true);
180
181 Data data1 = data;
182 data1.setName("ndn:/A"); // violates MinSuffixComponents
183 data1.wireEncode();
184 BOOST_CHECK_EQUAL(interest.matchesData(data1), false);
185
186 Interest interest1 = interest;
187 interest1.setMinSuffixComponents(1);
188 BOOST_CHECK_EQUAL(interest1.matchesData(data1), true);
189
190 Data data2 = data;
191 data2.setName("ndn:/A/E/F"); // violates MaxSuffixComponents
192 data2.wireEncode();
193 BOOST_CHECK_EQUAL(interest.matchesData(data2), false);
194
195 Interest interest2 = interest;
196 interest2.setMaxSuffixComponents(3);
197 BOOST_CHECK_EQUAL(interest2.matchesData(data2), true);
198
199 Data data3 = data;
200 SignatureSha256WithRsa signature3(KeyLocator("ndn:/G")); // violates PublisherPublicKeyLocator
Junxiao Shidb7464d2017-07-13 03:11:17 +0000201 signature3.setValue(encoding::makeEmptyBlock(tlv::SignatureValue));
Junxiao Shi899277a2017-07-07 22:12:12 +0000202 data3.setSignature(signature3);
203 data3.wireEncode();
204 BOOST_CHECK_EQUAL(interest.matchesData(data3), false);
205
206 Interest interest3 = interest;
207 interest3.setPublisherPublicKeyLocator(KeyLocator("ndn:/G"));
208 BOOST_CHECK_EQUAL(interest3.matchesData(data3), true);
209
210 Data data4 = data;
211 DigestSha256 signature4; // violates PublisherPublicKeyLocator
Junxiao Shidb7464d2017-07-13 03:11:17 +0000212 signature4.setValue(encoding::makeEmptyBlock(tlv::SignatureValue));
Junxiao Shi899277a2017-07-07 22:12:12 +0000213 data4.setSignature(signature4);
214 data4.wireEncode();
215 BOOST_CHECK_EQUAL(interest.matchesData(data4), false);
216
217 Interest interest4 = interest;
218 interest4.setPublisherPublicKeyLocator(KeyLocator());
219 BOOST_CHECK_EQUAL(interest4.matchesData(data4), true);
220
221 Data data5 = data;
222 data5.setName("ndn:/A/J"); // violates Exclude
223 data5.wireEncode();
224 BOOST_CHECK_EQUAL(interest.matchesData(data5), false);
225
226 Interest interest5 = interest;
227 interest5.setExclude(Exclude().excludeAfter(name::Component("K")));
228 BOOST_CHECK_EQUAL(interest5.matchesData(data5), true);
229
230 Data data6 = data;
231 data6.setName("ndn:/H/I"); // violates Name
232 data6.wireEncode();
233 BOOST_CHECK_EQUAL(interest.matchesData(data6), false);
234
235 Data data7 = data;
236 data7.setName("ndn:/A/B");
237 data7.wireEncode();
238
Junxiao Shidb7464d2017-07-13 03:11:17 +0000239 Interest interest7("/A/B/sha256digest=54008e240a7eea2714a161dfddf0dd6ced223b3856e9da96792151e180f3b128");
Junxiao Shi899277a2017-07-07 22:12:12 +0000240 BOOST_CHECK_EQUAL(interest7.matchesData(data7), true);
241
242 Interest interest7b("/A/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
243 BOOST_CHECK_EQUAL(interest7b.matchesData(data7), false); // violates implicit digest
244}
245
246BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(MatchesInterest, 1)
247BOOST_AUTO_TEST_CASE(MatchesInterest)
248{
249 Interest interest;
250 interest
251 .setName("/A")
252 .setMinSuffixComponents(2)
253 .setMaxSuffixComponents(2)
254 .setPublisherPublicKeyLocator(KeyLocator("/B"))
255 .setExclude(Exclude().excludeAfter(name::Component("J")))
256 .setNonce(10)
Davide Pesavento0f830802018-01-16 23:58:58 -0500257 .setInterestLifetime(5_s)
Junxiao Shid701e5b2017-07-26 01:30:41 +0000258 .setForwardingHint({{1, "/H"}});
Junxiao Shi899277a2017-07-07 22:12:12 +0000259
260 Interest other;
261 BOOST_CHECK_EQUAL(interest.matchesInterest(other), false);
262
263 other.setName(interest.getName());
264 BOOST_CHECK_EQUAL(interest.matchesInterest(other), false);
265
266 other.setSelectors(interest.getSelectors());
267 BOOST_CHECK_EQUAL(interest.matchesInterest(other), false); // will match until #3162 implemented
268
Junxiao Shid701e5b2017-07-26 01:30:41 +0000269 other.setForwardingHint({{1, "/H"}});
Junxiao Shi899277a2017-07-07 22:12:12 +0000270 BOOST_CHECK_EQUAL(interest.matchesInterest(other), true);
271
272 other.setNonce(200);
273 BOOST_CHECK_EQUAL(interest.matchesInterest(other), true);
274
Davide Pesavento0f830802018-01-16 23:58:58 -0500275 other.setInterestLifetime(5_h);
Junxiao Shi899277a2017-07-07 22:12:12 +0000276 BOOST_CHECK_EQUAL(interest.matchesInterest(other), true);
Junxiao Shi899277a2017-07-07 22:12:12 +0000277}
278
279// ---- field accessors ----
280
281BOOST_AUTO_TEST_CASE(GetNonce)
282{
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000283 unique_ptr<Interest> i1, i2;
Junxiao Shi899277a2017-07-07 22:12:12 +0000284
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000285 // getNonce automatically assigns a random Nonce.
286 // It's possible to assign the same Nonce to two Interest, but it's unlikely to get 100 pairs of
287 // same Nonces in a row.
Junxiao Shi899277a2017-07-07 22:12:12 +0000288 int nIterations = 0;
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000289 uint32_t nonce1 = 0, nonce2 = 0;
Junxiao Shi899277a2017-07-07 22:12:12 +0000290 do {
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000291 i1 = make_unique<Interest>();
292 nonce1 = i1->getNonce();
293 i2 = make_unique<Interest>();
294 nonce2 = i2->getNonce();
Junxiao Shi899277a2017-07-07 22:12:12 +0000295 }
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000296 while (nonce1 == nonce2 && ++nIterations < 100);
297 BOOST_CHECK_NE(nonce1, nonce2);
298 BOOST_CHECK(i1->hasNonce());
299 BOOST_CHECK(i2->hasNonce());
Junxiao Shi899277a2017-07-07 22:12:12 +0000300
301 // Once a Nonce is assigned, it should not change.
Junxiao Shi2dd711d2017-07-21 13:40:52 +0000302 BOOST_CHECK_EQUAL(i1->getNonce(), nonce1);
303}
304
305BOOST_AUTO_TEST_CASE(SetNonce)
306{
307 Interest i1("/A");
308 i1.setNonce(1);
309 i1.wireEncode();
310 BOOST_CHECK_EQUAL(i1.getNonce(), 1);
311
312 Interest i2(i1);
313 BOOST_CHECK_EQUAL(i2.getNonce(), 1);
314
315 i2.setNonce(2);
316 BOOST_CHECK_EQUAL(i2.getNonce(), 2);
317 BOOST_CHECK_EQUAL(i1.getNonce(), 1); // should not affect i1 Nonce (Bug #4168)
Junxiao Shi899277a2017-07-07 22:12:12 +0000318}
319
320BOOST_AUTO_TEST_CASE(RefreshNonce)
321{
322 Interest i;
323 BOOST_CHECK(!i.hasNonce());
324 i.refreshNonce();
325 BOOST_CHECK(!i.hasNonce());
326
327 i.setNonce(1);
328 BOOST_CHECK(i.hasNonce());
329 i.refreshNonce();
330 BOOST_CHECK(i.hasNonce());
331 BOOST_CHECK_NE(i.getNonce(), 1);
332}
333
334BOOST_AUTO_TEST_CASE(SetInterestLifetime)
335{
336 BOOST_CHECK_THROW(Interest("/A", time::milliseconds(-1)), std::invalid_argument);
Davide Pesavento0f830802018-01-16 23:58:58 -0500337 BOOST_CHECK_NO_THROW(Interest("/A", 0_ms));
Junxiao Shi899277a2017-07-07 22:12:12 +0000338
339 Interest i("/local/ndn/prefix");
340 i.setNonce(1);
341 BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
342 BOOST_CHECK_THROW(i.setInterestLifetime(time::milliseconds(-1)), std::invalid_argument);
343 BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
Davide Pesavento0f830802018-01-16 23:58:58 -0500344 i.setInterestLifetime(0_ms);
345 BOOST_CHECK_EQUAL(i.getInterestLifetime(), 0_ms);
346 i.setInterestLifetime(1_ms);
347 BOOST_CHECK_EQUAL(i.getInterestLifetime(), 1_ms);
Junxiao Shi899277a2017-07-07 22:12:12 +0000348}
349
Junxiao Shib2a70332017-07-07 22:15:03 +0000350BOOST_AUTO_TEST_CASE(ModifyForwardingHint)
351{
352 Interest i;
353 i.setForwardingHint({{1, "/A"}});
354 i.wireEncode();
355 BOOST_CHECK(i.hasWire());
356
357 i.modifyForwardingHint([] (DelegationList& fh) { fh.insert(2, "/B"); });
358 BOOST_CHECK(!i.hasWire());
359 BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{1, "/A"}, {2, "/B"}}));
360}
361
Junxiao Shi899277a2017-07-07 22:12:12 +0000362// ---- operators ----
363
364BOOST_AUTO_TEST_CASE(Equality)
365{
366 Interest a;
367 Interest b;
368
369 // if nonce is not set, it would be set to a random value
370 a.setNonce(1);
371 b.setNonce(1);
372
373 BOOST_CHECK_EQUAL(a == b, true);
374 BOOST_CHECK_EQUAL(a != b, false);
375
376 // compare Name
377 a.setName("/A");
378 BOOST_CHECK_EQUAL(a == b, false);
379 BOOST_CHECK_EQUAL(a != b, true);
380
381 b.setName("/B");
382 BOOST_CHECK_EQUAL(a == b, false);
383 BOOST_CHECK_EQUAL(a != b, true);
384
385 b.setName("/A");
386 BOOST_CHECK_EQUAL(a == b, true);
387 BOOST_CHECK_EQUAL(a != b, false);
388
389 // compare Selectors
390 a.setChildSelector(1);
391 BOOST_CHECK_EQUAL(a == b, false);
392 BOOST_CHECK_EQUAL(a != b, true);
393
394 b.setChildSelector(1);
395 BOOST_CHECK_EQUAL(a == b, true);
396 BOOST_CHECK_EQUAL(a != b, false);
397
398 // compare Nonce
399 a.setNonce(100);
400 BOOST_CHECK_EQUAL(a == b, false);
401 BOOST_CHECK_EQUAL(a != b, true);
402
403 b.setNonce(100);
404 BOOST_CHECK_EQUAL(a == b, true);
405 BOOST_CHECK_EQUAL(a != b, false);
406
407 // compare InterestLifetime
Davide Pesavento0f830802018-01-16 23:58:58 -0500408 a.setInterestLifetime(10_s);
Junxiao Shi899277a2017-07-07 22:12:12 +0000409 BOOST_CHECK_EQUAL(a == b, false);
410 BOOST_CHECK_EQUAL(a != b, true);
411
Davide Pesavento0f830802018-01-16 23:58:58 -0500412 b.setInterestLifetime(10_s);
Junxiao Shi899277a2017-07-07 22:12:12 +0000413 BOOST_CHECK_EQUAL(a == b, true);
414 BOOST_CHECK_EQUAL(a != b, false);
415
Junxiao Shid701e5b2017-07-26 01:30:41 +0000416 // compare ForwardingHint
417 a.setForwardingHint({{1, "/H"}});
Junxiao Shi899277a2017-07-07 22:12:12 +0000418 BOOST_CHECK_EQUAL(a == b, false);
419 BOOST_CHECK_EQUAL(a != b, true);
420
Junxiao Shid701e5b2017-07-26 01:30:41 +0000421 b.setForwardingHint({{1, "/H"}});
Junxiao Shi899277a2017-07-07 22:12:12 +0000422 BOOST_CHECK_EQUAL(a == b, true);
423 BOOST_CHECK_EQUAL(a != b, false);
424}
425
Davide Pesaventoeee3e822016-11-26 19:19:34 +0100426BOOST_AUTO_TEST_SUITE_END() // TestInterest
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -0800427
Alexander Afanasyev90164962014-03-06 08:29:59 +0000428} // namespace tests
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -0800429} // namespace ndn