blob: 94fffa23064dc76937705162b7d83d2a2cccbdf9 [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 Pesavento31be3f62019-01-24 23:20:23 -05003 * Copyright (c) 2014-2019, 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>
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -050024#include <ndn-cxx/security/command-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
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800158 using DataContainer = std::map<uint64_t, shared_ptr<ndn::Data>>;
Shuo Chenccfbe242014-04-29 23:57:51 +0800159 DataContainer m_data;
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500160 ndn::security::CommandInterestSigner m_cmdSigner;
Shuo Chenccfbe242014-04-29 23:57:51 +0800161};
162
163void
164NdnPutFile::prepareNextData(uint64_t referenceSegmentNo)
165{
166 // make sure m_data has [referenceSegmentNo, referenceSegmentNo + PRE_SIGN_DATA_COUNT] Data
167 if (m_isFinished)
168 return;
169
170 size_t nDataToPrepare = PRE_SIGN_DATA_COUNT;
171
172 if (!m_data.empty()) {
173 uint64_t maxSegmentNo = m_data.rbegin()->first;
174
175 if (maxSegmentNo - referenceSegmentNo >= nDataToPrepare) {
176 // nothing to prepare
177 return;
178 }
179
180 nDataToPrepare -= maxSegmentNo - referenceSegmentNo;
181 }
182
183 for (size_t i = 0; i < nDataToPrepare && !m_isFinished; ++i) {
184 uint8_t buffer[DEFAULT_BLOCK_SIZE];
Davide Pesavento31be3f62019-01-24 23:20:23 -0500185 auto readSize = boost::iostreams::read(*insertStream,
186 reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
Shuo Chenccfbe242014-04-29 23:57:51 +0800187 if (readSize <= 0) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800188 BOOST_THROW_EXCEPTION(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800189 }
190
Davide Pesavento31be3f62019-01-24 23:20:23 -0500191 auto data = make_shared<ndn::Data>(Name(m_dataPrefix).appendSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800192
193 if (insertStream->peek() == std::istream::traits_type::eof()) {
Davide Pesavento0c139512018-11-03 18:23:38 -0400194 data->setFinalBlock(ndn::name::Component::fromSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800195 m_isFinished = true;
196 }
197
198 data->setContent(buffer, readSize);
199 data->setFreshnessPeriod(freshnessPeriod);
200 signData(*data);
201
202 m_data.insert(std::make_pair(m_currentSegmentNo, data));
203
204 ++m_currentSegmentNo;
205 }
206}
207
208void
209NdnPutFile::run()
210{
211 m_dataPrefix = ndnName;
212 if (!isUnversioned)
213 m_dataPrefix.appendVersion(m_timestampVersion);
214
215 if (isVerbose)
216 std::cerr << "setInterestFilter for " << m_dataPrefix << std::endl;
217 m_face.setInterestFilter(m_dataPrefix,
218 isSingle ?
Wentao Shanga8f3c402014-10-30 14:03:27 -0700219 bind(&NdnPutFile::onSingleInterest, this, _1, _2)
220 :
221 bind(&NdnPutFile::onInterest, this, _1, _2),
222 bind(&NdnPutFile::onRegisterSuccess, this, _1),
223 bind(&NdnPutFile::onRegisterFailed, this, _1, _2));
Shuo Chenccfbe242014-04-29 23:57:51 +0800224
Shuo Chenccfbe242014-04-29 23:57:51 +0800225 if (hasTimeout)
Davide Pesavento8891c832019-03-20 23:20:35 -0400226 m_scheduler.schedule(timeout, [this] { stopProcess(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800227
228 m_face.processEvents();
229}
230
231void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700232NdnPutFile::onRegisterSuccess(const Name& prefix)
233{
234 startInsertCommand();
235}
236
237void
Shuo Chenccfbe242014-04-29 23:57:51 +0800238NdnPutFile::startInsertCommand()
239{
240 RepoCommandParameter parameters;
241 parameters.setName(m_dataPrefix);
242 if (!isSingle) {
243 parameters.setStartBlockId(0);
244 }
245
246 ndn::Interest commandInterest = generateCommandInterest(repoPrefix, "insert", parameters);
247 m_face.expressInterest(commandInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700248 bind(&NdnPutFile::onInsertCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800249 bind(&NdnPutFile::onInsertCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700250 bind(&NdnPutFile::onInsertCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800251}
252
253void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800254NdnPutFile::onInsertCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800255{
256 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500257 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800258 if (statusCode >= 400) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800259 BOOST_THROW_EXCEPTION(Error("insert command failed with code " +
260 boost::lexical_cast<std::string>(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800261 }
262 m_processId = response.getProcessId();
263
Davide Pesavento8891c832019-03-20 23:20:35 -0400264 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800265}
266
267void
268NdnPutFile::onInsertCommandTimeout(const ndn::Interest& interest)
269{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800270 BOOST_THROW_EXCEPTION(Error("command response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800271}
272
273void
274NdnPutFile::onInterest(const ndn::Name& prefix, const ndn::Interest& interest)
275{
276 if (interest.getName().size() != prefix.size() + 1) {
277 if (isVerbose) {
278 std::cerr << "Error processing incoming interest " << interest << ": "
279 << "Unrecognized Interest" << std::endl;
280 }
281 return;
282 }
283
284 uint64_t segmentNo;
285 try {
286 ndn::Name::Component segmentComponent = interest.getName().get(prefix.size());
287 segmentNo = segmentComponent.toSegment();
288 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800289 catch (const tlv::Error& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800290 if (isVerbose) {
291 std::cerr << "Error processing incoming interest " << interest << ": "
292 << e.what() << std::endl;
293 }
294 return;
295 }
296
297 prepareNextData(segmentNo);
298
299 DataContainer::iterator item = m_data.find(segmentNo);
300 if (item == m_data.end()) {
301 if (isVerbose) {
302 std::cerr << "Requested segment [" << segmentNo << "] does not exist" << std::endl;
303 }
304 return;
305 }
306
Weiqi Shi5822e342014-08-21 20:05:30 -0700307 if (m_isFinished) {
308 uint64_t final = m_currentSegmentNo - 1;
Davide Pesavento0c139512018-11-03 18:23:38 -0400309 item->second->setFinalBlock(ndn::name::Component::fromSegment(final));
Weiqi Shi5822e342014-08-21 20:05:30 -0700310 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800311 m_face.put(*item->second);
312}
313
314void
315NdnPutFile::onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest)
316{
317 BOOST_ASSERT(prefix == m_dataPrefix);
318
319 if (prefix != interest.getName()) {
320 if (isVerbose) {
321 std::cerr << "Received unexpected interest " << interest << std::endl;
322 }
323 return;
324 }
325
326 uint8_t buffer[DEFAULT_BLOCK_SIZE];
327 std::streamsize readSize =
328 boost::iostreams::read(*insertStream, reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
329
330 if (readSize <= 0) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800331 BOOST_THROW_EXCEPTION(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800332 }
333
334 if (insertStream->peek() != std::istream::traits_type::eof()) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800335 BOOST_THROW_EXCEPTION(Error("Input data does not fit into one Data packet"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800336 }
337
Davide Pesavento31be3f62019-01-24 23:20:23 -0500338 auto data = make_shared<ndn::Data>(m_dataPrefix);
Weiqi Shi5822e342014-08-21 20:05:30 -0700339 data->setContent(buffer, readSize);
340 data->setFreshnessPeriod(freshnessPeriod);
341 signData(*data);
342 m_face.put(*data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800343
344 m_isFinished = true;
345}
346
347void
348NdnPutFile::onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
349{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800350 BOOST_THROW_EXCEPTION(Error("onRegisterFailed: " + reason));
Shuo Chenccfbe242014-04-29 23:57:51 +0800351}
352
353void
354NdnPutFile::stopProcess()
355{
356 m_face.getIoService().stop();
357}
358
359void
360NdnPutFile::signData(ndn::Data& data)
361{
362 if (useDigestSha256) {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000363 m_keyChain.sign(data, ndn::signingWithSha256());
Shuo Chenccfbe242014-04-29 23:57:51 +0800364 }
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000365 else if (identityForData.empty())
366 m_keyChain.sign(data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800367 else {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000368 m_keyChain.sign(data, ndn::signingByIdentity(identityForData));
Shuo Chenccfbe242014-04-29 23:57:51 +0800369 }
370}
371
372void
373NdnPutFile::startCheckCommand()
374{
375 ndn::Interest checkInterest = generateCommandInterest(repoPrefix, "insert check",
376 RepoCommandParameter()
377 .setProcessId(m_processId));
378 m_face.expressInterest(checkInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700379 bind(&NdnPutFile::onCheckCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800380 bind(&NdnPutFile::onCheckCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700381 bind(&NdnPutFile::onCheckCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800382}
383
384void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800385NdnPutFile::onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800386{
387 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500388 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800389 if (statusCode >= 400) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800390 BOOST_THROW_EXCEPTION(Error("Insert check command failed with code: " +
391 boost::lexical_cast<std::string>(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800392 }
393
394 if (m_isFinished) {
395 uint64_t insertCount = response.getInsertNum();
396
397 if (isSingle) {
398 if (insertCount == 1) {
399 m_face.getIoService().stop();
400 return;
401 }
402 }
403 // Technically, the check should not infer, but directly has signal from repo that
404 // write operation has been finished
405
406 if (insertCount == m_currentSegmentNo) {
407 m_face.getIoService().stop();
408 return;
409 }
410 }
411
Davide Pesavento8891c832019-03-20 23:20:35 -0400412 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800413}
414
415void
416NdnPutFile::onCheckCommandTimeout(const ndn::Interest& interest)
417{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800418 BOOST_THROW_EXCEPTION(Error("check response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800419}
420
421ndn::Interest
422NdnPutFile::generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
423 const RepoCommandParameter& commandParameter)
424{
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500425 Name cmd = commandPrefix;
426 cmd
427 .append(command)
428 .append(commandParameter.wireEncode());
429 ndn::Interest interest;
Shuo Chenccfbe242014-04-29 23:57:51 +0800430
431 if (identityForCommand.empty())
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500432 interest = m_cmdSigner.makeCommandInterest(cmd);
Shuo Chenccfbe242014-04-29 23:57:51 +0800433 else {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500434 interest = m_cmdSigner.makeCommandInterest(cmd, ndn::signingByIdentity(identityForCommand));
Shuo Chenccfbe242014-04-29 23:57:51 +0800435 }
436
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500437 interest.setInterestLifetime(interestLifetime);
Shuo Chenccfbe242014-04-29 23:57:51 +0800438 return interest;
439}
440
441static void
Davide Pesavento31be3f62019-01-24 23:20:23 -0500442usage(const char* programName)
Shuo Chenccfbe242014-04-29 23:57:51 +0800443{
Davide Pesavento31be3f62019-01-24 23:20:23 -0500444 std::cerr << "Usage: "
445 << programName << " [-u] [-s] [-D] [-d] [-i identity] [-I identity] [-x freshness]"
446 " [-l lifetime] [-w timeout] repo-prefix ndn-name filename\n"
447 << "\n"
448 << "Write a file into a repo.\n"
449 << "\n"
450 << " -u: unversioned: do not add a version component\n"
451 << " -s: single: do not add version or segment component, implies -u\n"
452 << " -D: use DigestSha256 signing method instead of SignatureSha256WithRsa\n"
453 << " -i: specify identity used for signing Data\n"
454 << " -I: specify identity used for signing commands\n"
455 << " -x: FreshnessPeriod in milliseconds\n"
456 << " -l: InterestLifetime in milliseconds for each command\n"
457 << " -w: timeout in milliseconds for whole process (default unlimited)\n"
458 << " -v: be verbose\n"
459 << " repo-prefix: repo command prefix\n"
460 << " ndn-name: NDN Name prefix for written Data\n"
461 << " filename: local file name; \"-\" reads from stdin\n"
462 << std::endl;
Shuo Chenccfbe242014-04-29 23:57:51 +0800463}
464
Davide Pesavento31be3f62019-01-24 23:20:23 -0500465static int
Shuo Chenccfbe242014-04-29 23:57:51 +0800466main(int argc, char** argv)
467{
468 NdnPutFile ndnPutFile;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500469
Shuo Chenccfbe242014-04-29 23:57:51 +0800470 int opt;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500471 while ((opt = getopt(argc, argv, "husDi:I:x:l:w:v")) != -1) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800472 switch (opt) {
Davide Pesavento31be3f62019-01-24 23:20:23 -0500473 case 'h':
474 usage(argv[0]);
475 return 0;
Shuo Chenccfbe242014-04-29 23:57:51 +0800476 case 'u':
477 ndnPutFile.isUnversioned = true;
478 break;
479 case 's':
480 ndnPutFile.isSingle = true;
481 break;
482 case 'D':
483 ndnPutFile.useDigestSha256 = true;
484 break;
485 case 'i':
486 ndnPutFile.identityForData = std::string(optarg);
487 break;
488 case 'I':
489 ndnPutFile.identityForCommand = std::string(optarg);
490 break;
491 case 'x':
492 try {
493 ndnPutFile.freshnessPeriod = milliseconds(boost::lexical_cast<uint64_t>(optarg));
494 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800495 catch (const boost::bad_lexical_cast&) {
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800496 std::cerr << "-x option should be an integer" << std::endl;;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500497 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800498 }
499 break;
500 case 'l':
501 try {
502 ndnPutFile.interestLifetime = milliseconds(boost::lexical_cast<uint64_t>(optarg));
503 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800504 catch (const boost::bad_lexical_cast&) {
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800505 std::cerr << "-l option should be an integer" << std::endl;;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500506 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800507 }
508 break;
509 case 'w':
510 ndnPutFile.hasTimeout = true;
511 try {
512 ndnPutFile.timeout = milliseconds(boost::lexical_cast<uint64_t>(optarg));
513 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800514 catch (const boost::bad_lexical_cast&) {
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800515 std::cerr << "-w option should be an integer" << std::endl;;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500516 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800517 }
518 break;
519 case 'v':
520 ndnPutFile.isVerbose = true;
521 break;
Shuo Chenccfbe242014-04-29 23:57:51 +0800522 default:
Davide Pesavento31be3f62019-01-24 23:20:23 -0500523 usage(argv[0]);
524 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800525 }
526 }
527
Davide Pesavento31be3f62019-01-24 23:20:23 -0500528 if (argc != optind + 3) {
529 usage(argv[0]);
530 return 2;
531 }
532
Shuo Chenccfbe242014-04-29 23:57:51 +0800533 argc -= optind;
534 argv += optind;
535
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800536 ndnPutFile.repoPrefix = Name(argv[0]);
537 ndnPutFile.ndnName = Name(argv[1]);
Shuo Chenccfbe242014-04-29 23:57:51 +0800538 if (strcmp(argv[2], "-") == 0) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800539 ndnPutFile.insertStream = &std::cin;
540 ndnPutFile.run();
541 }
542 else {
543 std::ifstream inputFileStream(argv[2], std::ios::in | std::ios::binary);
544 if (!inputFileStream.is_open()) {
545 std::cerr << "ERROR: cannot open " << argv[2] << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500546 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800547 }
548
549 ndnPutFile.insertStream = &inputFileStream;
550 ndnPutFile.run();
551 }
552
553 // ndnPutFile MUST NOT be used anymore because .insertStream is a dangling pointer
554
555 return 0;
556}
557
558} // namespace repo
559
560int
561main(int argc, char** argv)
562{
563 try {
564 return repo::main(argc, argv);
565 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800566 catch (const std::exception& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800567 std::cerr << "ERROR: " << e.what() << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500568 return 1;
Shuo Chenccfbe242014-04-29 23:57:51 +0800569 }
570}