blob: 1f59a3643d69f2a12c3fe4b724a834962628c32f [file] [log] [blame]
Alexander Afanasyev42290b22017-03-09 12:58:29 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Wentao Shangbcbc9292014-04-28 21:17:06 -07002/**
Alexander Afanasyev42290b22017-03-09 12:58:29 -08003 * Copyright (c) 2014-2017, 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"
21#include <boost/lexical_cast.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070022#include <fstream>
Wentao Shangbcbc9292014-04-28 21:17:06 -070023
24namespace repo {
25
Wentao Shanga8f3c402014-10-30 14:03:27 -070026using ndn::Name;
27using ndn::Interest;
28using ndn::Data;
29using ndn::Block;
30
31using std::bind;
32using std::placeholders::_1;
33using std::placeholders::_2;
Wentao Shangbcbc9292014-04-28 21:17:06 -070034
Weiqi Shi5822e342014-08-21 20:05:30 -070035static const int MAX_RETRY = 3;
36
Wentao Shangbcbc9292014-04-28 21:17:06 -070037void
38Consumer::fetchData(const Name& name)
39{
40 Interest interest(name);
41 interest.setInterestLifetime(m_interestLifetime);
Weiqi Shi5822e342014-08-21 20:05:30 -070042 //std::cout<<"interest name = "<<interest.getName()<<std::endl;
Wentao Shangbcbc9292014-04-28 21:17:06 -070043 if (m_hasVersion)
44 {
45 interest.setMustBeFresh(m_mustBeFresh);
46 }
47 else
48 {
49 interest.setMustBeFresh(true);
50 interest.setChildSelector(1);
51 }
52
53 m_face.expressInterest(interest,
Weiqi Shi5822e342014-08-21 20:05:30 -070054 m_hasVersion ?
Wentao Shanga8f3c402014-10-30 14:03:27 -070055 bind(&Consumer::onVersionedData, this, _1, _2)
56 :
57 bind(&Consumer::onUnversionedData, this, _1, _2),
Alexander Afanasyev42290b22017-03-09 12:58:29 -080058 bind(&Consumer::onTimeout, this, _1), // Nack
Wentao Shangbcbc9292014-04-28 21:17:06 -070059 bind(&Consumer::onTimeout, this, _1));
60}
61
62void
63Consumer::run()
64{
65 // Send the first Interest
66 Name name(m_dataName);
Wentao Shangbcbc9292014-04-28 21:17:06 -070067
Weiqi Shi5822e342014-08-21 20:05:30 -070068 m_nextSegment++;
Wentao Shangbcbc9292014-04-28 21:17:06 -070069 fetchData(name);
70
71 // processEvents will block until the requested data received or timeout occurs
72 m_face.processEvents(m_timeout);
73}
74
75void
Alexander Afanasyev42290b22017-03-09 12:58:29 -080076Consumer::onVersionedData(const Interest& interest, const Data& data)
Wentao Shangbcbc9292014-04-28 21:17:06 -070077{
78 const Name& name = data.getName();
Wentao Shangbcbc9292014-04-28 21:17:06 -070079
Weiqi Shi5822e342014-08-21 20:05:30 -070080 // the received data name may have segment number or not
81 if (name.size() == m_dataName.size()) {
82 if (!m_isSingle) {
83 Name fetchName = name;
84 fetchName.appendSegment(0);
85 fetchData(fetchName);
86 }
87 }
88 else if (name.size() == m_dataName.size() + 1) {
89 if (!m_isSingle) {
90 if (m_isFirst) {
91 uint64_t segment = name[-1].toSegment();
92 if (segment != 0) {
93 fetchData(Name(m_dataName).appendSegment(0));
94 m_isFirst = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -070095 return;
96 }
Weiqi Shi5822e342014-08-21 20:05:30 -070097 m_isFirst = false;
98 }
99 fetchNextData(name, data);
Wentao Shangbcbc9292014-04-28 21:17:06 -0700100 }
Weiqi Shi5822e342014-08-21 20:05:30 -0700101 else {
102 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
103 return;
104 }
105 }
106 else {
107 std::cerr << "ERROR: Name size does not match" << std::endl;
108 return;
109 }
110 readData(data);
111}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700112
Weiqi Shi5822e342014-08-21 20:05:30 -0700113void
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800114Consumer::onUnversionedData(const Interest& interest, const Data& data)
Weiqi Shi5822e342014-08-21 20:05:30 -0700115{
116 const Name& name = data.getName();
117 //std::cout<<"recevied data name = "<<name<<std::endl;
118 if (name.size() == m_dataName.size() + 1) {
119 if (!m_isSingle) {
120 Name fetchName = name;
121 fetchName.append(name[-1]).appendSegment(0);
122 fetchData(fetchName);
123 }
124 }
125 else if (name.size() == m_dataName.size() + 2) {
126 if (!m_isSingle) {
127 if (m_isFirst) {
128 uint64_t segment = name[-1].toSegment();
129 if (segment != 0) {
130 fetchData(Name(m_dataName).append(name[-2]).appendSegment(0));
131 m_isFirst = false;
132 return;
133 }
134 m_isFirst = false;
135 }
136 fetchNextData(name, data);
137 }
138 else {
139 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
140 return;
141 }
142 }
143 else {
144 std::cerr << "ERROR: Name size does not match" << std::endl;
145 return;
146 }
147 readData(data);
148}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700149
Weiqi Shi5822e342014-08-21 20:05:30 -0700150void
151Consumer::readData(const Data& data)
152{
Wentao Shangbcbc9292014-04-28 21:17:06 -0700153 const Block& content = data.getContent();
154 m_os.write(reinterpret_cast<const char*>(content.value()), content.value_size());
155 m_totalSize += content.value_size();
156 if (m_verbose)
Weiqi Shi5822e342014-08-21 20:05:30 -0700157 {
158 std::cerr << "LOG: received data = " << data.getName() << std::endl;
159 }
160 if (m_isFinished || m_isSingle) {
161 std::cerr << "INFO: End of file is reached." << std::endl;
162 std::cerr << "INFO: Total # of segments received: " << m_nextSegment << std::endl;
163 std::cerr << "INFO: Total # bytes of content received: " << m_totalSize << std::endl;
164 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700165}
166
Weiqi Shi5822e342014-08-21 20:05:30 -0700167void
168Consumer::fetchNextData(const Name& name, const Data& data)
169{
170 uint64_t segment = name[-1].toSegment();
171 BOOST_ASSERT(segment == (m_nextSegment - 1));
Wentao Shanga8f3c402014-10-30 14:03:27 -0700172 const ndn::name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
Weiqi Shi5822e342014-08-21 20:05:30 -0700173 if (finalBlockId == name[-1]) {
174 m_isFinished = true;
175 }
176 else
177 {
178 // Reset retry counter
179 m_retryCount = 0;
180 if (m_hasVersion)
181 fetchData(Name(m_dataName).appendSegment(m_nextSegment++));
182 else
183 fetchData(Name(m_dataName).append(name[-2]).appendSegment(m_nextSegment++));
184 }
185}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700186
187void
188Consumer::onTimeout(const Interest& interest)
189{
Weiqi Shi5822e342014-08-21 20:05:30 -0700190 if (m_retryCount++ < MAX_RETRY)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700191 {
192 // Retransmit the interest
193 fetchData(interest.getName());
194 if (m_verbose)
195 {
196 std::cerr << "TIMEOUT: retransmit interest for " << interest.getName() << std::endl;
197 }
198 }
199 else
200 {
201 std::cerr << "TIMEOUT: last interest sent for segment #" << (m_nextSegment - 1) << std::endl;
Weiqi Shi5822e342014-08-21 20:05:30 -0700202 std::cerr << "TIMEOUT: abort fetching after " << MAX_RETRY
Wentao Shangbcbc9292014-04-28 21:17:06 -0700203 << " times of retry" << std::endl;
204 }
205}
206
207
208int
209usage(const std::string& filename)
210{
211 std::cerr << "Usage: \n "
Weiqi Shi5822e342014-08-21 20:05:30 -0700212 << filename << " [-v] [-s] [-u] [-l lifetime] [-w timeout] [-o filename] ndn-name\n\n"
Wentao Shangbcbc9292014-04-28 21:17:06 -0700213 << "-v: be verbose\n"
Weiqi Shi5822e342014-08-21 20:05:30 -0700214 << "-s: only get single data packet\n"
215 << "-u: versioned: ndn-name contains version component\n"
216 << " if -u is not specified, this command will return the rightmost child for the prefix\n"
Wentao Shangbcbc9292014-04-28 21:17:06 -0700217 << "-l: InterestLifetime in milliseconds\n"
218 << "-w: timeout in milliseconds for whole process (default unlimited)\n"
Weiqi Shi5822e342014-08-21 20:05:30 -0700219 << "-o: write to local file name instead of stdout\n"
220 << "ndn-name: NDN Name prefix for Data to be read\n";
Wentao Shangbcbc9292014-04-28 21:17:06 -0700221 return 1;
222}
223
224
225int
226main(int argc, char** argv)
227{
228 std::string name;
229 const char* outputFile = 0;
Weiqi Shi5822e342014-08-21 20:05:30 -0700230 bool verbose = false, versioned = false, single = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700231 int interestLifetime = 4000; // in milliseconds
232 int timeout = 0; // in milliseconds
233
234 int opt;
Weiqi Shi5822e342014-08-21 20:05:30 -0700235 while ((opt = getopt(argc, argv, "vsul:w:o:")) != -1)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700236 {
237 switch (opt) {
238 case 'v':
239 verbose = true;
240 break;
Weiqi Shi5822e342014-08-21 20:05:30 -0700241 case 's':
242 single = true;
243 break;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700244 case 'u':
Weiqi Shi5822e342014-08-21 20:05:30 -0700245 versioned = true;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700246 break;
247 case 'l':
248 try
249 {
250 interestLifetime = boost::lexical_cast<int>(optarg);
251 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800252 catch (const boost::bad_lexical_cast&)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700253 {
254 std::cerr << "ERROR: -l option should be an integer." << std::endl;
255 return 1;
256 }
257 interestLifetime = std::max(interestLifetime, 0);
258 break;
259 case 'w':
260 try
261 {
262 timeout = boost::lexical_cast<int>(optarg);
263 }
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800264 catch (const boost::bad_lexical_cast&)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700265 {
266 std::cerr << "ERROR: -w option should be an integer." << std::endl;
267 return 1;
268 }
269 timeout = std::max(timeout, 0);
270 break;
271 case 'o':
272 outputFile = optarg;
273 break;
274 default:
275 return usage(argv[0]);
276 }
277 }
278
279 if (optind < argc)
280 {
281 name = argv[optind];
282 }
283
284 if (name.empty())
285 {
286 return usage(argv[0]);
287 }
288
289 std::streambuf* buf;
290 std::ofstream of;
291
292 if (outputFile != 0)
293 {
Diarmuid Collinsdd6348a2014-12-14 12:32:07 -0800294 of.open(outputFile, std::ios::out | std::ios::binary | std::ios::trunc);
295 if (!of || !of.is_open()) {
296 std::cerr << "ERROR: cannot open " << outputFile << std::endl;
297 return 1;
298 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700299 buf = of.rdbuf();
300 }
301 else
302 {
303 buf = std::cout.rdbuf();
304 }
305
306 std::ostream os(buf);
307
Weiqi Shi5822e342014-08-21 20:05:30 -0700308 Consumer consumer(name, os, verbose, versioned, single,
Wentao Shangbcbc9292014-04-28 21:17:06 -0700309 interestLifetime, timeout);
310
311 try
312 {
313 consumer.run();
314 }
315 catch (const std::exception& e)
316 {
317 std::cerr << "ERROR: " << e.what() << std::endl;
318 }
319
320 return 0;
321}
322
323} // namespace repo
324
325int
326main(int argc, char** argv)
327{
328 return repo::main(argc, argv);
329}