blob: 50f8ab358691877702c7d573835d870d7df14902 [file] [log] [blame]
Wentao Shangbcbc9292014-04-28 21:17:06 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California.
4 *
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
26using namespace ndn;
27
Weiqi Shi5822e342014-08-21 20:05:30 -070028static const int MAX_RETRY = 3;
29
Wentao Shangbcbc9292014-04-28 21:17:06 -070030void
31Consumer::fetchData(const Name& name)
32{
33 Interest interest(name);
34 interest.setInterestLifetime(m_interestLifetime);
Weiqi Shi5822e342014-08-21 20:05:30 -070035 //std::cout<<"interest name = "<<interest.getName()<<std::endl;
Wentao Shangbcbc9292014-04-28 21:17:06 -070036 if (m_hasVersion)
37 {
38 interest.setMustBeFresh(m_mustBeFresh);
39 }
40 else
41 {
42 interest.setMustBeFresh(true);
43 interest.setChildSelector(1);
44 }
45
46 m_face.expressInterest(interest,
Weiqi Shi5822e342014-08-21 20:05:30 -070047 m_hasVersion ?
48 bind(&Consumer::onVersionedData, this, _1, _2)
49 :
50 bind(&Consumer::onUnversionedData, this, _1, _2),
Wentao Shangbcbc9292014-04-28 21:17:06 -070051 bind(&Consumer::onTimeout, this, _1));
52}
53
54void
55Consumer::run()
56{
57 // Send the first Interest
58 Name name(m_dataName);
Wentao Shangbcbc9292014-04-28 21:17:06 -070059
Weiqi Shi5822e342014-08-21 20:05:30 -070060 m_nextSegment++;
Wentao Shangbcbc9292014-04-28 21:17:06 -070061 fetchData(name);
62
63 // processEvents will block until the requested data received or timeout occurs
64 m_face.processEvents(m_timeout);
65}
66
67void
Weiqi Shi5822e342014-08-21 20:05:30 -070068Consumer::onVersionedData(const Interest& interest, Data& data)
Wentao Shangbcbc9292014-04-28 21:17:06 -070069{
70 const Name& name = data.getName();
Wentao Shangbcbc9292014-04-28 21:17:06 -070071
Weiqi Shi5822e342014-08-21 20:05:30 -070072 // the received data name may have segment number or not
73 if (name.size() == m_dataName.size()) {
74 if (!m_isSingle) {
75 Name fetchName = name;
76 fetchName.appendSegment(0);
77 fetchData(fetchName);
78 }
79 }
80 else if (name.size() == m_dataName.size() + 1) {
81 if (!m_isSingle) {
82 if (m_isFirst) {
83 uint64_t segment = name[-1].toSegment();
84 if (segment != 0) {
85 fetchData(Name(m_dataName).appendSegment(0));
86 m_isFirst = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -070087 return;
88 }
Weiqi Shi5822e342014-08-21 20:05:30 -070089 m_isFirst = false;
90 }
91 fetchNextData(name, data);
Wentao Shangbcbc9292014-04-28 21:17:06 -070092 }
Weiqi Shi5822e342014-08-21 20:05:30 -070093 else {
94 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
95 return;
96 }
97 }
98 else {
99 std::cerr << "ERROR: Name size does not match" << std::endl;
100 return;
101 }
102 readData(data);
103}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700104
Weiqi Shi5822e342014-08-21 20:05:30 -0700105void
106Consumer::onUnversionedData(const Interest& interest, Data& data)
107{
108 const Name& name = data.getName();
109 //std::cout<<"recevied data name = "<<name<<std::endl;
110 if (name.size() == m_dataName.size() + 1) {
111 if (!m_isSingle) {
112 Name fetchName = name;
113 fetchName.append(name[-1]).appendSegment(0);
114 fetchData(fetchName);
115 }
116 }
117 else if (name.size() == m_dataName.size() + 2) {
118 if (!m_isSingle) {
119 if (m_isFirst) {
120 uint64_t segment = name[-1].toSegment();
121 if (segment != 0) {
122 fetchData(Name(m_dataName).append(name[-2]).appendSegment(0));
123 m_isFirst = false;
124 return;
125 }
126 m_isFirst = false;
127 }
128 fetchNextData(name, data);
129 }
130 else {
131 std::cerr << "ERROR: Data is not stored in a single packet" << std::endl;
132 return;
133 }
134 }
135 else {
136 std::cerr << "ERROR: Name size does not match" << std::endl;
137 return;
138 }
139 readData(data);
140}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700141
Weiqi Shi5822e342014-08-21 20:05:30 -0700142void
143Consumer::readData(const Data& data)
144{
Wentao Shangbcbc9292014-04-28 21:17:06 -0700145 const Block& content = data.getContent();
146 m_os.write(reinterpret_cast<const char*>(content.value()), content.value_size());
147 m_totalSize += content.value_size();
148 if (m_verbose)
Weiqi Shi5822e342014-08-21 20:05:30 -0700149 {
150 std::cerr << "LOG: received data = " << data.getName() << std::endl;
151 }
152 if (m_isFinished || m_isSingle) {
153 std::cerr << "INFO: End of file is reached." << std::endl;
154 std::cerr << "INFO: Total # of segments received: " << m_nextSegment << std::endl;
155 std::cerr << "INFO: Total # bytes of content received: " << m_totalSize << std::endl;
156 }
Wentao Shangbcbc9292014-04-28 21:17:06 -0700157}
158
Weiqi Shi5822e342014-08-21 20:05:30 -0700159void
160Consumer::fetchNextData(const Name& name, const Data& data)
161{
162 uint64_t segment = name[-1].toSegment();
163 BOOST_ASSERT(segment == (m_nextSegment - 1));
164 const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
165 if (finalBlockId == name[-1]) {
166 m_isFinished = true;
167 }
168 else
169 {
170 // Reset retry counter
171 m_retryCount = 0;
172 if (m_hasVersion)
173 fetchData(Name(m_dataName).appendSegment(m_nextSegment++));
174 else
175 fetchData(Name(m_dataName).append(name[-2]).appendSegment(m_nextSegment++));
176 }
177}
Wentao Shangbcbc9292014-04-28 21:17:06 -0700178
179void
180Consumer::onTimeout(const Interest& interest)
181{
Weiqi Shi5822e342014-08-21 20:05:30 -0700182 if (m_retryCount++ < MAX_RETRY)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700183 {
184 // Retransmit the interest
185 fetchData(interest.getName());
186 if (m_verbose)
187 {
188 std::cerr << "TIMEOUT: retransmit interest for " << interest.getName() << std::endl;
189 }
190 }
191 else
192 {
193 std::cerr << "TIMEOUT: last interest sent for segment #" << (m_nextSegment - 1) << std::endl;
Weiqi Shi5822e342014-08-21 20:05:30 -0700194 std::cerr << "TIMEOUT: abort fetching after " << MAX_RETRY
Wentao Shangbcbc9292014-04-28 21:17:06 -0700195 << " times of retry" << std::endl;
196 }
197}
198
199
200int
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
216
217int
218main(int argc, char** argv)
219{
220 std::string name;
221 const char* outputFile = 0;
Weiqi Shi5822e342014-08-21 20:05:30 -0700222 bool verbose = false, versioned = false, single = false;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700223 int interestLifetime = 4000; // in milliseconds
224 int timeout = 0; // in milliseconds
225
226 int opt;
Weiqi Shi5822e342014-08-21 20:05:30 -0700227 while ((opt = getopt(argc, argv, "vsul:w:o:")) != -1)
Wentao Shangbcbc9292014-04-28 21:17:06 -0700228 {
229 switch (opt) {
230 case 'v':
231 verbose = true;
232 break;
Weiqi Shi5822e342014-08-21 20:05:30 -0700233 case 's':
234 single = true;
235 break;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700236 case 'u':
Weiqi Shi5822e342014-08-21 20:05:30 -0700237 versioned = true;
Wentao Shangbcbc9292014-04-28 21:17:06 -0700238 break;
239 case 'l':
240 try
241 {
242 interestLifetime = boost::lexical_cast<int>(optarg);
243 }
244 catch (boost::bad_lexical_cast&)
245 {
246 std::cerr << "ERROR: -l option should be an integer." << std::endl;
247 return 1;
248 }
249 interestLifetime = std::max(interestLifetime, 0);
250 break;
251 case 'w':
252 try
253 {
254 timeout = boost::lexical_cast<int>(optarg);
255 }
256 catch (boost::bad_lexical_cast&)
257 {
258 std::cerr << "ERROR: -w option should be an integer." << std::endl;
259 return 1;
260 }
261 timeout = std::max(timeout, 0);
262 break;
263 case 'o':
264 outputFile = optarg;
265 break;
266 default:
267 return usage(argv[0]);
268 }
269 }
270
271 if (optind < argc)
272 {
273 name = argv[optind];
274 }
275
276 if (name.empty())
277 {
278 return usage(argv[0]);
279 }
280
281 std::streambuf* buf;
282 std::ofstream of;
283
284 if (outputFile != 0)
285 {
286 of.open(outputFile);
287 if (!of)
288 {
289 std::cerr << "ERROR: output file is invalid" << std::endl;
290 return 1;
291 }
292 buf = of.rdbuf();
293 }
294 else
295 {
296 buf = std::cout.rdbuf();
297 }
298
299 std::ostream os(buf);
300
Weiqi Shi5822e342014-08-21 20:05:30 -0700301 Consumer consumer(name, os, verbose, versioned, single,
Wentao Shangbcbc9292014-04-28 21:17:06 -0700302 interestLifetime, timeout);
303
304 try
305 {
306 consumer.run();
307 }
308 catch (const std::exception& e)
309 {
310 std::cerr << "ERROR: " << e.what() << std::endl;
311 }
312
313 return 0;
314}
315
316} // namespace repo
317
318int
319main(int argc, char** argv)
320{
321 return repo::main(argc, argv);
322}