blob: ce112953310032ff2e4f29636d7ce10d458cf7d3 [file] [log] [blame]
Weiwei Liue4765012016-06-01 00:10:29 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +00002/*
schneiderklausd8197df2019-03-16 11:31:40 -07003 * Copyright (c) 2016-2019, Regents of the University of California,
Davide Pesaventobf1c0692017-01-15 19:15:09 -05004 * Colorado State University,
5 * University Pierre & Marie Curie, Sorbonne University.
Weiwei Liue4765012016-06-01 00:10:29 -07006 *
7 * This file is part of ndn-tools (Named Data Networking Essential Tools).
8 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
9 *
10 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
22 *
23 * @author Wentao Shang
24 * @author Steve DiBenedetto
25 * @author Andrea Tosatto
26 * @author Davide Pesavento
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +000027 * @author Chavoosh Ghasemi
Weiwei Liue4765012016-06-01 00:10:29 -070028 */
29
schneiderklausd8197df2019-03-16 11:31:40 -070030#include "pipeline-interests-fixed.hpp"
Weiwei Liue4765012016-06-01 00:10:29 -070031#include "data-fetcher.hpp"
32
33namespace ndn {
34namespace chunks {
35
Davide Pesavento97a33b22019-10-17 22:10:47 -040036PipelineInterestsFixed::PipelineInterestsFixed(Face& face, const Options& opts)
37 : PipelineInterests(face, opts)
Weiwei Liue4765012016-06-01 00:10:29 -070038{
39 m_segmentFetchers.resize(m_options.maxPipelineSize);
Davide Pesavento97a33b22019-10-17 22:10:47 -040040
41 if (m_options.isVerbose) {
42 printOptions();
43 std::cerr << "\tPipeline size = " << m_options.maxPipelineSize << "\n";
44 }
Weiwei Liue4765012016-06-01 00:10:29 -070045}
46
schneiderklausd8197df2019-03-16 11:31:40 -070047PipelineInterestsFixed::~PipelineInterestsFixed()
Weiwei Liue4765012016-06-01 00:10:29 -070048{
49 cancel();
50}
51
52void
schneiderklausd8197df2019-03-16 11:31:40 -070053PipelineInterestsFixed::doRun()
Weiwei Liue4765012016-06-01 00:10:29 -070054{
55 // if the FinalBlockId is unknown, this could potentially request non-existent segments
56 for (size_t nRequestedSegments = 0;
57 nRequestedSegments < m_options.maxPipelineSize;
58 ++nRequestedSegments) {
59 if (!fetchNextSegment(nRequestedSegments))
60 // all segments have been requested
61 break;
62 }
63}
64
65bool
schneiderklausd8197df2019-03-16 11:31:40 -070066PipelineInterestsFixed::fetchNextSegment(std::size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -070067{
68 if (isStopping())
69 return false;
70
71 if (m_hasFailure) {
72 onFailure("Fetching terminated but no final segment number has been found");
73 return false;
74 }
75
Davide Pesaventob587cfd2017-11-04 16:29:50 -040076 uint64_t nextSegmentNo = getNextSegmentNo();
77 if (m_hasFinalBlockId && nextSegmentNo > m_lastSegmentNo)
78 return false;
Weiwei Liue4765012016-06-01 00:10:29 -070079
80 // send interest for next segment
81 if (m_options.isVerbose)
Davide Pesaventob587cfd2017-11-04 16:29:50 -040082 std::cerr << "Requesting segment #" << nextSegmentNo << std::endl;
Weiwei Liue4765012016-06-01 00:10:29 -070083
Davide Pesavento84d84772019-04-07 14:40:07 -040084 auto interest = Interest()
85 .setName(Name(m_prefix).appendSegment(nextSegmentNo))
86 .setCanBePrefix(false)
87 .setMustBeFresh(m_options.mustBeFresh)
88 .setInterestLifetime(m_options.interestLifetime);
Weiwei Liue4765012016-06-01 00:10:29 -070089
90 auto fetcher = DataFetcher::fetch(m_face, interest,
91 m_options.maxRetriesOnTimeoutOrNack,
92 m_options.maxRetriesOnTimeoutOrNack,
schneiderklausd8197df2019-03-16 11:31:40 -070093 bind(&PipelineInterestsFixed::handleData, this, _1, _2, pipeNo),
94 bind(&PipelineInterestsFixed::handleFail, this, _2, pipeNo),
95 bind(&PipelineInterestsFixed::handleFail, this, _2, pipeNo),
Weiwei Liue4765012016-06-01 00:10:29 -070096 m_options.isVerbose);
97
98 BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
Davide Pesaventob587cfd2017-11-04 16:29:50 -040099 m_segmentFetchers[pipeNo] = make_pair(fetcher, nextSegmentNo);
Weiwei Liue4765012016-06-01 00:10:29 -0700100
101 return true;
102}
103
104void
schneiderklausd8197df2019-03-16 11:31:40 -0700105PipelineInterestsFixed::doCancel()
Weiwei Liue4765012016-06-01 00:10:29 -0700106{
107 for (auto& fetcher : m_segmentFetchers) {
108 if (fetcher.first)
109 fetcher.first->cancel();
110 }
111
112 m_segmentFetchers.clear();
113}
114
115void
schneiderklausd8197df2019-03-16 11:31:40 -0700116PipelineInterestsFixed::handleData(const Interest& interest, const Data& data, size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -0700117{
118 if (isStopping())
119 return;
120
Davide Pesavento84d84772019-04-07 14:40:07 -0400121 // Interest was expressed with CanBePrefix=false
Weiwei Liue4765012016-06-01 00:10:29 -0700122 BOOST_ASSERT(data.getName().equals(interest.getName()));
123
124 if (m_options.isVerbose)
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500125 std::cerr << "Received segment #" << getSegmentFromPacket(data) << std::endl;
Weiwei Liue4765012016-06-01 00:10:29 -0700126
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400127 onData(data);
Weiwei Liue4765012016-06-01 00:10:29 -0700128
Davide Pesavento969cd5a2018-04-20 16:27:47 -0400129 if (!m_hasFinalBlockId && data.getFinalBlock()) {
130 m_lastSegmentNo = data.getFinalBlock()->toSegment();
Weiwei Liue4765012016-06-01 00:10:29 -0700131 m_hasFinalBlockId = true;
132
133 for (auto& fetcher : m_segmentFetchers) {
134 if (fetcher.first == nullptr)
135 continue;
136
137 if (fetcher.second > m_lastSegmentNo) {
138 // stop trying to fetch segments that are beyond m_lastSegmentNo
139 fetcher.first->cancel();
140 }
141 else if (fetcher.first->hasError()) { // fetcher.second <= m_lastSegmentNo
142 // there was an error while fetching a segment that is part of the content
143 return onFailure("Failure retrieving segment #" + to_string(fetcher.second));
144 }
145 }
146 }
147
Ryan Wickman2c9933c2018-06-12 11:51:51 -0500148 if (allSegmentsReceived()) {
Davide Pesaventof6991e12018-01-08 20:58:50 -0500149 if (!m_options.isQuiet) {
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +0000150 printSummary();
151 }
152 }
153 else {
154 fetchNextSegment(pipeNo);
155 }
Weiwei Liue4765012016-06-01 00:10:29 -0700156}
157
schneiderklausd8197df2019-03-16 11:31:40 -0700158void PipelineInterestsFixed::handleFail(const std::string& reason, std::size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -0700159{
160 if (isStopping())
161 return;
162
163 // if the failed segment is definitely part of the content, raise a fatal error
164 if (m_hasFinalBlockId && m_segmentFetchers[pipeNo].second <= m_lastSegmentNo)
165 return onFailure(reason);
166
167 if (!m_hasFinalBlockId) {
168 bool areAllFetchersStopped = true;
169 for (auto& fetcher : m_segmentFetchers) {
170 if (fetcher.first == nullptr)
171 continue;
172
173 // cancel fetching all segments that follow
174 if (fetcher.second > m_segmentFetchers[pipeNo].second) {
175 fetcher.first->cancel();
176 }
177 else if (fetcher.first->isRunning()) { // fetcher.second <= m_segmentFetchers[pipeNo].second
178 areAllFetchersStopped = false;
179 }
180 }
181
182 if (areAllFetchersStopped) {
183 onFailure("Fetching terminated but no final segment number has been found");
184 }
185 else {
186 m_hasFailure = true;
187 }
188 }
189}
190
191} // namespace chunks
192} // namespace ndn