blob: dbc5b5da23d00824151ae37e5e9f28027562441f [file] [log] [blame]
Alexander Afanasyev42290b22017-03-09 12:58:29 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevc0e26582017-08-13 21:16:49 -04002/*
Davide Pesaventof43a03e2018-02-21 22:04:21 -05003 * Copyright (c) 2014-2018, Regents of the University of California.
Wentao Shangbcbc9292014-04-28 21:17:06 -07004 *
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
17 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "ndngetfile.hpp"
Alexander Afanasyevc0e26582017-08-13 21:16:49 -040021
Wentao Shang91fb4f22014-05-20 10:55:22 -070022#include <fstream>
Alexander Afanasyevc0e26582017-08-13 21:16:49 -040023#include <iostream>
24
25#include <boost/lexical_cast.hpp>
Wentao Shangbcbc9292014-04-28 21:17:06 -070026
27namespace repo {
28
Wentao Shanga8f3c402014-10-30 14:03:27 -070029using ndn::Name;
30using ndn::Interest;
31using ndn::Data;
32using ndn::Block;
33
34using std::bind;
35using std::placeholders::_1;
36using std::placeholders::_2;
Wentao Shangbcbc9292014-04-28 21:17:06 -070037
Weiqi Shi5822e342014-08-21 20:05:30 -070038static const int MAX_RETRY = 3;
39
Wentao Shangbcbc9292014-04-28 21:17:06 -070040void
41Consumer::fetchData(const Name& name)
42{
43 Interest interest(name);
44 interest.setInterestLifetime(m_interestLifetime);
Davide Pesaventof43a03e2018-02-21 22:04:21 -050045 if (m_hasVersion) {
46 interest.setMustBeFresh(m_mustBeFresh);
47 }
48 else {
49 interest.setMustBeFresh(true);
50 interest.setChildSelector(1);
51 }
Wentao Shangbcbc9292014-04-28 21:17:06 -070052
53 m_face.expressInterest(interest,
Davide Pesaventof43a03e2018-02-21 22:04:21 -050054 m_hasVersion ? bind(&Consumer::onVersionedData, this, _1, _2)
55 : bind(&Consumer::onUnversionedData, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -080056 bind(&Consumer::onTimeout, this, _1), // Nack
Wentao Shangbcbc9292014-04-28 21:17:06 -070057 bind(&Consumer::onTimeout, this, _1));
58}
59
60void
61Consumer::run()
62{
63 // Send the first Interest
64 Name name(m_dataName);
Wentao Shangbcbc9292014-04-28 21:17:06 -070065
Weiqi Shi5822e342014-08-21 20:05:30 -070066 m_nextSegment++;
Wentao Shangbcbc9292014-04-28 21:17:06 -070067 fetchData(name);
68
69 // processEvents will block until the requested data received or timeout occurs
70 m_face.processEvents(m_timeout);
71}
72
73void
Alexander Afanasyev42290b22017-03-09 12:58:29 -080074Consumer::onVersionedData(const Interest& interest, const Data& data)
Wentao Shangbcbc9292014-04-28 21:17:06 -070075{
76 const Name& name = data.getName();
Wentao Shangbcbc9292014-04-28 21:17:06 -070077
Weiqi Shi5822e342014-08-21 20:05:30 -070078 // the received data name may have segment number or not
79 if (name.size() == m_dataName.size()) {
80 if (!m_isSingle) {
81 Name fetchName = name;
82 fetchName.appendSegment(0);
83 fetchData(fetchName);
84 }
85 }
86 else if (name.size() == m_dataName.size() + 1) {
87 if (!m_isSingle) {
88 if (m_isFirst) {
89 uint64_t segment = name[-1].toSegment();
90 if (segment != 0) {
91 fetchData(Name(m_dataName).appendSegment(0));
92 m_isFirst = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -070093 return;
94 }
Weiqi Shi5822e342014-08-21 20:05:30 -070095 m_isFirst = false;
96 }
97 fetchNextData(name, data);
Wentao Shangbcbc9292014-04-28 21:17:06 -070098 }
Weiqi Shi5822e342014-08-21 20:05:30 -070099 else {
100 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
101 return;
102 }
103 }
104 else {
105 std::cerr << "ERROR: Name size does not match" << std::endl;
106 return;
107 }
108 readData(data);
109}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700110
Weiqi Shi5822e342014-08-21 20:05:30 -0700111void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800112Consumer::onUnversionedData(const Interest& interest, const Data& data)
Weiqi Shi5822e342014-08-21 20:05:30 -0700113{
114 const Name& name = data.getName();
115 //std::cout<<"recevied data name = "<<name<<std::endl;
116 if (name.size() == m_dataName.size() + 1) {
117 if (!m_isSingle) {
118 Name fetchName = name;
119 fetchName.append(name[-1]).appendSegment(0);
120 fetchData(fetchName);
121 }
122 }
123 else if (name.size() == m_dataName.size() + 2) {
124 if (!m_isSingle) {
125 if (m_isFirst) {
126 uint64_t segment = name[-1].toSegment();
127 if (segment != 0) {
128 fetchData(Name(m_dataName).append(name[-2]).appendSegment(0));
129 m_isFirst = false;
130 return;
131 }
132 m_isFirst = false;
133 }
134 fetchNextData(name, data);
135 }
136 else {
137 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
138 return;
139 }
140 }
141 else {
142 std::cerr << "ERROR: Name size does not match" << std::endl;
143 return;
144 }
145 readData(data);
146}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700147
Weiqi Shi5822e342014-08-21 20:05:30 -0700148void
149Consumer::readData(const Data& data)
150{
Wentao Shangbcbc9292014-04-28 21:17:06 -0700151 const Block& content = data.getContent();
152 m_os.write(reinterpret_cast<const char*>(content.value()), content.value_size());
153 m_totalSize += content.value_size();
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500154 if (m_verbose) {
Weiqi Shi5822e342014-08-21 20:05:30 -0700155 std::cerr << "LOG: received data = " << data.getName() << std::endl;
156 }
157 if (m_isFinished || m_isSingle) {
158 std::cerr << "INFO: End of file is reached." << std::endl;
159 std::cerr << "INFO: Total # of segments received: " << m_nextSegment << std::endl;
160 std::cerr << "INFO: Total # bytes of content received: " << m_totalSize << std::endl;
161 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700162}
163
Weiqi Shi5822e342014-08-21 20:05:30 -0700164void
165Consumer::fetchNextData(const Name& name, const Data& data)
166{
167 uint64_t segment = name[-1].toSegment();
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500168 BOOST_VERIFY(segment == (m_nextSegment - 1));
169
Wentao Shanga8f3c402014-10-30 14:03:27 -0700170 const ndn::name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
Weiqi Shi5822e342014-08-21 20:05:30 -0700171 if (finalBlockId == name[-1]) {
172 m_isFinished = true;
173 }
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500174 else {
Weiqi Shi5822e342014-08-21 20:05:30 -0700175 // Reset retry counter
176 m_retryCount = 0;
177 if (m_hasVersion)
178 fetchData(Name(m_dataName).appendSegment(m_nextSegment++));
179 else
180 fetchData(Name(m_dataName).append(name[-2]).appendSegment(m_nextSegment++));
181 }
182}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700183
184void
185Consumer::onTimeout(const Interest& interest)
186{
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500187 if (m_retryCount++ < MAX_RETRY) {
188 // Retransmit the interest
189 fetchData(interest.getName());
190 if (m_verbose)
191 std::cerr << "TIMEOUT: retransmit interest for " << interest.getName() << std::endl;
192 }
193 else {
194 std::cerr << "TIMEOUT: last interest sent for segment #" << (m_nextSegment - 1) << std::endl;
195 std::cerr << "TIMEOUT: abort fetching after " << MAX_RETRY
196 << " times of retry" << std::endl;
197 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700198}
199
Wentao Shangbcbc9292014-04-28 21:17:06 -0700200int
201usage(const std::string& filename)
202{
203 std::cerr << "Usage: \n "
Weiqi Shi5822e342014-08-21 20:05:30 -0700204 << filename << " [-v] [-s] [-u] [-l lifetime] [-w timeout] [-o filename] ndn-name\n\n"
Wentao Shangbcbc9292014-04-28 21:17:06 -0700205 << "-v: be verbose\n"
Weiqi Shi5822e342014-08-21 20:05:30 -0700206 << "-s: only get single data packet\n"
207 << "-u: versioned: ndn-name contains version component\n"
208 << " if -u is not specified, this command will return the rightmost child for the prefix\n"
Wentao Shangbcbc9292014-04-28 21:17:06 -0700209 << "-l: InterestLifetime in milliseconds\n"
210 << "-w: timeout in milliseconds for whole process (default unlimited)\n"
Weiqi Shi5822e342014-08-21 20:05:30 -0700211 << "-o: write to local file name instead of stdout\n"
212 << "ndn-name: NDN Name prefix for Data to be read\n";
Wentao Shangbcbc9292014-04-28 21:17:06 -0700213 return 1;
214}
215
Wentao Shangbcbc9292014-04-28 21:17:06 -0700216int
217main(int argc, char** argv)
218{
219 std::string name;
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500220 const char* outputFile = nullptr;
Weiqi Shi5822e342014-08-21 20:05:30 -0700221 bool verbose = false, versioned = false, single = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700222 int interestLifetime = 4000; // in milliseconds
223 int timeout = 0; // in milliseconds
224
225 int opt;
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500226 while ((opt = getopt(argc, argv, "vsul:w:o:")) != -1) {
227 switch (opt) {
228 case 'v':
229 verbose = true;
230 break;
231 case 's':
232 single = true;
233 break;
234 case 'u':
235 versioned = true;
236 break;
237 case 'l':
238 try {
239 interestLifetime = boost::lexical_cast<int>(optarg);
Wentao Shangbcbc9292014-04-28 21:17:06 -0700240 }
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500241 catch (const boost::bad_lexical_cast&) {
242 std::cerr << "ERROR: -l option should be an integer." << std::endl;
243 return 1;
244 }
245 interestLifetime = std::max(interestLifetime, 0);
246 break;
247 case 'w':
248 try {
249 timeout = boost::lexical_cast<int>(optarg);
250 }
251 catch (const boost::bad_lexical_cast&) {
252 std::cerr << "ERROR: -w option should be an integer." << std::endl;
253 return 1;
254 }
255 timeout = std::max(timeout, 0);
256 break;
257 case 'o':
258 outputFile = optarg;
259 break;
260 default:
Wentao Shangbcbc9292014-04-28 21:17:06 -0700261 return usage(argv[0]);
262 }
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500263 }
264
265 if (optind < argc)
266 name = argv[optind];
267
268 if (name.empty())
269 return usage(argv[0]);
Wentao Shangbcbc9292014-04-28 21:17:06 -0700270
271 std::streambuf* buf;
272 std::ofstream of;
273
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500274 if (outputFile != nullptr) {
275 of.open(outputFile, std::ios::out | std::ios::binary | std::ios::trunc);
276 if (!of || !of.is_open()) {
277 std::cerr << "ERROR: cannot open " << outputFile << std::endl;
278 return 1;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700279 }
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500280 buf = of.rdbuf();
281 }
282 else {
283 buf = std::cout.rdbuf();
284 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700285
286 std::ostream os(buf);
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500287 Consumer consumer(name, os, verbose, versioned, single, interestLifetime, timeout);
Wentao Shangbcbc9292014-04-28 21:17:06 -0700288
Davide Pesaventof43a03e2018-02-21 22:04:21 -0500289 try {
290 consumer.run();
291 }
292 catch (const std::exception& e) {
293 std::cerr << "ERROR: " << e.what() << std::endl;
294 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700295
296 return 0;
297}
298
299} // namespace repo
300
301int
302main(int argc, char** argv)
303{
304 return repo::main(argc, argv);
305}