blob: 5dcb4716861f69a7c8765acc1fa174363b2dd32a [file] [log] [blame]
Weiwei Liue4765012016-06-01 00:10:29 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventobf1c0692017-01-15 19:15:09 -05003 * Copyright (c) 2016-2017, Regents of the University of California,
4 * 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
27 */
28
29#include "pipeline-interests-fixed-window.hpp"
30#include "data-fetcher.hpp"
31
32namespace ndn {
33namespace chunks {
34
35PipelineInterestsFixedWindow::PipelineInterestsFixedWindow(Face& face, const Options& options)
36 : PipelineInterests(face)
37 , m_options(options)
38 , m_nextSegmentNo(0)
39 , m_hasFailure(false)
40{
41 m_segmentFetchers.resize(m_options.maxPipelineSize);
42}
43
44PipelineInterestsFixedWindow::~PipelineInterestsFixedWindow()
45{
46 cancel();
47}
48
49void
50PipelineInterestsFixedWindow::doRun()
51{
52 // if the FinalBlockId is unknown, this could potentially request non-existent segments
53 for (size_t nRequestedSegments = 0;
54 nRequestedSegments < m_options.maxPipelineSize;
55 ++nRequestedSegments) {
56 if (!fetchNextSegment(nRequestedSegments))
57 // all segments have been requested
58 break;
59 }
60}
61
62bool
63PipelineInterestsFixedWindow::fetchNextSegment(std::size_t pipeNo)
64{
65 if (isStopping())
66 return false;
67
68 if (m_hasFailure) {
69 onFailure("Fetching terminated but no final segment number has been found");
70 return false;
71 }
72
73 if (m_nextSegmentNo == m_excludedSegmentNo)
74 m_nextSegmentNo++;
75
76 if (m_hasFinalBlockId && m_nextSegmentNo > m_lastSegmentNo)
77 return false;
78
79 // send interest for next segment
80 if (m_options.isVerbose)
81 std::cerr << "Requesting segment #" << m_nextSegmentNo << std::endl;
82
83 Interest interest(Name(m_prefix).appendSegment(m_nextSegmentNo));
84 interest.setInterestLifetime(m_options.interestLifetime);
85 interest.setMustBeFresh(m_options.mustBeFresh);
86 interest.setMaxSuffixComponents(1);
87
88 auto fetcher = DataFetcher::fetch(m_face, interest,
89 m_options.maxRetriesOnTimeoutOrNack,
90 m_options.maxRetriesOnTimeoutOrNack,
91 bind(&PipelineInterestsFixedWindow::handleData, this, _1, _2, pipeNo),
92 bind(&PipelineInterestsFixedWindow::handleFail, this, _2, pipeNo),
93 bind(&PipelineInterestsFixedWindow::handleFail, this, _2, pipeNo),
94 m_options.isVerbose);
95
96 BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
97 m_segmentFetchers[pipeNo] = make_pair(fetcher, m_nextSegmentNo);
98 m_nextSegmentNo++;
99
100 return true;
101}
102
103void
104PipelineInterestsFixedWindow::doCancel()
105{
106 for (auto& fetcher : m_segmentFetchers) {
107 if (fetcher.first)
108 fetcher.first->cancel();
109 }
110
111 m_segmentFetchers.clear();
112}
113
114void
115PipelineInterestsFixedWindow::handleData(const Interest& interest, const Data& data, size_t pipeNo)
116{
117 if (isStopping())
118 return;
119
120 BOOST_ASSERT(data.getName().equals(interest.getName()));
121
122 if (m_options.isVerbose)
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500123 std::cerr << "Received segment #" << getSegmentFromPacket(data) << std::endl;
Weiwei Liue4765012016-06-01 00:10:29 -0700124
125 onData(interest, data);
126
127 if (!m_hasFinalBlockId && !data.getFinalBlockId().empty()) {
128 m_lastSegmentNo = data.getFinalBlockId().toSegment();
129 m_hasFinalBlockId = true;
130
131 for (auto& fetcher : m_segmentFetchers) {
132 if (fetcher.first == nullptr)
133 continue;
134
135 if (fetcher.second > m_lastSegmentNo) {
136 // stop trying to fetch segments that are beyond m_lastSegmentNo
137 fetcher.first->cancel();
138 }
139 else if (fetcher.first->hasError()) { // fetcher.second <= m_lastSegmentNo
140 // there was an error while fetching a segment that is part of the content
141 return onFailure("Failure retrieving segment #" + to_string(fetcher.second));
142 }
143 }
144 }
145
146 fetchNextSegment(pipeNo);
147}
148
149void PipelineInterestsFixedWindow::handleFail(const std::string& reason, std::size_t pipeNo)
150{
151 if (isStopping())
152 return;
153
154 // if the failed segment is definitely part of the content, raise a fatal error
155 if (m_hasFinalBlockId && m_segmentFetchers[pipeNo].second <= m_lastSegmentNo)
156 return onFailure(reason);
157
158 if (!m_hasFinalBlockId) {
159 bool areAllFetchersStopped = true;
160 for (auto& fetcher : m_segmentFetchers) {
161 if (fetcher.first == nullptr)
162 continue;
163
164 // cancel fetching all segments that follow
165 if (fetcher.second > m_segmentFetchers[pipeNo].second) {
166 fetcher.first->cancel();
167 }
168 else if (fetcher.first->isRunning()) { // fetcher.second <= m_segmentFetchers[pipeNo].second
169 areAllFetchersStopped = false;
170 }
171 }
172
173 if (areAllFetchersStopped) {
174 onFailure("Fetching terminated but no final segment number has been found");
175 }
176 else {
177 m_hasFailure = true;
178 }
179 }
180}
181
182} // namespace chunks
183} // namespace ndn