blob: bed681a3111acb256298d47af40319e2a941c691 [file] [log] [blame]
Shuo Chenccfbe242014-04-29 23:57:51 +08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevc0e26582017-08-13 21:16:49 -04002/*
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -04003 * Copyright (c) 2014-2022, Regents of the University of California.
Shuo Chenccfbe242014-04-29 23:57:51 +08004 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
Alexander Afanasyev42290b22017-03-09 12:58:29 -080017 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Shuo Chenccfbe242014-04-29 23:57:51 +080018 */
19
Alexander Afanasyev39d98072014-05-04 12:46:29 -070020#include "../src/repo-command-parameter.hpp"
21#include "../src/repo-command-response.hpp"
Shuo Chenccfbe242014-04-29 23:57:51 +080022
23#include <ndn-cxx/face.hpp>
Davide Pesavento75e8d462021-05-16 17:00:42 -040024#include <ndn-cxx/security/interest-signer.hpp>
Shuo Chenccfbe242014-04-29 23:57:51 +080025#include <ndn-cxx/security/key-chain.hpp>
Junxiao Shi959c5b92016-08-23 01:05:27 +000026#include <ndn-cxx/security/signing-helpers.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070027#include <ndn-cxx/util/scheduler.hpp>
Alexander Afanasyevc0e26582017-08-13 21:16:49 -040028
Wentao Shang91fb4f22014-05-20 10:55:22 -070029#include <stdint.h>
Alexander Afanasyevc0e26582017-08-13 21:16:49 -040030#include <stdlib.h>
Davide Pesavento31be3f62019-01-24 23:20:23 -050031#include <unistd.h>
Alexander Afanasyevc0e26582017-08-13 21:16:49 -040032
33#include <fstream>
34#include <iostream>
35#include <string>
36
weijia yuan3aa8d2b2018-03-06 15:35:57 -080037#include <boost/asio.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070038#include <boost/lexical_cast.hpp>
Shuo Chenccfbe242014-04-29 23:57:51 +080039#include <boost/iostreams/operations.hpp>
40#include <boost/iostreams/read.hpp>
41
42namespace repo {
43
44using namespace ndn::time;
45
Wentao Shanga8f3c402014-10-30 14:03:27 -070046using std::shared_ptr;
47using std::make_shared;
48using std::bind;
Wentao Shanga8f3c402014-10-30 14:03:27 -070049
Shuo Chenccfbe242014-04-29 23:57:51 +080050static const uint64_t DEFAULT_BLOCK_SIZE = 1000;
51static const uint64_t DEFAULT_INTEREST_LIFETIME = 4000;
52static const uint64_t DEFAULT_FRESHNESS_PERIOD = 10000;
53static const uint64_t DEFAULT_CHECK_PERIOD = 1000;
Weiqi Shi5822e342014-08-21 20:05:30 -070054static const size_t PRE_SIGN_DATA_COUNT = 11;
Shuo Chenccfbe242014-04-29 23:57:51 +080055
Alexander Afanasyev42290b22017-03-09 12:58:29 -080056class NdnPutFile : boost::noncopyable
Shuo Chenccfbe242014-04-29 23:57:51 +080057{
58public:
59 class Error : public std::runtime_error
60 {
61 public:
Davide Pesavento31be3f62019-01-24 23:20:23 -050062 using std::runtime_error::runtime_error;
Shuo Chenccfbe242014-04-29 23:57:51 +080063 };
64
65 NdnPutFile()
66 : isUnversioned(false)
67 , isSingle(false)
68 , useDigestSha256(false)
69 , freshnessPeriod(DEFAULT_FRESHNESS_PERIOD)
70 , interestLifetime(DEFAULT_INTEREST_LIFETIME)
71 , hasTimeout(false)
72 , timeout(0)
Davide Pesavento31be3f62019-01-24 23:20:23 -050073 , insertStream(nullptr)
Shuo Chenccfbe242014-04-29 23:57:51 +080074 , isVerbose(false)
Shuo Chenccfbe242014-04-29 23:57:51 +080075 , m_scheduler(m_face.getIoService())
76 , m_timestampVersion(toUnixTimestamp(system_clock::now()).count())
77 , m_processId(0)
78 , m_checkPeriod(DEFAULT_CHECK_PERIOD)
79 , m_currentSegmentNo(0)
80 , m_isFinished(false)
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -050081 , m_cmdSigner(m_keyChain)
Shuo Chenccfbe242014-04-29 23:57:51 +080082 {
83 }
84
85 void
86 run();
87
88private:
89 void
90 prepareNextData(uint64_t referenceSegmentNo);
91
92 void
93 startInsertCommand();
94
95 void
Alexander Afanasyev42290b22017-03-09 12:58:29 -080096 onInsertCommandResponse(const ndn::Interest& interest, const ndn::Data& data);
Shuo Chenccfbe242014-04-29 23:57:51 +080097
98 void
99 onInsertCommandTimeout(const ndn::Interest& interest);
100
101 void
102 onInterest(const ndn::Name& prefix, const ndn::Interest& interest);
103
104 void
105 onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest);
106
107 void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700108 onRegisterSuccess(const ndn::Name& prefix);
109
110 void
Shuo Chenccfbe242014-04-29 23:57:51 +0800111 onRegisterFailed(const ndn::Name& prefix, const std::string& reason);
112
113 void
114 stopProcess();
115
116 void
117 signData(ndn::Data& data);
118
119 void
120 startCheckCommand();
121
122 void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800123 onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800124
125 void
126 onCheckCommandTimeout(const ndn::Interest& interest);
127
128 ndn::Interest
129 generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
130 const RepoCommandParameter& commandParameter);
131
132public:
133 bool isUnversioned;
134 bool isSingle;
135 bool useDigestSha256;
136 std::string identityForData;
137 std::string identityForCommand;
138 milliseconds freshnessPeriod;
139 milliseconds interestLifetime;
140 bool hasTimeout;
141 milliseconds timeout;
142 ndn::Name repoPrefix;
143 ndn::Name ndnName;
144 std::istream* insertStream;
145 bool isVerbose;
146
147private:
148 ndn::Face m_face;
149 ndn::Scheduler m_scheduler;
150 ndn::KeyChain m_keyChain;
Shuo Chenccfbe242014-04-29 23:57:51 +0800151 uint64_t m_timestampVersion;
152 uint64_t m_processId;
153 milliseconds m_checkPeriod;
154 size_t m_currentSegmentNo;
155 bool m_isFinished;
156 ndn::Name m_dataPrefix;
157
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400158 std::map<uint64_t, std::shared_ptr<ndn::Data>> m_data;
Davide Pesavento75e8d462021-05-16 17:00:42 -0400159 ndn::security::InterestSigner m_cmdSigner;
Shuo Chenccfbe242014-04-29 23:57:51 +0800160};
161
162void
163NdnPutFile::prepareNextData(uint64_t referenceSegmentNo)
164{
165 // make sure m_data has [referenceSegmentNo, referenceSegmentNo + PRE_SIGN_DATA_COUNT] Data
166 if (m_isFinished)
167 return;
168
169 size_t nDataToPrepare = PRE_SIGN_DATA_COUNT;
170
171 if (!m_data.empty()) {
172 uint64_t maxSegmentNo = m_data.rbegin()->first;
173
174 if (maxSegmentNo - referenceSegmentNo >= nDataToPrepare) {
175 // nothing to prepare
176 return;
177 }
178
179 nDataToPrepare -= maxSegmentNo - referenceSegmentNo;
180 }
181
182 for (size_t i = 0; i < nDataToPrepare && !m_isFinished; ++i) {
183 uint8_t buffer[DEFAULT_BLOCK_SIZE];
Davide Pesavento31be3f62019-01-24 23:20:23 -0500184 auto readSize = boost::iostreams::read(*insertStream,
185 reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
Shuo Chenccfbe242014-04-29 23:57:51 +0800186 if (readSize <= 0) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400187 NDN_THROW(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800188 }
189
Davide Pesavento31be3f62019-01-24 23:20:23 -0500190 auto data = make_shared<ndn::Data>(Name(m_dataPrefix).appendSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800191
192 if (insertStream->peek() == std::istream::traits_type::eof()) {
Davide Pesavento0c139512018-11-03 18:23:38 -0400193 data->setFinalBlock(ndn::name::Component::fromSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800194 m_isFinished = true;
195 }
196
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400197 data->setContent(ndn::make_span(buffer, readSize));
Shuo Chenccfbe242014-04-29 23:57:51 +0800198 data->setFreshnessPeriod(freshnessPeriod);
199 signData(*data);
200
201 m_data.insert(std::make_pair(m_currentSegmentNo, data));
202
203 ++m_currentSegmentNo;
204 }
205}
206
207void
208NdnPutFile::run()
209{
210 m_dataPrefix = ndnName;
211 if (!isUnversioned)
212 m_dataPrefix.appendVersion(m_timestampVersion);
213
214 if (isVerbose)
215 std::cerr << "setInterestFilter for " << m_dataPrefix << std::endl;
Davide Pesavento75e8d462021-05-16 17:00:42 -0400216
Shuo Chenccfbe242014-04-29 23:57:51 +0800217 m_face.setInterestFilter(m_dataPrefix,
218 isSingle ?
Davide Pesavento75e8d462021-05-16 17:00:42 -0400219 bind(&NdnPutFile::onSingleInterest, this, _1, _2) :
220 bind(&NdnPutFile::onInterest, this, _1, _2),
Wentao Shanga8f3c402014-10-30 14:03:27 -0700221 bind(&NdnPutFile::onRegisterSuccess, this, _1),
222 bind(&NdnPutFile::onRegisterFailed, this, _1, _2));
Shuo Chenccfbe242014-04-29 23:57:51 +0800223
Shuo Chenccfbe242014-04-29 23:57:51 +0800224 if (hasTimeout)
Davide Pesavento8891c832019-03-20 23:20:35 -0400225 m_scheduler.schedule(timeout, [this] { stopProcess(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800226
227 m_face.processEvents();
228}
229
230void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700231NdnPutFile::onRegisterSuccess(const Name& prefix)
232{
233 startInsertCommand();
234}
235
236void
Shuo Chenccfbe242014-04-29 23:57:51 +0800237NdnPutFile::startInsertCommand()
238{
239 RepoCommandParameter parameters;
240 parameters.setName(m_dataPrefix);
241 if (!isSingle) {
242 parameters.setStartBlockId(0);
243 }
244
245 ndn::Interest commandInterest = generateCommandInterest(repoPrefix, "insert", parameters);
246 m_face.expressInterest(commandInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700247 bind(&NdnPutFile::onInsertCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800248 bind(&NdnPutFile::onInsertCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700249 bind(&NdnPutFile::onInsertCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800250}
251
252void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400253NdnPutFile::onInsertCommandResponse(const ndn::Interest&, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800254{
255 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500256 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800257 if (statusCode >= 400) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400258 NDN_THROW(Error("insert command failed with code " + std::to_string(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800259 }
260 m_processId = response.getProcessId();
261
Davide Pesavento8891c832019-03-20 23:20:35 -0400262 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800263}
264
265void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400266NdnPutFile::onInsertCommandTimeout(const ndn::Interest&)
Shuo Chenccfbe242014-04-29 23:57:51 +0800267{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400268 NDN_THROW(Error("command response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800269}
270
271void
272NdnPutFile::onInterest(const ndn::Name& prefix, const ndn::Interest& interest)
273{
274 if (interest.getName().size() != prefix.size() + 1) {
275 if (isVerbose) {
276 std::cerr << "Error processing incoming interest " << interest << ": "
277 << "Unrecognized Interest" << std::endl;
278 }
279 return;
280 }
281
282 uint64_t segmentNo;
283 try {
284 ndn::Name::Component segmentComponent = interest.getName().get(prefix.size());
285 segmentNo = segmentComponent.toSegment();
286 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800287 catch (const tlv::Error& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800288 if (isVerbose) {
289 std::cerr << "Error processing incoming interest " << interest << ": "
290 << e.what() << std::endl;
291 }
292 return;
293 }
294
295 prepareNextData(segmentNo);
296
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400297 auto item = m_data.find(segmentNo);
Shuo Chenccfbe242014-04-29 23:57:51 +0800298 if (item == m_data.end()) {
299 if (isVerbose) {
300 std::cerr << "Requested segment [" << segmentNo << "] does not exist" << std::endl;
301 }
302 return;
303 }
304
Weiqi Shi5822e342014-08-21 20:05:30 -0700305 if (m_isFinished) {
306 uint64_t final = m_currentSegmentNo - 1;
Davide Pesavento0c139512018-11-03 18:23:38 -0400307 item->second->setFinalBlock(ndn::name::Component::fromSegment(final));
Weiqi Shi5822e342014-08-21 20:05:30 -0700308 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800309 m_face.put(*item->second);
310}
311
312void
313NdnPutFile::onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest)
314{
315 BOOST_ASSERT(prefix == m_dataPrefix);
316
317 if (prefix != interest.getName()) {
318 if (isVerbose) {
319 std::cerr << "Received unexpected interest " << interest << std::endl;
320 }
321 return;
322 }
323
324 uint8_t buffer[DEFAULT_BLOCK_SIZE];
325 std::streamsize readSize =
326 boost::iostreams::read(*insertStream, reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
327
328 if (readSize <= 0) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400329 NDN_THROW(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800330 }
331
332 if (insertStream->peek() != std::istream::traits_type::eof()) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400333 NDN_THROW(Error("Input data does not fit into one Data packet"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800334 }
335
Davide Pesavento31be3f62019-01-24 23:20:23 -0500336 auto data = make_shared<ndn::Data>(m_dataPrefix);
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400337 data->setContent(ndn::make_span(buffer, readSize));
Weiqi Shi5822e342014-08-21 20:05:30 -0700338 data->setFreshnessPeriod(freshnessPeriod);
339 signData(*data);
340 m_face.put(*data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800341
342 m_isFinished = true;
343}
344
345void
346NdnPutFile::onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
347{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400348 NDN_THROW(Error("onRegisterFailed: " + reason));
Shuo Chenccfbe242014-04-29 23:57:51 +0800349}
350
351void
352NdnPutFile::stopProcess()
353{
354 m_face.getIoService().stop();
355}
356
357void
358NdnPutFile::signData(ndn::Data& data)
359{
360 if (useDigestSha256) {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000361 m_keyChain.sign(data, ndn::signingWithSha256());
Shuo Chenccfbe242014-04-29 23:57:51 +0800362 }
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000363 else if (identityForData.empty())
364 m_keyChain.sign(data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800365 else {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000366 m_keyChain.sign(data, ndn::signingByIdentity(identityForData));
Shuo Chenccfbe242014-04-29 23:57:51 +0800367 }
368}
369
370void
371NdnPutFile::startCheckCommand()
372{
373 ndn::Interest checkInterest = generateCommandInterest(repoPrefix, "insert check",
374 RepoCommandParameter()
375 .setProcessId(m_processId));
376 m_face.expressInterest(checkInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700377 bind(&NdnPutFile::onCheckCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800378 bind(&NdnPutFile::onCheckCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700379 bind(&NdnPutFile::onCheckCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800380}
381
382void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400383NdnPutFile::onCheckCommandResponse(const ndn::Interest&, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800384{
385 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500386 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800387 if (statusCode >= 400) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400388 NDN_THROW(Error("Insert check command failed with code " + std::to_string(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800389 }
390
391 if (m_isFinished) {
392 uint64_t insertCount = response.getInsertNum();
393
394 if (isSingle) {
395 if (insertCount == 1) {
396 m_face.getIoService().stop();
397 return;
398 }
399 }
400 // Technically, the check should not infer, but directly has signal from repo that
401 // write operation has been finished
402
403 if (insertCount == m_currentSegmentNo) {
404 m_face.getIoService().stop();
405 return;
406 }
407 }
408
Davide Pesavento8891c832019-03-20 23:20:35 -0400409 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800410}
411
412void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400413NdnPutFile::onCheckCommandTimeout(const ndn::Interest&)
Shuo Chenccfbe242014-04-29 23:57:51 +0800414{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400415 NDN_THROW(Error("check response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800416}
417
418ndn::Interest
419NdnPutFile::generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
420 const RepoCommandParameter& commandParameter)
421{
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500422 Name cmd = commandPrefix;
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400423 cmd.append(command).append(tlv::GenericNameComponent, commandParameter.wireEncode());
Shuo Chenccfbe242014-04-29 23:57:51 +0800424
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400425 ndn::Interest interest;
426 if (identityForCommand.empty()) {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500427 interest = m_cmdSigner.makeCommandInterest(cmd);
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400428 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800429 else {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500430 interest = m_cmdSigner.makeCommandInterest(cmd, ndn::signingByIdentity(identityForCommand));
Shuo Chenccfbe242014-04-29 23:57:51 +0800431 }
432
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500433 interest.setInterestLifetime(interestLifetime);
Shuo Chenccfbe242014-04-29 23:57:51 +0800434 return interest;
435}
436
437static void
Davide Pesavento31be3f62019-01-24 23:20:23 -0500438usage(const char* programName)
Shuo Chenccfbe242014-04-29 23:57:51 +0800439{
Davide Pesavento31be3f62019-01-24 23:20:23 -0500440 std::cerr << "Usage: "
441 << programName << " [-u] [-s] [-D] [-d] [-i identity] [-I identity] [-x freshness]"
442 " [-l lifetime] [-w timeout] repo-prefix ndn-name filename\n"
443 << "\n"
444 << "Write a file into a repo.\n"
445 << "\n"
446 << " -u: unversioned: do not add a version component\n"
447 << " -s: single: do not add version or segment component, implies -u\n"
448 << " -D: use DigestSha256 signing method instead of SignatureSha256WithRsa\n"
449 << " -i: specify identity used for signing Data\n"
450 << " -I: specify identity used for signing commands\n"
451 << " -x: FreshnessPeriod in milliseconds\n"
452 << " -l: InterestLifetime in milliseconds for each command\n"
453 << " -w: timeout in milliseconds for whole process (default unlimited)\n"
454 << " -v: be verbose\n"
455 << " repo-prefix: repo command prefix\n"
456 << " ndn-name: NDN Name prefix for written Data\n"
457 << " filename: local file name; \"-\" reads from stdin\n"
458 << std::endl;
Shuo Chenccfbe242014-04-29 23:57:51 +0800459}
460
Davide Pesavento31be3f62019-01-24 23:20:23 -0500461static int
Shuo Chenccfbe242014-04-29 23:57:51 +0800462main(int argc, char** argv)
463{
464 NdnPutFile ndnPutFile;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500465
Shuo Chenccfbe242014-04-29 23:57:51 +0800466 int opt;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500467 while ((opt = getopt(argc, argv, "husDi:I:x:l:w:v")) != -1) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800468 switch (opt) {
Davide Pesavento31be3f62019-01-24 23:20:23 -0500469 case 'h':
470 usage(argv[0]);
471 return 0;
Shuo Chenccfbe242014-04-29 23:57:51 +0800472 case 'u':
473 ndnPutFile.isUnversioned = true;
474 break;
475 case 's':
476 ndnPutFile.isSingle = true;
477 break;
478 case 'D':
479 ndnPutFile.useDigestSha256 = true;
480 break;
481 case 'i':
482 ndnPutFile.identityForData = std::string(optarg);
483 break;
484 case 'I':
485 ndnPutFile.identityForCommand = std::string(optarg);
486 break;
487 case 'x':
488 try {
489 ndnPutFile.freshnessPeriod = milliseconds(boost::lexical_cast<uint64_t>(optarg));
490 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800491 catch (const boost::bad_lexical_cast&) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400492 std::cerr << "-x option should be an integer" << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500493 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800494 }
495 break;
496 case 'l':
497 try {
498 ndnPutFile.interestLifetime = milliseconds(boost::lexical_cast<uint64_t>(optarg));
499 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800500 catch (const boost::bad_lexical_cast&) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400501 std::cerr << "-l option should be an integer" << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500502 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800503 }
504 break;
505 case 'w':
506 ndnPutFile.hasTimeout = true;
507 try {
508 ndnPutFile.timeout = milliseconds(boost::lexical_cast<uint64_t>(optarg));
509 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800510 catch (const boost::bad_lexical_cast&) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400511 std::cerr << "-w option should be an integer" << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500512 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800513 }
514 break;
515 case 'v':
516 ndnPutFile.isVerbose = true;
517 break;
Shuo Chenccfbe242014-04-29 23:57:51 +0800518 default:
Davide Pesavento31be3f62019-01-24 23:20:23 -0500519 usage(argv[0]);
520 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800521 }
522 }
523
Davide Pesavento31be3f62019-01-24 23:20:23 -0500524 if (argc != optind + 3) {
525 usage(argv[0]);
526 return 2;
527 }
528
Shuo Chenccfbe242014-04-29 23:57:51 +0800529 argc -= optind;
530 argv += optind;
531
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800532 ndnPutFile.repoPrefix = Name(argv[0]);
533 ndnPutFile.ndnName = Name(argv[1]);
Shuo Chenccfbe242014-04-29 23:57:51 +0800534 if (strcmp(argv[2], "-") == 0) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800535 ndnPutFile.insertStream = &std::cin;
536 ndnPutFile.run();
537 }
538 else {
539 std::ifstream inputFileStream(argv[2], std::ios::in | std::ios::binary);
540 if (!inputFileStream.is_open()) {
541 std::cerr << "ERROR: cannot open " << argv[2] << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500542 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800543 }
544
545 ndnPutFile.insertStream = &inputFileStream;
546 ndnPutFile.run();
547 }
548
549 // ndnPutFile MUST NOT be used anymore because .insertStream is a dangling pointer
550
551 return 0;
552}
553
554} // namespace repo
555
556int
557main(int argc, char** argv)
558{
559 try {
560 return repo::main(argc, argv);
561 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800562 catch (const std::exception& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800563 std::cerr << "ERROR: " << e.what() << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500564 return 1;
Shuo Chenccfbe242014-04-29 23:57:51 +0800565 }
566}