blob: 97dbd77e49268c55a36140b0eca32e45a919eb61 [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 Pesavento0c139512018-11-03 18:23:38 -04003 * Copyright (c) 2014-2018, 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>
31
32#include <fstream>
33#include <iostream>
34#include <string>
35
weijia yuan3aa8d2b2018-03-06 15:35:57 -080036#include <boost/asio.hpp>
Shuo Chenccfbe242014-04-29 23:57:51 +080037#include <boost/filesystem.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;
49using std::placeholders::_1;
50using std::placeholders::_2;
51
Shuo Chenccfbe242014-04-29 23:57:51 +080052static const uint64_t DEFAULT_BLOCK_SIZE = 1000;
53static const uint64_t DEFAULT_INTEREST_LIFETIME = 4000;
54static const uint64_t DEFAULT_FRESHNESS_PERIOD = 10000;
55static const uint64_t DEFAULT_CHECK_PERIOD = 1000;
Weiqi Shi5822e342014-08-21 20:05:30 -070056static const size_t PRE_SIGN_DATA_COUNT = 11;
Shuo Chenccfbe242014-04-29 23:57:51 +080057
Alexander Afanasyev42290b22017-03-09 12:58:29 -080058class NdnPutFile : boost::noncopyable
Shuo Chenccfbe242014-04-29 23:57:51 +080059{
60public:
61 class Error : public std::runtime_error
62 {
63 public:
64 explicit
65 Error(const std::string& what)
66 : std::runtime_error(what)
67 {
68 }
69 };
70
71 NdnPutFile()
72 : isUnversioned(false)
73 , isSingle(false)
74 , useDigestSha256(false)
75 , freshnessPeriod(DEFAULT_FRESHNESS_PERIOD)
76 , interestLifetime(DEFAULT_INTEREST_LIFETIME)
77 , hasTimeout(false)
78 , timeout(0)
79 , insertStream(0)
80 , isVerbose(false)
Shuo Chenccfbe242014-04-29 23:57:51 +080081 , m_scheduler(m_face.getIoService())
82 , m_timestampVersion(toUnixTimestamp(system_clock::now()).count())
83 , m_processId(0)
84 , m_checkPeriod(DEFAULT_CHECK_PERIOD)
85 , m_currentSegmentNo(0)
86 , m_isFinished(false)
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -050087 , m_cmdSigner(m_keyChain)
Shuo Chenccfbe242014-04-29 23:57:51 +080088 {
89 }
90
91 void
92 run();
93
94private:
95 void
96 prepareNextData(uint64_t referenceSegmentNo);
97
98 void
99 startInsertCommand();
100
101 void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800102 onInsertCommandResponse(const ndn::Interest& interest, const ndn::Data& data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800103
104 void
105 onInsertCommandTimeout(const ndn::Interest& interest);
106
107 void
108 onInterest(const ndn::Name& prefix, const ndn::Interest& interest);
109
110 void
111 onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest);
112
113 void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700114 onRegisterSuccess(const ndn::Name& prefix);
115
116 void
Shuo Chenccfbe242014-04-29 23:57:51 +0800117 onRegisterFailed(const ndn::Name& prefix, const std::string& reason);
118
119 void
120 stopProcess();
121
122 void
123 signData(ndn::Data& data);
124
125 void
126 startCheckCommand();
127
128 void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800129 onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800130
131 void
132 onCheckCommandTimeout(const ndn::Interest& interest);
133
134 ndn::Interest
135 generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
136 const RepoCommandParameter& commandParameter);
137
138public:
139 bool isUnversioned;
140 bool isSingle;
141 bool useDigestSha256;
142 std::string identityForData;
143 std::string identityForCommand;
144 milliseconds freshnessPeriod;
145 milliseconds interestLifetime;
146 bool hasTimeout;
147 milliseconds timeout;
148 ndn::Name repoPrefix;
149 ndn::Name ndnName;
150 std::istream* insertStream;
151 bool isVerbose;
152
153private:
154 ndn::Face m_face;
155 ndn::Scheduler m_scheduler;
156 ndn::KeyChain m_keyChain;
Shuo Chenccfbe242014-04-29 23:57:51 +0800157 uint64_t m_timestampVersion;
158 uint64_t m_processId;
159 milliseconds m_checkPeriod;
160 size_t m_currentSegmentNo;
161 bool m_isFinished;
162 ndn::Name m_dataPrefix;
163
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800164 using DataContainer = std::map<uint64_t, shared_ptr<ndn::Data>>;
Shuo Chenccfbe242014-04-29 23:57:51 +0800165 DataContainer m_data;
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500166 ndn::security::CommandInterestSigner m_cmdSigner;
Shuo Chenccfbe242014-04-29 23:57:51 +0800167};
168
169void
170NdnPutFile::prepareNextData(uint64_t referenceSegmentNo)
171{
172 // make sure m_data has [referenceSegmentNo, referenceSegmentNo + PRE_SIGN_DATA_COUNT] Data
173 if (m_isFinished)
174 return;
175
176 size_t nDataToPrepare = PRE_SIGN_DATA_COUNT;
177
178 if (!m_data.empty()) {
179 uint64_t maxSegmentNo = m_data.rbegin()->first;
180
181 if (maxSegmentNo - referenceSegmentNo >= nDataToPrepare) {
182 // nothing to prepare
183 return;
184 }
185
186 nDataToPrepare -= maxSegmentNo - referenceSegmentNo;
187 }
188
189 for (size_t i = 0; i < nDataToPrepare && !m_isFinished; ++i) {
190 uint8_t buffer[DEFAULT_BLOCK_SIZE];
191
192 std::streamsize readSize =
193 boost::iostreams::read(*insertStream, reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
194
195 if (readSize <= 0) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800196 BOOST_THROW_EXCEPTION(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800197 }
198
Wentao Shanga8f3c402014-10-30 14:03:27 -0700199 shared_ptr<ndn::Data> data =
200 make_shared<ndn::Data>(Name(m_dataPrefix)
Shuo Chenccfbe242014-04-29 23:57:51 +0800201 .appendSegment(m_currentSegmentNo));
202
203 if (insertStream->peek() == std::istream::traits_type::eof()) {
Davide Pesavento0c139512018-11-03 18:23:38 -0400204 data->setFinalBlock(ndn::name::Component::fromSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800205 m_isFinished = true;
206 }
207
208 data->setContent(buffer, readSize);
209 data->setFreshnessPeriod(freshnessPeriod);
210 signData(*data);
211
212 m_data.insert(std::make_pair(m_currentSegmentNo, data));
213
214 ++m_currentSegmentNo;
215 }
216}
217
218void
219NdnPutFile::run()
220{
221 m_dataPrefix = ndnName;
222 if (!isUnversioned)
223 m_dataPrefix.appendVersion(m_timestampVersion);
224
225 if (isVerbose)
226 std::cerr << "setInterestFilter for " << m_dataPrefix << std::endl;
227 m_face.setInterestFilter(m_dataPrefix,
228 isSingle ?
Wentao Shanga8f3c402014-10-30 14:03:27 -0700229 bind(&NdnPutFile::onSingleInterest, this, _1, _2)
230 :
231 bind(&NdnPutFile::onInterest, this, _1, _2),
232 bind(&NdnPutFile::onRegisterSuccess, this, _1),
233 bind(&NdnPutFile::onRegisterFailed, this, _1, _2));
Shuo Chenccfbe242014-04-29 23:57:51 +0800234
Weiqi Shi5822e342014-08-21 20:05:30 -0700235
Shuo Chenccfbe242014-04-29 23:57:51 +0800236 if (hasTimeout)
Wentao Shanga8f3c402014-10-30 14:03:27 -0700237 m_scheduler.scheduleEvent(timeout, bind(&NdnPutFile::stopProcess, this));
Shuo Chenccfbe242014-04-29 23:57:51 +0800238
239 m_face.processEvents();
240}
241
242void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700243NdnPutFile::onRegisterSuccess(const Name& prefix)
244{
245 startInsertCommand();
246}
247
248void
Shuo Chenccfbe242014-04-29 23:57:51 +0800249NdnPutFile::startInsertCommand()
250{
251 RepoCommandParameter parameters;
252 parameters.setName(m_dataPrefix);
253 if (!isSingle) {
254 parameters.setStartBlockId(0);
255 }
256
257 ndn::Interest commandInterest = generateCommandInterest(repoPrefix, "insert", parameters);
258 m_face.expressInterest(commandInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700259 bind(&NdnPutFile::onInsertCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800260 bind(&NdnPutFile::onInsertCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700261 bind(&NdnPutFile::onInsertCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800262}
263
264void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800265NdnPutFile::onInsertCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800266{
267 RepoCommandResponse response(data.getContent().blockFromValue());
weijia yuan82cf9142018-10-21 12:25:02 -0700268 int statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800269 if (statusCode >= 400) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800270 BOOST_THROW_EXCEPTION(Error("insert command failed with code " +
271 boost::lexical_cast<std::string>(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800272 }
273 m_processId = response.getProcessId();
274
275 m_scheduler.scheduleEvent(m_checkPeriod,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700276 bind(&NdnPutFile::startCheckCommand, this));
Shuo Chenccfbe242014-04-29 23:57:51 +0800277}
278
279void
280NdnPutFile::onInsertCommandTimeout(const ndn::Interest& interest)
281{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800282 BOOST_THROW_EXCEPTION(Error("command response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800283}
284
285void
286NdnPutFile::onInterest(const ndn::Name& prefix, const ndn::Interest& interest)
287{
288 if (interest.getName().size() != prefix.size() + 1) {
289 if (isVerbose) {
290 std::cerr << "Error processing incoming interest " << interest << ": "
291 << "Unrecognized Interest" << std::endl;
292 }
293 return;
294 }
295
296 uint64_t segmentNo;
297 try {
298 ndn::Name::Component segmentComponent = interest.getName().get(prefix.size());
299 segmentNo = segmentComponent.toSegment();
300 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800301 catch (const tlv::Error& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800302 if (isVerbose) {
303 std::cerr << "Error processing incoming interest " << interest << ": "
304 << e.what() << std::endl;
305 }
306 return;
307 }
308
309 prepareNextData(segmentNo);
310
311 DataContainer::iterator item = m_data.find(segmentNo);
312 if (item == m_data.end()) {
313 if (isVerbose) {
314 std::cerr << "Requested segment [" << segmentNo << "] does not exist" << std::endl;
315 }
316 return;
317 }
318
Weiqi Shi5822e342014-08-21 20:05:30 -0700319 if (m_isFinished) {
320 uint64_t final = m_currentSegmentNo - 1;
Davide Pesavento0c139512018-11-03 18:23:38 -0400321 item->second->setFinalBlock(ndn::name::Component::fromSegment(final));
Weiqi Shi5822e342014-08-21 20:05:30 -0700322 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800323 m_face.put(*item->second);
324}
325
326void
327NdnPutFile::onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest)
328{
329 BOOST_ASSERT(prefix == m_dataPrefix);
330
331 if (prefix != interest.getName()) {
332 if (isVerbose) {
333 std::cerr << "Received unexpected interest " << interest << std::endl;
334 }
335 return;
336 }
337
338 uint8_t buffer[DEFAULT_BLOCK_SIZE];
339 std::streamsize readSize =
340 boost::iostreams::read(*insertStream, reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
341
342 if (readSize <= 0) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800343 BOOST_THROW_EXCEPTION(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800344 }
345
346 if (insertStream->peek() != std::istream::traits_type::eof()) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800347 BOOST_THROW_EXCEPTION(Error("Input data does not fit into one Data packet"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800348 }
349
Wentao Shanga8f3c402014-10-30 14:03:27 -0700350 shared_ptr<ndn::Data> data = make_shared<ndn::Data>(m_dataPrefix);
Weiqi Shi5822e342014-08-21 20:05:30 -0700351 data->setContent(buffer, readSize);
352 data->setFreshnessPeriod(freshnessPeriod);
353 signData(*data);
354 m_face.put(*data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800355
356 m_isFinished = true;
357}
358
359void
360NdnPutFile::onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
361{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800362 BOOST_THROW_EXCEPTION(Error("onRegisterFailed: " + reason));
Shuo Chenccfbe242014-04-29 23:57:51 +0800363}
364
365void
366NdnPutFile::stopProcess()
367{
368 m_face.getIoService().stop();
369}
370
371void
372NdnPutFile::signData(ndn::Data& data)
373{
374 if (useDigestSha256) {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000375 m_keyChain.sign(data, ndn::signingWithSha256());
Shuo Chenccfbe242014-04-29 23:57:51 +0800376 }
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000377 else if (identityForData.empty())
378 m_keyChain.sign(data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800379 else {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000380 m_keyChain.sign(data, ndn::signingByIdentity(identityForData));
Shuo Chenccfbe242014-04-29 23:57:51 +0800381 }
382}
383
384void
385NdnPutFile::startCheckCommand()
386{
387 ndn::Interest checkInterest = generateCommandInterest(repoPrefix, "insert check",
388 RepoCommandParameter()
389 .setProcessId(m_processId));
390 m_face.expressInterest(checkInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700391 bind(&NdnPutFile::onCheckCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800392 bind(&NdnPutFile::onCheckCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700393 bind(&NdnPutFile::onCheckCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800394}
395
396void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800397NdnPutFile::onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800398{
399 RepoCommandResponse response(data.getContent().blockFromValue());
weijia yuan82cf9142018-10-21 12:25:02 -0700400 int statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800401 if (statusCode >= 400) {
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800402 BOOST_THROW_EXCEPTION(Error("Insert check command failed with code: " +
403 boost::lexical_cast<std::string>(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800404 }
405
406 if (m_isFinished) {
407 uint64_t insertCount = response.getInsertNum();
408
409 if (isSingle) {
410 if (insertCount == 1) {
411 m_face.getIoService().stop();
412 return;
413 }
414 }
415 // Technically, the check should not infer, but directly has signal from repo that
416 // write operation has been finished
417
418 if (insertCount == m_currentSegmentNo) {
419 m_face.getIoService().stop();
420 return;
421 }
422 }
423
424 m_scheduler.scheduleEvent(m_checkPeriod,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700425 bind(&NdnPutFile::startCheckCommand, this));
Shuo Chenccfbe242014-04-29 23:57:51 +0800426}
427
428void
429NdnPutFile::onCheckCommandTimeout(const ndn::Interest& interest)
430{
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800431 BOOST_THROW_EXCEPTION(Error("check response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800432}
433
434ndn::Interest
435NdnPutFile::generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
436 const RepoCommandParameter& commandParameter)
437{
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500438 Name cmd = commandPrefix;
439 cmd
440 .append(command)
441 .append(commandParameter.wireEncode());
442 ndn::Interest interest;
Shuo Chenccfbe242014-04-29 23:57:51 +0800443
444 if (identityForCommand.empty())
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500445 interest = m_cmdSigner.makeCommandInterest(cmd);
Shuo Chenccfbe242014-04-29 23:57:51 +0800446 else {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500447 interest = m_cmdSigner.makeCommandInterest(cmd, ndn::signingByIdentity(identityForCommand));
Shuo Chenccfbe242014-04-29 23:57:51 +0800448 }
449
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500450 interest.setInterestLifetime(interestLifetime);
Shuo Chenccfbe242014-04-29 23:57:51 +0800451 return interest;
452}
453
454static void
455usage()
456{
457 fprintf(stderr,
458 "ndnputfile [-u] [-s] [-D] [-d] [-i identity] [-I identity]"
459 " [-x freshness] [-l lifetime] [-w timeout] repo-prefix ndn-name filename\n"
460 "\n"
461 " Write a file into a repo.\n"
462 " -u: unversioned: do not add a version component\n"
463 " -s: single: do not add version or segment component, implies -u\n"
464 " -D: use DigestSha256 signing method instead of SignatureSha256WithRsa\n"
465 " -i: specify identity used for signing Data\n"
466 " -I: specify identity used for signing commands\n"
467 " -x: FreshnessPeriod in milliseconds\n"
468 " -l: InterestLifetime in milliseconds for each command\n"
469 " -w: timeout in milliseconds for whole process (default unlimited)\n"
470 " -v: be verbose\n"
471 " repo-prefix: repo command prefix\n"
472 " ndn-name: NDN Name prefix for written Data\n"
473 " filename: local file name; \"-\" reads from stdin\n"
474 );
475 exit(1);
476}
477
478int
479main(int argc, char** argv)
480{
481 NdnPutFile ndnPutFile;
482 int opt;
483 while ((opt = getopt(argc, argv, "usDi:I:x:l:w:vh")) != -1) {
484 switch (opt) {
485 case 'u':
486 ndnPutFile.isUnversioned = true;
487 break;
488 case 's':
489 ndnPutFile.isSingle = true;
490 break;
491 case 'D':
492 ndnPutFile.useDigestSha256 = true;
493 break;
494 case 'i':
495 ndnPutFile.identityForData = std::string(optarg);
496 break;
497 case 'I':
498 ndnPutFile.identityForCommand = std::string(optarg);
499 break;
500 case 'x':
501 try {
502 ndnPutFile.freshnessPeriod = 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 << "-x option should be an integer" << std::endl;;
Shuo Chenccfbe242014-04-29 23:57:51 +0800506 return 1;
507 }
508 break;
509 case 'l':
510 try {
511 ndnPutFile.interestLifetime = milliseconds(boost::lexical_cast<uint64_t>(optarg));
512 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800513 catch (const boost::bad_lexical_cast&) {
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800514 std::cerr << "-l option should be an integer" << std::endl;;
Shuo Chenccfbe242014-04-29 23:57:51 +0800515 return 1;
516 }
517 break;
518 case 'w':
519 ndnPutFile.hasTimeout = true;
520 try {
521 ndnPutFile.timeout = milliseconds(boost::lexical_cast<uint64_t>(optarg));
522 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800523 catch (const boost::bad_lexical_cast&) {
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800524 std::cerr << "-w option should be an integer" << std::endl;;
Shuo Chenccfbe242014-04-29 23:57:51 +0800525 return 1;
526 }
527 break;
528 case 'v':
529 ndnPutFile.isVerbose = true;
530 break;
531 case 'h':
532 usage();
533 break;
534 default:
535 break;
536 }
537 }
538
539 argc -= optind;
540 argv += optind;
541
542 if (argc != 3)
543 usage();
544
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800545 ndnPutFile.repoPrefix = Name(argv[0]);
546 ndnPutFile.ndnName = Name(argv[1]);
Shuo Chenccfbe242014-04-29 23:57:51 +0800547 if (strcmp(argv[2], "-") == 0) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800548 ndnPutFile.insertStream = &std::cin;
549 ndnPutFile.run();
550 }
551 else {
552 std::ifstream inputFileStream(argv[2], std::ios::in | std::ios::binary);
553 if (!inputFileStream.is_open()) {
554 std::cerr << "ERROR: cannot open " << argv[2] << std::endl;
555 return 1;
556 }
557
558 ndnPutFile.insertStream = &inputFileStream;
559 ndnPutFile.run();
560 }
561
562 // ndnPutFile MUST NOT be used anymore because .insertStream is a dangling pointer
563
564 return 0;
565}
566
567} // namespace repo
568
569int
570main(int argc, char** argv)
571{
572 try {
573 return repo::main(argc, argv);
574 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800575 catch (const std::exception& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800576 std::cerr << "ERROR: " << e.what() << std::endl;
577 return 2;
578 }
579}