blob: 9e8ffa1c24e71c89b59ca9947f2532335fb40c5f [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/*
Davide Pesavento11fc3eb2024-01-26 01:46:56 -05003 * Copyright (c) 2016-2024, 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
Davide Pesavento5748e822024-01-26 18:40:22 -050033#include <iostream>
34
Davide Pesaventob3570c62022-02-19 19:19:00 -050035namespace ndn::chunks {
Weiwei Liue4765012016-06-01 00:10:29 -070036
Davide Pesavento97a33b22019-10-17 22:10:47 -040037PipelineInterestsFixed::PipelineInterestsFixed(Face& face, const Options& opts)
38 : PipelineInterests(face, opts)
Weiwei Liue4765012016-06-01 00:10:29 -070039{
40 m_segmentFetchers.resize(m_options.maxPipelineSize);
Davide Pesavento97a33b22019-10-17 22:10:47 -040041
42 if (m_options.isVerbose) {
43 printOptions();
44 std::cerr << "\tPipeline size = " << m_options.maxPipelineSize << "\n";
45 }
Weiwei Liue4765012016-06-01 00:10:29 -070046}
47
schneiderklausd8197df2019-03-16 11:31:40 -070048PipelineInterestsFixed::~PipelineInterestsFixed()
Weiwei Liue4765012016-06-01 00:10:29 -070049{
50 cancel();
51}
52
53void
schneiderklausd8197df2019-03-16 11:31:40 -070054PipelineInterestsFixed::doRun()
Weiwei Liue4765012016-06-01 00:10:29 -070055{
56 // if the FinalBlockId is unknown, this could potentially request non-existent segments
57 for (size_t nRequestedSegments = 0;
58 nRequestedSegments < m_options.maxPipelineSize;
59 ++nRequestedSegments) {
60 if (!fetchNextSegment(nRequestedSegments))
61 // all segments have been requested
62 break;
63 }
64}
65
66bool
schneiderklausd8197df2019-03-16 11:31:40 -070067PipelineInterestsFixed::fetchNextSegment(std::size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -070068{
69 if (isStopping())
70 return false;
71
72 if (m_hasFailure) {
73 onFailure("Fetching terminated but no final segment number has been found");
74 return false;
75 }
76
Davide Pesaventob587cfd2017-11-04 16:29:50 -040077 uint64_t nextSegmentNo = getNextSegmentNo();
78 if (m_hasFinalBlockId && nextSegmentNo > m_lastSegmentNo)
79 return false;
Weiwei Liue4765012016-06-01 00:10:29 -070080
81 // send interest for next segment
82 if (m_options.isVerbose)
Davide Pesaventof8d9a532021-07-03 16:04:12 -040083 std::cerr << "Requesting segment #" << nextSegmentNo << "\n";
Weiwei Liue4765012016-06-01 00:10:29 -070084
Davide Pesavento84d84772019-04-07 14:40:07 -040085 auto interest = Interest()
86 .setName(Name(m_prefix).appendSegment(nextSegmentNo))
Davide Pesavento84d84772019-04-07 14:40:07 -040087 .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,
Davide Pesavento5748e822024-01-26 18:40:22 -050093 [this, pipeNo] (const auto& interest, const auto& data) {
Davide Pesaventof8d9a532021-07-03 16:04:12 -040094 handleData(interest, data, pipeNo);
95 },
Davide Pesavento5748e822024-01-26 18:40:22 -050096 [this, pipeNo] (const auto&, const auto& reason) {
Davide Pesaventof8d9a532021-07-03 16:04:12 -040097 handleFail(reason, pipeNo);
98 },
Davide Pesavento5748e822024-01-26 18:40:22 -050099 [this, pipeNo] (const auto&, const auto& reason) {
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400100 handleFail(reason, pipeNo);
101 },
Weiwei Liue4765012016-06-01 00:10:29 -0700102 m_options.isVerbose);
103
104 BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
Davide Pesaventob587cfd2017-11-04 16:29:50 -0400105 m_segmentFetchers[pipeNo] = make_pair(fetcher, nextSegmentNo);
Weiwei Liue4765012016-06-01 00:10:29 -0700106
107 return true;
108}
109
110void
schneiderklausd8197df2019-03-16 11:31:40 -0700111PipelineInterestsFixed::doCancel()
Weiwei Liue4765012016-06-01 00:10:29 -0700112{
113 for (auto& fetcher : m_segmentFetchers) {
114 if (fetcher.first)
115 fetcher.first->cancel();
116 }
117
118 m_segmentFetchers.clear();
119}
120
121void
schneiderklausd8197df2019-03-16 11:31:40 -0700122PipelineInterestsFixed::handleData(const Interest& interest, const Data& data, size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -0700123{
124 if (isStopping())
125 return;
126
Davide Pesavento84d84772019-04-07 14:40:07 -0400127 // Interest was expressed with CanBePrefix=false
Weiwei Liue4765012016-06-01 00:10:29 -0700128 BOOST_ASSERT(data.getName().equals(interest.getName()));
129
130 if (m_options.isVerbose)
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400131 std::cerr << "Received segment #" << getSegmentFromPacket(data) << "\n";
Weiwei Liue4765012016-06-01 00:10:29 -0700132
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400133 onData(data);
Weiwei Liue4765012016-06-01 00:10:29 -0700134
Davide Pesavento969cd5a2018-04-20 16:27:47 -0400135 if (!m_hasFinalBlockId && data.getFinalBlock()) {
136 m_lastSegmentNo = data.getFinalBlock()->toSegment();
Weiwei Liue4765012016-06-01 00:10:29 -0700137 m_hasFinalBlockId = true;
138
139 for (auto& fetcher : m_segmentFetchers) {
140 if (fetcher.first == nullptr)
141 continue;
142
143 if (fetcher.second > m_lastSegmentNo) {
144 // stop trying to fetch segments that are beyond m_lastSegmentNo
145 fetcher.first->cancel();
146 }
147 else if (fetcher.first->hasError()) { // fetcher.second <= m_lastSegmentNo
148 // there was an error while fetching a segment that is part of the content
Davide Pesavento11fc3eb2024-01-26 01:46:56 -0500149 return onFailure("Failure retrieving segment #" + std::to_string(fetcher.second));
Weiwei Liue4765012016-06-01 00:10:29 -0700150 }
151 }
152 }
153
Ryan Wickman2c9933c2018-06-12 11:51:51 -0500154 if (allSegmentsReceived()) {
Davide Pesaventof6991e12018-01-08 20:58:50 -0500155 if (!m_options.isQuiet) {
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +0000156 printSummary();
157 }
158 }
159 else {
160 fetchNextSegment(pipeNo);
161 }
Weiwei Liue4765012016-06-01 00:10:29 -0700162}
163
schneiderklausd8197df2019-03-16 11:31:40 -0700164void PipelineInterestsFixed::handleFail(const std::string& reason, std::size_t pipeNo)
Weiwei Liue4765012016-06-01 00:10:29 -0700165{
166 if (isStopping())
167 return;
168
169 // if the failed segment is definitely part of the content, raise a fatal error
170 if (m_hasFinalBlockId && m_segmentFetchers[pipeNo].second <= m_lastSegmentNo)
171 return onFailure(reason);
172
173 if (!m_hasFinalBlockId) {
174 bool areAllFetchersStopped = true;
175 for (auto& fetcher : m_segmentFetchers) {
176 if (fetcher.first == nullptr)
177 continue;
178
179 // cancel fetching all segments that follow
180 if (fetcher.second > m_segmentFetchers[pipeNo].second) {
181 fetcher.first->cancel();
182 }
183 else if (fetcher.first->isRunning()) { // fetcher.second <= m_segmentFetchers[pipeNo].second
184 areAllFetchersStopped = false;
185 }
186 }
187
188 if (areAllFetchersStopped) {
189 onFailure("Fetching terminated but no final segment number has been found");
190 }
191 else {
192 m_hasFailure = true;
193 }
194 }
195}
196
Davide Pesaventob3570c62022-02-19 19:19:00 -0500197} // namespace ndn::chunks