blob: 2e5fc9e6e659036f6437df74bd90f7b4f93da6c6 [file] [log] [blame]
Andrea Tosatto672b9a72016-01-05 16:18:20 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi06d008c2019-02-04 08:26:59 +00002/*
Davide Pesaventob3570c62022-02-19 19:19:00 -05003 * Copyright (c) 2016-2022, Regents of the University of California,
Junxiao Shi06d008c2019-02-04 08:26:59 +00004 * Colorado State University,
5 * University Pierre & Marie Curie, Sorbonne University.
Andrea Tosatto672b9a72016-01-05 16:18:20 +01006 *
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 Andrea Tosatto
24 * @author Davide Pesavento
25 */
26
27#include "data-fetcher.hpp"
28
29#include <cmath>
30
Davide Pesaventob3570c62022-02-19 19:19:00 -050031namespace ndn::chunks {
Andrea Tosatto672b9a72016-01-05 16:18:20 +010032
33shared_ptr<DataFetcher>
34DataFetcher::fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
35 DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
36 bool isVerbose)
37{
38 auto dataFetcher = shared_ptr<DataFetcher>(new DataFetcher(face,
39 maxNackRetries,
40 maxTimeoutRetries,
41 std::move(onData),
42 std::move(onNack),
43 std::move(onTimeout),
44 isVerbose));
45 dataFetcher->expressInterest(interest, dataFetcher);
46 return dataFetcher;
47}
48
49DataFetcher::DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
50 DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
51 bool isVerbose)
52 : m_face(face)
53 , m_scheduler(m_face.getIoService())
54 , m_onData(std::move(onData))
55 , m_onNack(std::move(onNack))
56 , m_onTimeout(std::move(onTimeout))
57 , m_maxNackRetries(maxNackRetries)
58 , m_maxTimeoutRetries(maxTimeoutRetries)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010059 , m_isVerbose(isVerbose)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010060{
61 BOOST_ASSERT(m_onData != nullptr);
62}
63
64void
65DataFetcher::cancel()
66{
67 if (isRunning()) {
68 m_isStopped = true;
Junxiao Shi06d008c2019-02-04 08:26:59 +000069 m_pendingInterest.cancel();
Andrea Tosatto672b9a72016-01-05 16:18:20 +010070 m_scheduler.cancelAllEvents();
71 }
72}
73
74void
75DataFetcher::expressInterest(const Interest& interest, const shared_ptr<DataFetcher>& self)
76{
77 m_nCongestionRetries = 0;
Junxiao Shi06d008c2019-02-04 08:26:59 +000078 m_pendingInterest = m_face.expressInterest(interest,
Davide Pesaventof8d9a532021-07-03 16:04:12 -040079 [=] (auto&&... args) { handleData(std::forward<decltype(args)>(args)..., self); },
80 [=] (auto&&... args) { handleNack(std::forward<decltype(args)>(args)..., self); },
81 [=] (auto&&... args) { handleTimeout(std::forward<decltype(args)>(args)..., self); });
Andrea Tosatto672b9a72016-01-05 16:18:20 +010082}
83
84void
85DataFetcher::handleData(const Interest& interest, const Data& data,
86 const shared_ptr<DataFetcher>& self)
87{
88 if (!isRunning())
89 return;
90
91 m_isStopped = true;
92 m_onData(interest, data);
93}
94
95void
96DataFetcher::handleNack(const Interest& interest, const lp::Nack& nack,
97 const shared_ptr<DataFetcher>& self)
98{
99 if (!isRunning())
100 return;
101
102 if (m_maxNackRetries != MAX_RETRIES_INFINITE)
103 ++m_nNacks;
104
105 if (m_isVerbose)
106 std::cerr << "Received Nack with reason " << nack.getReason()
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400107 << " for Interest " << interest << "\n";
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100108
109 if (m_nNacks <= m_maxNackRetries || m_maxNackRetries == MAX_RETRIES_INFINITE) {
110 Interest newInterest(interest);
111 newInterest.refreshNonce();
112
113 switch (nack.getReason()) {
114 case lp::NackReason::DUPLICATE: {
115 expressInterest(newInterest, self);
116 break;
117 }
118 case lp::NackReason::CONGESTION: {
119 time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, m_nCongestionRetries)));
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400120 if (backoffTime > MAX_CONGESTION_BACKOFF_TIME) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100121 backoffTime = MAX_CONGESTION_BACKOFF_TIME;
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400122 }
123 else {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100124 m_nCongestionRetries++;
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400125 }
126 m_scheduler.schedule(backoffTime, [=] { expressInterest(newInterest, self); });
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100127 break;
128 }
129 default: {
130 m_hasError = true;
131 if (m_onNack)
132 m_onNack(interest, "Could not retrieve data for " + interest.getName().toUri() +
133 ", reason: " + boost::lexical_cast<std::string>(nack.getReason()));
134 break;
135 }
136 }
137 }
138 else {
139 m_hasError = true;
140 if (m_onNack)
141 m_onNack(interest, "Reached the maximum number of nack retries (" + to_string(m_maxNackRetries) +
142 ") while retrieving data for " + interest.getName().toUri());
143 }
144}
145
146void
147DataFetcher::handleTimeout(const Interest& interest, const shared_ptr<DataFetcher>& self)
148{
149 if (!isRunning())
150 return;
151
152 if (m_maxTimeoutRetries != MAX_RETRIES_INFINITE)
153 ++m_nTimeouts;
154
155 if (m_isVerbose)
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400156 std::cerr << "Timeout for Interest " << interest << "\n";
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100157
158 if (m_nTimeouts <= m_maxTimeoutRetries || m_maxTimeoutRetries == MAX_RETRIES_INFINITE) {
159 Interest newInterest(interest);
160 newInterest.refreshNonce();
161 expressInterest(newInterest, self);
162 }
163 else {
164 m_hasError = true;
165 if (m_onTimeout)
166 m_onTimeout(interest, "Reached the maximum number of timeout retries (" + to_string(m_maxTimeoutRetries) +
167 ") while retrieving data for " + interest.getName().toUri());
168 }
169}
170
Davide Pesaventob3570c62022-02-19 19:19:00 -0500171} // namespace ndn::chunks