blob: b011c7147b97e89154ca6db385a33bb827795621 [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 Pesavento399f4d92023-09-17 14:03:51 -04003 * Copyright (c) 2014-2023, 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
Davide Pesavento399f4d92023-09-17 14:03:51 -040020#include "repo-command-parameter.hpp"
21#include "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)
Davide Pesavento164ae3b2023-11-11 22:00:23 -050075 , m_scheduler(m_face.getIoContext())
Shuo Chenccfbe242014-04-29 23:57:51 +080076 , 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
Shuo Chenccfbe242014-04-29 23:57:51 +0800114 signData(ndn::Data& data);
115
116 void
117 startCheckCommand();
118
119 void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800120 onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800121
122 void
123 onCheckCommandTimeout(const ndn::Interest& interest);
124
125 ndn::Interest
126 generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
127 const RepoCommandParameter& commandParameter);
128
129public:
130 bool isUnversioned;
131 bool isSingle;
132 bool useDigestSha256;
133 std::string identityForData;
134 std::string identityForCommand;
135 milliseconds freshnessPeriod;
136 milliseconds interestLifetime;
137 bool hasTimeout;
138 milliseconds timeout;
139 ndn::Name repoPrefix;
140 ndn::Name ndnName;
141 std::istream* insertStream;
142 bool isVerbose;
143
144private:
145 ndn::Face m_face;
146 ndn::Scheduler m_scheduler;
147 ndn::KeyChain m_keyChain;
Shuo Chenccfbe242014-04-29 23:57:51 +0800148 uint64_t m_timestampVersion;
149 uint64_t m_processId;
150 milliseconds m_checkPeriod;
151 size_t m_currentSegmentNo;
152 bool m_isFinished;
153 ndn::Name m_dataPrefix;
154
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400155 std::map<uint64_t, std::shared_ptr<ndn::Data>> m_data;
Davide Pesavento75e8d462021-05-16 17:00:42 -0400156 ndn::security::InterestSigner m_cmdSigner;
Shuo Chenccfbe242014-04-29 23:57:51 +0800157};
158
159void
160NdnPutFile::prepareNextData(uint64_t referenceSegmentNo)
161{
162 // make sure m_data has [referenceSegmentNo, referenceSegmentNo + PRE_SIGN_DATA_COUNT] Data
163 if (m_isFinished)
164 return;
165
166 size_t nDataToPrepare = PRE_SIGN_DATA_COUNT;
167
168 if (!m_data.empty()) {
169 uint64_t maxSegmentNo = m_data.rbegin()->first;
170
171 if (maxSegmentNo - referenceSegmentNo >= nDataToPrepare) {
172 // nothing to prepare
173 return;
174 }
175
176 nDataToPrepare -= maxSegmentNo - referenceSegmentNo;
177 }
178
179 for (size_t i = 0; i < nDataToPrepare && !m_isFinished; ++i) {
180 uint8_t buffer[DEFAULT_BLOCK_SIZE];
Davide Pesavento31be3f62019-01-24 23:20:23 -0500181 auto readSize = boost::iostreams::read(*insertStream,
182 reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
Shuo Chenccfbe242014-04-29 23:57:51 +0800183 if (readSize <= 0) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400184 NDN_THROW(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800185 }
186
Davide Pesavento31be3f62019-01-24 23:20:23 -0500187 auto data = make_shared<ndn::Data>(Name(m_dataPrefix).appendSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800188
189 if (insertStream->peek() == std::istream::traits_type::eof()) {
Davide Pesavento0c139512018-11-03 18:23:38 -0400190 data->setFinalBlock(ndn::name::Component::fromSegment(m_currentSegmentNo));
Shuo Chenccfbe242014-04-29 23:57:51 +0800191 m_isFinished = true;
192 }
193
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400194 data->setContent(ndn::make_span(buffer, readSize));
Shuo Chenccfbe242014-04-29 23:57:51 +0800195 data->setFreshnessPeriod(freshnessPeriod);
196 signData(*data);
197
198 m_data.insert(std::make_pair(m_currentSegmentNo, data));
199
200 ++m_currentSegmentNo;
201 }
202}
203
204void
205NdnPutFile::run()
206{
207 m_dataPrefix = ndnName;
208 if (!isUnversioned)
209 m_dataPrefix.appendVersion(m_timestampVersion);
210
211 if (isVerbose)
212 std::cerr << "setInterestFilter for " << m_dataPrefix << std::endl;
Davide Pesavento75e8d462021-05-16 17:00:42 -0400213
Shuo Chenccfbe242014-04-29 23:57:51 +0800214 m_face.setInterestFilter(m_dataPrefix,
215 isSingle ?
Davide Pesavento75e8d462021-05-16 17:00:42 -0400216 bind(&NdnPutFile::onSingleInterest, this, _1, _2) :
217 bind(&NdnPutFile::onInterest, this, _1, _2),
Wentao Shanga8f3c402014-10-30 14:03:27 -0700218 bind(&NdnPutFile::onRegisterSuccess, this, _1),
219 bind(&NdnPutFile::onRegisterFailed, this, _1, _2));
Shuo Chenccfbe242014-04-29 23:57:51 +0800220
Shuo Chenccfbe242014-04-29 23:57:51 +0800221 if (hasTimeout)
Davide Pesavento164ae3b2023-11-11 22:00:23 -0500222 m_scheduler.schedule(timeout, [this] { m_face.getIoContext().stop(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800223
224 m_face.processEvents();
225}
226
227void
Wentao Shang91fb4f22014-05-20 10:55:22 -0700228NdnPutFile::onRegisterSuccess(const Name& prefix)
229{
230 startInsertCommand();
231}
232
233void
Shuo Chenccfbe242014-04-29 23:57:51 +0800234NdnPutFile::startInsertCommand()
235{
236 RepoCommandParameter parameters;
237 parameters.setName(m_dataPrefix);
238 if (!isSingle) {
239 parameters.setStartBlockId(0);
240 }
241
242 ndn::Interest commandInterest = generateCommandInterest(repoPrefix, "insert", parameters);
243 m_face.expressInterest(commandInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700244 bind(&NdnPutFile::onInsertCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800245 bind(&NdnPutFile::onInsertCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700246 bind(&NdnPutFile::onInsertCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800247}
248
249void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400250NdnPutFile::onInsertCommandResponse(const ndn::Interest&, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800251{
252 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500253 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800254 if (statusCode >= 400) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400255 NDN_THROW(Error("insert command failed with code " + std::to_string(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800256 }
257 m_processId = response.getProcessId();
258
Davide Pesavento8891c832019-03-20 23:20:35 -0400259 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800260}
261
262void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400263NdnPutFile::onInsertCommandTimeout(const ndn::Interest&)
Shuo Chenccfbe242014-04-29 23:57:51 +0800264{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400265 NDN_THROW(Error("command response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800266}
267
268void
269NdnPutFile::onInterest(const ndn::Name& prefix, const ndn::Interest& interest)
270{
271 if (interest.getName().size() != prefix.size() + 1) {
272 if (isVerbose) {
273 std::cerr << "Error processing incoming interest " << interest << ": "
274 << "Unrecognized Interest" << std::endl;
275 }
276 return;
277 }
278
279 uint64_t segmentNo;
280 try {
281 ndn::Name::Component segmentComponent = interest.getName().get(prefix.size());
282 segmentNo = segmentComponent.toSegment();
283 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800284 catch (const tlv::Error& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800285 if (isVerbose) {
286 std::cerr << "Error processing incoming interest " << interest << ": "
287 << e.what() << std::endl;
288 }
289 return;
290 }
291
292 prepareNextData(segmentNo);
293
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400294 auto item = m_data.find(segmentNo);
Shuo Chenccfbe242014-04-29 23:57:51 +0800295 if (item == m_data.end()) {
296 if (isVerbose) {
297 std::cerr << "Requested segment [" << segmentNo << "] does not exist" << std::endl;
298 }
299 return;
300 }
301
Weiqi Shi5822e342014-08-21 20:05:30 -0700302 if (m_isFinished) {
303 uint64_t final = m_currentSegmentNo - 1;
Davide Pesavento0c139512018-11-03 18:23:38 -0400304 item->second->setFinalBlock(ndn::name::Component::fromSegment(final));
Weiqi Shi5822e342014-08-21 20:05:30 -0700305 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800306 m_face.put(*item->second);
307}
308
309void
310NdnPutFile::onSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest)
311{
312 BOOST_ASSERT(prefix == m_dataPrefix);
313
314 if (prefix != interest.getName()) {
315 if (isVerbose) {
316 std::cerr << "Received unexpected interest " << interest << std::endl;
317 }
318 return;
319 }
320
321 uint8_t buffer[DEFAULT_BLOCK_SIZE];
322 std::streamsize readSize =
323 boost::iostreams::read(*insertStream, reinterpret_cast<char*>(buffer), DEFAULT_BLOCK_SIZE);
324
325 if (readSize <= 0) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400326 NDN_THROW(Error("Error reading from the input stream"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800327 }
328
329 if (insertStream->peek() != std::istream::traits_type::eof()) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400330 NDN_THROW(Error("Input data does not fit into one Data packet"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800331 }
332
Davide Pesavento31be3f62019-01-24 23:20:23 -0500333 auto data = make_shared<ndn::Data>(m_dataPrefix);
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400334 data->setContent(ndn::make_span(buffer, readSize));
Weiqi Shi5822e342014-08-21 20:05:30 -0700335 data->setFreshnessPeriod(freshnessPeriod);
336 signData(*data);
337 m_face.put(*data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800338
339 m_isFinished = true;
340}
341
342void
343NdnPutFile::onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
344{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400345 NDN_THROW(Error("onRegisterFailed: " + reason));
Shuo Chenccfbe242014-04-29 23:57:51 +0800346}
347
348void
Shuo Chenccfbe242014-04-29 23:57:51 +0800349NdnPutFile::signData(ndn::Data& data)
350{
351 if (useDigestSha256) {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000352 m_keyChain.sign(data, ndn::signingWithSha256());
Shuo Chenccfbe242014-04-29 23:57:51 +0800353 }
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000354 else if (identityForData.empty())
355 m_keyChain.sign(data);
Shuo Chenccfbe242014-04-29 23:57:51 +0800356 else {
Junxiao Shi047a6fb2017-06-08 16:16:05 +0000357 m_keyChain.sign(data, ndn::signingByIdentity(identityForData));
Shuo Chenccfbe242014-04-29 23:57:51 +0800358 }
359}
360
361void
362NdnPutFile::startCheckCommand()
363{
364 ndn::Interest checkInterest = generateCommandInterest(repoPrefix, "insert check",
365 RepoCommandParameter()
366 .setProcessId(m_processId));
367 m_face.expressInterest(checkInterest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700368 bind(&NdnPutFile::onCheckCommandResponse, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800369 bind(&NdnPutFile::onCheckCommandTimeout, this, _1), // Nack
Wentao Shanga8f3c402014-10-30 14:03:27 -0700370 bind(&NdnPutFile::onCheckCommandTimeout, this, _1));
Shuo Chenccfbe242014-04-29 23:57:51 +0800371}
372
373void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400374NdnPutFile::onCheckCommandResponse(const ndn::Interest&, const ndn::Data& data)
Shuo Chenccfbe242014-04-29 23:57:51 +0800375{
376 RepoCommandResponse response(data.getContent().blockFromValue());
Davide Pesavento31be3f62019-01-24 23:20:23 -0500377 auto statusCode = response.getCode();
Shuo Chenccfbe242014-04-29 23:57:51 +0800378 if (statusCode >= 400) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400379 NDN_THROW(Error("Insert check command failed with code " + std::to_string(statusCode)));
Shuo Chenccfbe242014-04-29 23:57:51 +0800380 }
381
382 if (m_isFinished) {
383 uint64_t insertCount = response.getInsertNum();
384
385 if (isSingle) {
386 if (insertCount == 1) {
Davide Pesavento164ae3b2023-11-11 22:00:23 -0500387 m_face.getIoContext().stop();
Shuo Chenccfbe242014-04-29 23:57:51 +0800388 return;
389 }
390 }
391 // Technically, the check should not infer, but directly has signal from repo that
392 // write operation has been finished
393
394 if (insertCount == m_currentSegmentNo) {
Davide Pesavento164ae3b2023-11-11 22:00:23 -0500395 m_face.getIoContext().stop();
Shuo Chenccfbe242014-04-29 23:57:51 +0800396 return;
397 }
398 }
399
Davide Pesavento8891c832019-03-20 23:20:35 -0400400 m_scheduler.schedule(m_checkPeriod, [this] { startCheckCommand(); });
Shuo Chenccfbe242014-04-29 23:57:51 +0800401}
402
403void
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400404NdnPutFile::onCheckCommandTimeout(const ndn::Interest&)
Shuo Chenccfbe242014-04-29 23:57:51 +0800405{
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400406 NDN_THROW(Error("check response timeout"));
Shuo Chenccfbe242014-04-29 23:57:51 +0800407}
408
409ndn::Interest
410NdnPutFile::generateCommandInterest(const ndn::Name& commandPrefix, const std::string& command,
411 const RepoCommandParameter& commandParameter)
412{
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500413 Name cmd = commandPrefix;
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400414 cmd.append(command).append(tlv::GenericNameComponent, commandParameter.wireEncode());
Shuo Chenccfbe242014-04-29 23:57:51 +0800415
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400416 ndn::Interest interest;
417 if (identityForCommand.empty()) {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500418 interest = m_cmdSigner.makeCommandInterest(cmd);
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400419 }
Shuo Chenccfbe242014-04-29 23:57:51 +0800420 else {
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500421 interest = m_cmdSigner.makeCommandInterest(cmd, ndn::signingByIdentity(identityForCommand));
Shuo Chenccfbe242014-04-29 23:57:51 +0800422 }
423
Alexander Afanasyev2e8147c2017-11-09 14:17:02 -0500424 interest.setInterestLifetime(interestLifetime);
Shuo Chenccfbe242014-04-29 23:57:51 +0800425 return interest;
426}
427
428static void
Davide Pesavento31be3f62019-01-24 23:20:23 -0500429usage(const char* programName)
Shuo Chenccfbe242014-04-29 23:57:51 +0800430{
Davide Pesavento31be3f62019-01-24 23:20:23 -0500431 std::cerr << "Usage: "
432 << programName << " [-u] [-s] [-D] [-d] [-i identity] [-I identity] [-x freshness]"
433 " [-l lifetime] [-w timeout] repo-prefix ndn-name filename\n"
434 << "\n"
435 << "Write a file into a repo.\n"
436 << "\n"
437 << " -u: unversioned: do not add a version component\n"
438 << " -s: single: do not add version or segment component, implies -u\n"
439 << " -D: use DigestSha256 signing method instead of SignatureSha256WithRsa\n"
440 << " -i: specify identity used for signing Data\n"
441 << " -I: specify identity used for signing commands\n"
442 << " -x: FreshnessPeriod in milliseconds\n"
443 << " -l: InterestLifetime in milliseconds for each command\n"
444 << " -w: timeout in milliseconds for whole process (default unlimited)\n"
445 << " -v: be verbose\n"
446 << " repo-prefix: repo command prefix\n"
447 << " ndn-name: NDN Name prefix for written Data\n"
448 << " filename: local file name; \"-\" reads from stdin\n"
449 << std::endl;
Shuo Chenccfbe242014-04-29 23:57:51 +0800450}
451
Davide Pesavento31be3f62019-01-24 23:20:23 -0500452static int
Shuo Chenccfbe242014-04-29 23:57:51 +0800453main(int argc, char** argv)
454{
455 NdnPutFile ndnPutFile;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500456
Shuo Chenccfbe242014-04-29 23:57:51 +0800457 int opt;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500458 while ((opt = getopt(argc, argv, "husDi:I:x:l:w:v")) != -1) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800459 switch (opt) {
Davide Pesavento31be3f62019-01-24 23:20:23 -0500460 case 'h':
461 usage(argv[0]);
462 return 0;
Shuo Chenccfbe242014-04-29 23:57:51 +0800463 case 'u':
464 ndnPutFile.isUnversioned = true;
465 break;
466 case 's':
467 ndnPutFile.isSingle = true;
468 break;
469 case 'D':
470 ndnPutFile.useDigestSha256 = true;
471 break;
472 case 'i':
473 ndnPutFile.identityForData = std::string(optarg);
474 break;
475 case 'I':
476 ndnPutFile.identityForCommand = std::string(optarg);
477 break;
478 case 'x':
479 try {
480 ndnPutFile.freshnessPeriod = milliseconds(boost::lexical_cast<uint64_t>(optarg));
481 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800482 catch (const boost::bad_lexical_cast&) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400483 std::cerr << "-x option should be an integer" << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500484 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800485 }
486 break;
487 case 'l':
488 try {
489 ndnPutFile.interestLifetime = 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 << "-l 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 'w':
497 ndnPutFile.hasTimeout = true;
498 try {
499 ndnPutFile.timeout = milliseconds(boost::lexical_cast<uint64_t>(optarg));
500 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800501 catch (const boost::bad_lexical_cast&) {
Davide Pesavento9c0bd8d2022-03-14 16:48:12 -0400502 std::cerr << "-w option should be an integer" << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500503 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800504 }
505 break;
506 case 'v':
507 ndnPutFile.isVerbose = true;
508 break;
Shuo Chenccfbe242014-04-29 23:57:51 +0800509 default:
Davide Pesavento31be3f62019-01-24 23:20:23 -0500510 usage(argv[0]);
511 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800512 }
513 }
514
Davide Pesavento31be3f62019-01-24 23:20:23 -0500515 if (argc != optind + 3) {
516 usage(argv[0]);
517 return 2;
518 }
519
Shuo Chenccfbe242014-04-29 23:57:51 +0800520 argc -= optind;
521 argv += optind;
522
weijia yuan3aa8d2b2018-03-06 15:35:57 -0800523 ndnPutFile.repoPrefix = Name(argv[0]);
524 ndnPutFile.ndnName = Name(argv[1]);
Shuo Chenccfbe242014-04-29 23:57:51 +0800525 if (strcmp(argv[2], "-") == 0) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800526 ndnPutFile.insertStream = &std::cin;
527 ndnPutFile.run();
528 }
529 else {
530 std::ifstream inputFileStream(argv[2], std::ios::in | std::ios::binary);
531 if (!inputFileStream.is_open()) {
532 std::cerr << "ERROR: cannot open " << argv[2] << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500533 return 2;
Shuo Chenccfbe242014-04-29 23:57:51 +0800534 }
535
536 ndnPutFile.insertStream = &inputFileStream;
537 ndnPutFile.run();
538 }
539
540 // ndnPutFile MUST NOT be used anymore because .insertStream is a dangling pointer
541
542 return 0;
543}
544
545} // namespace repo
546
547int
548main(int argc, char** argv)
549{
550 try {
551 return repo::main(argc, argv);
552 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800553 catch (const std::exception& e) {
Shuo Chenccfbe242014-04-29 23:57:51 +0800554 std::cerr << "ERROR: " << e.what() << std::endl;
Davide Pesavento31be3f62019-01-24 23:20:23 -0500555 return 1;
Shuo Chenccfbe242014-04-29 23:57:51 +0800556 }
557}