blob: e058ca0f99904518068bb5d21234bed624c19bac [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 Pesavento11fc3eb2024-01-26 01:46:56 -05003 * Copyright (c) 2016-2024, 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
Davide Pesavento5748e822024-01-26 18:40:22 -050029#include <boost/lexical_cast.hpp>
30
Andrea Tosatto672b9a72016-01-05 16:18:20 +010031#include <cmath>
Davide Pesavento5748e822024-01-26 18:40:22 -050032#include <iostream>
Andrea Tosatto672b9a72016-01-05 16:18:20 +010033
Davide Pesaventob3570c62022-02-19 19:19:00 -050034namespace ndn::chunks {
Andrea Tosatto672b9a72016-01-05 16:18:20 +010035
Davide Pesavento5748e822024-01-26 18:40:22 -050036std::shared_ptr<DataFetcher>
Andrea Tosatto672b9a72016-01-05 16:18:20 +010037DataFetcher::fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
38 DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
39 bool isVerbose)
40{
Davide Pesavento5748e822024-01-26 18:40:22 -050041 auto dataFetcher = std::shared_ptr<DataFetcher>(new DataFetcher(face,
42 maxNackRetries,
43 maxTimeoutRetries,
44 std::move(onData),
45 std::move(onNack),
46 std::move(onTimeout),
47 isVerbose));
Andrea Tosatto672b9a72016-01-05 16:18:20 +010048 dataFetcher->expressInterest(interest, dataFetcher);
49 return dataFetcher;
50}
51
52DataFetcher::DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
53 DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
54 bool isVerbose)
55 : m_face(face)
Davide Pesavento7e9d7e42023-11-11 15:00:03 -050056 , m_scheduler(m_face.getIoContext())
Andrea Tosatto672b9a72016-01-05 16:18:20 +010057 , m_onData(std::move(onData))
58 , m_onNack(std::move(onNack))
59 , m_onTimeout(std::move(onTimeout))
60 , m_maxNackRetries(maxNackRetries)
61 , m_maxTimeoutRetries(maxTimeoutRetries)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010062 , m_isVerbose(isVerbose)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010063{
64 BOOST_ASSERT(m_onData != nullptr);
65}
66
67void
68DataFetcher::cancel()
69{
70 if (isRunning()) {
71 m_isStopped = true;
Junxiao Shi06d008c2019-02-04 08:26:59 +000072 m_pendingInterest.cancel();
Andrea Tosatto672b9a72016-01-05 16:18:20 +010073 m_scheduler.cancelAllEvents();
74 }
75}
76
77void
Davide Pesavento5748e822024-01-26 18:40:22 -050078DataFetcher::expressInterest(const Interest& interest, const std::shared_ptr<DataFetcher>& self)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010079{
80 m_nCongestionRetries = 0;
Junxiao Shi06d008c2019-02-04 08:26:59 +000081 m_pendingInterest = m_face.expressInterest(interest,
Davide Pesavento5748e822024-01-26 18:40:22 -050082 [this, self] (auto&&... args) { handleData(std::forward<decltype(args)>(args)..., self); },
83 [this, self] (auto&&... args) { handleNack(std::forward<decltype(args)>(args)..., self); },
84 [this, self] (auto&&... args) { handleTimeout(std::forward<decltype(args)>(args)..., self); });
Andrea Tosatto672b9a72016-01-05 16:18:20 +010085}
86
87void
88DataFetcher::handleData(const Interest& interest, const Data& data,
Davide Pesavento5748e822024-01-26 18:40:22 -050089 const std::shared_ptr<DataFetcher>& self)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010090{
91 if (!isRunning())
92 return;
93
94 m_isStopped = true;
95 m_onData(interest, data);
96}
97
98void
99DataFetcher::handleNack(const Interest& interest, const lp::Nack& nack,
Davide Pesavento5748e822024-01-26 18:40:22 -0500100 const std::shared_ptr<DataFetcher>& self)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100101{
102 if (!isRunning())
103 return;
104
105 if (m_maxNackRetries != MAX_RETRIES_INFINITE)
106 ++m_nNacks;
107
108 if (m_isVerbose)
109 std::cerr << "Received Nack with reason " << nack.getReason()
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400110 << " for Interest " << interest << "\n";
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100111
112 if (m_nNacks <= m_maxNackRetries || m_maxNackRetries == MAX_RETRIES_INFINITE) {
113 Interest newInterest(interest);
114 newInterest.refreshNonce();
115
116 switch (nack.getReason()) {
117 case lp::NackReason::DUPLICATE: {
118 expressInterest(newInterest, self);
119 break;
120 }
121 case lp::NackReason::CONGESTION: {
122 time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, m_nCongestionRetries)));
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400123 if (backoffTime > MAX_CONGESTION_BACKOFF_TIME) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100124 backoffTime = MAX_CONGESTION_BACKOFF_TIME;
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400125 }
126 else {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100127 m_nCongestionRetries++;
Davide Pesaventobf2c5172019-03-20 19:08:09 -0400128 }
Davide Pesavento5748e822024-01-26 18:40:22 -0500129 m_scheduler.schedule(backoffTime, [this, newInterest, self] {
130 expressInterest(newInterest, self);
131 });
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100132 break;
133 }
134 default: {
135 m_hasError = true;
136 if (m_onNack)
137 m_onNack(interest, "Could not retrieve data for " + interest.getName().toUri() +
138 ", reason: " + boost::lexical_cast<std::string>(nack.getReason()));
139 break;
140 }
141 }
142 }
143 else {
144 m_hasError = true;
145 if (m_onNack)
Davide Pesavento11fc3eb2024-01-26 01:46:56 -0500146 m_onNack(interest, "Reached the maximum number of nack retries (" + std::to_string(m_maxNackRetries) +
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100147 ") while retrieving data for " + interest.getName().toUri());
148 }
149}
150
151void
Davide Pesavento5748e822024-01-26 18:40:22 -0500152DataFetcher::handleTimeout(const Interest& interest, const std::shared_ptr<DataFetcher>& self)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100153{
154 if (!isRunning())
155 return;
156
157 if (m_maxTimeoutRetries != MAX_RETRIES_INFINITE)
158 ++m_nTimeouts;
159
160 if (m_isVerbose)
Davide Pesaventof8d9a532021-07-03 16:04:12 -0400161 std::cerr << "Timeout for Interest " << interest << "\n";
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100162
163 if (m_nTimeouts <= m_maxTimeoutRetries || m_maxTimeoutRetries == MAX_RETRIES_INFINITE) {
164 Interest newInterest(interest);
165 newInterest.refreshNonce();
166 expressInterest(newInterest, self);
167 }
168 else {
169 m_hasError = true;
170 if (m_onTimeout)
Davide Pesavento11fc3eb2024-01-26 01:46:56 -0500171 m_onTimeout(interest, "Reached the maximum number of timeout retries (" + std::to_string(m_maxTimeoutRetries) +
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100172 ") while retrieving data for " + interest.getName().toUri());
173 }
174}
175
Davide Pesaventob3570c62022-02-19 19:19:00 -0500176} // namespace ndn::chunks