blob: f3cb2ce0c48e7451a820dd1357acf3ae5059ec64 [file] [log] [blame]
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -08002/*
Eric Newberrye345baa2018-05-23 18:17:07 -07003 * Copyright (c) 2013-2018, Regents of the University of California,
4 * Colorado State University,
5 * University Pierre & Marie Curie, Sorbonne University.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -07006 *
7 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
8 *
9 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU Lesser General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later version.
12 *
13 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16 *
17 * You should have received copies of the GNU General Public License and GNU Lesser
18 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Eric Newberrye345baa2018-05-23 18:17:07 -070022 *
23 * @author Shuo Yang
24 * @author Weiwei Liu
25 * @author Chavoosh Ghasemi
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070026 */
27
28#ifndef NDN_UTIL_SEGMENT_FETCHER_HPP
29#define NDN_UTIL_SEGMENT_FETCHER_HPP
30
31#include "../common.hpp"
32#include "../face.hpp"
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -080033#include "../security/v2/validator.hpp"
Eric Newberrye345baa2018-05-23 18:17:07 -070034#include "rtt-estimator.hpp"
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +000035#include "scheduler.hpp"
36#include "signal.hpp"
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070037
Eric Newberrye345baa2018-05-23 18:17:07 -070038#include <queue>
39
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070040namespace ndn {
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070041namespace util {
42
43/**
Eric Newberry2b765f82018-06-25 14:51:13 -070044 * @brief Utility class to fetch the latest version of a segmented object.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070045 *
Eric Newberry2b765f82018-06-25 14:51:13 -070046 * SegmentFetcher assumes that segments in the object are named `/<prefix>/<version>/<segment>`,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070047 * where:
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070048 * - `<prefix>` is the specified prefix,
49 * - `<version>` is an unknown version that needs to be discovered, and
Eric Newberry2b765f82018-06-25 14:51:13 -070050 * - `<segment>` is a segment number (The number of segments in the object is unknown until a Data
51 * packet containing the `FinalBlockId` field is receieved.)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070052 *
53 * The following logic is implemented in SegmentFetcher:
54 *
Eric Newberry2b765f82018-06-25 14:51:13 -070055 * 1. Express an Interest to discover the latest version of the object:
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070056 *
Eric Newberry2b765f82018-06-25 14:51:13 -070057 * >> Interest: `/<prefix>?ndn.CanBePrefix=true&ndn.MustBeFresh=true`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070058 *
Eric Newberry2b765f82018-06-25 14:51:13 -070059 * 2. Infer the latest version of the object: `<version> = Data.getName().get(-2)`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070060 *
Eric Newberry2b765f82018-06-25 14:51:13 -070061 * 3. Keep sending Interests for future segments until an error occurs or the number of segments
62 * indicated by the FinalBlockId in a received Data packet is reached. This retrieval will start
63 * at segment 1 if segment 0 was received in response to the Interest expressed in step 2;
64 * otherwise, retrieval will start at segment 0. By default, congestion control will be used to
65 * manage the Interest window size. Interests expressed in this step will follow this Name
66 * format:
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070067 *
Eric Newberry2b765f82018-06-25 14:51:13 -070068 * >> Interest: `/<prefix>/<version>/<segment=(N)>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070069 *
Eric Newberry2b765f82018-06-25 14:51:13 -070070 * 4. Signal `onComplete` with a memory block that combines the content of all segments in the
Eric Newberrye345baa2018-05-23 18:17:07 -070071 * object.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070072 *
Eric Newberrye345baa2018-05-23 18:17:07 -070073 * If an error occurs during the fetching process, `onError` is signaled with one of the error codes
74 * from `SegmentFetcher::ErrorCode`.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070075 *
Eric Newberrye345baa2018-05-23 18:17:07 -070076 * A Validator instance must be specified to validate individual segments. Every time a segment has
77 * been successfully validated, `afterValidationSuccess` will be signaled. If a segment fails
78 * validation, `afterValidationFailure` will be signaled.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070079 *
80 * Examples:
81 *
Eric Newberry2b765f82018-06-25 14:51:13 -070082 * @code
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070083 * void
Eric Newberrye345baa2018-05-23 18:17:07 -070084 * afterFetchComplete(ConstBufferPtr data)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070085 * {
86 * ...
87 * }
88 *
89 * void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050090 * afterFetchError(uint32_t errorCode, const std::string& errorMsg)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070091 * {
92 * ...
93 * }
94 *
95 * ...
Eric Newberrye345baa2018-05-23 18:17:07 -070096 * auto fetcher = SegmentFetcher::start(face, Interest("/data/prefix"), validator);
97 * fetcher->onComplete.connect(bind(&afterFetchComplete, this, _1));
98 * fetcher->onError.connect(bind(&afterFetchError, this, _1, _2));
Eric Newberry2b765f82018-06-25 14:51:13 -070099 * @endcode
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700100 *
101 */
102class SegmentFetcher : noncopyable
103{
104public:
Eric Newberrye345baa2018-05-23 18:17:07 -0700105 // Deprecated: will be removed when deprecated fetch() API is removed - use start() instead
Eric Newberrycc910cd2018-05-06 17:01:40 -0700106 typedef function<void (ConstBufferPtr data)> CompleteCallback;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700107 typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
108
109 /**
Eric Newberrye345baa2018-05-23 18:17:07 -0700110 * @brief Error codes passed to `onError`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700111 */
112 enum ErrorCode {
Eric Newberrye345baa2018-05-23 18:17:07 -0700113 /// retrieval timed out because the maximum timeout between the successful receipt of segments was exceeded
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700114 INTEREST_TIMEOUT = 1,
Eric Newberrye345baa2018-05-23 18:17:07 -0700115 /// one of the retrieved Data packets lacked a segment number in the last Name component (excl. implicit digest)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700116 DATA_HAS_NO_SEGMENT = 2,
Eric Newberrye345baa2018-05-23 18:17:07 -0700117 /// one of the retrieved segments failed user-provided validation
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500118 SEGMENT_VALIDATION_FAIL = 3,
Eric Newberrye345baa2018-05-23 18:17:07 -0700119 /// an unrecoverable Nack was received during retrieval
120 NACK_ERROR = 4,
121 /// a received FinalBlockId did not contain a segment component
122 FINALBLOCKID_NOT_SEGMENT = 5
123 };
124
125 class Options
126 {
127 public:
128 Options()
129 {
130 }
131
132 void
133 validate();
134
135 public:
136 bool useConstantCwnd = false; ///< if true, window size is kept at `initCwnd`
137 bool useConstantInterestTimeout = false; ///< if true, Interest timeout is kept at `maxTimeout`
138 time::milliseconds maxTimeout = 60_s; ///< maximum allowed time between successful receipt of segments
139 time::milliseconds interestLifetime = 4_s; ///< lifetime of sent Interests - independent of Interest timeout
140 double initCwnd = 1.0; ///< initial congestion window size
141 double initSsthresh = std::numeric_limits<double>::max(); ///< initial slow start threshold
142 double aiStep = 1.0; ///< additive increase step (in segments)
143 double mdCoef = 0.5; ///< multiplicative decrease coefficient
144 bool disableCwa = false; ///< disable Conservative Window Adaptation
145 bool resetCwndToInit = false; ///< reduce cwnd to initCwnd when loss event occurs
146 bool ignoreCongMarks = false; ///< disable window decrease after congestion mark received
147 RttEstimator::Options rttOptions; ///< options for RTT estimator
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700148 };
149
150 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000151 * @brief Initiates segment fetching
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700152 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700153 * @param face Reference to the Face that should be used to fetch data
Eric Newberrye345baa2018-05-23 18:17:07 -0700154 * @param baseInterest Interest for the initial segment of requested data.
Eric Newberry2b765f82018-06-25 14:51:13 -0700155 * This interest may include a custom InterestLifetime and parameters that
156 * will propagate to all subsequent Interests. The only exception is that the
157 * initial Interest will be forced to include the "CanBePrefix=true" and
158 * "MustBeFresh=true" parameters, which will not be included in subsequent
Eric Newberrycc910cd2018-05-06 17:01:40 -0700159 * Interests.
Eric Newberrye345baa2018-05-23 18:17:07 -0700160 * @param validator Reference to the Validator the fetcher will use to validate data.
161 * The caller must ensure the validator is valid until either `onComplete` or
162 * `onError` has been signaled.
163 * @param options Options controlling the transfer
Eric Newberrycc910cd2018-05-06 17:01:40 -0700164 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700165 * @return A shared_ptr to the constructed SegmentFetcher.
166 * This shared_ptr is kept internally for the lifetime of the transfer.
167 * Therefore, it does not need to be saved and is provided here so that the
168 * SegmentFetcher's signals can be connected to.
Eric Newberrycc910cd2018-05-06 17:01:40 -0700169 *
170 * Transfer completion, failure, and progress are indicated via signals.
171 */
Eric Newberrye345baa2018-05-23 18:17:07 -0700172 static shared_ptr<SegmentFetcher>
Eric Newberrycc910cd2018-05-06 17:01:40 -0700173 start(Face& face,
174 const Interest& baseInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700175 security::v2::Validator& validator,
176 const Options& options = Options());
Eric Newberrycc910cd2018-05-06 17:01:40 -0700177
178 /**
179 * @brief Initiates segment fetching
180 *
181 * @deprecated Use @c start
182 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700183 * @param face Reference to the Face that should be used to fetch data
184 * @param baseInterest An Interest for the initial segment of requested data.
Eric Newberry2b765f82018-06-25 14:51:13 -0700185 * This interest may include a custom InterestLifetime and parameters that
Eric Newberrye345baa2018-05-23 18:17:07 -0700186 * will propagate to all subsequent Interests. The only exception is that
Eric Newberry2b765f82018-06-25 14:51:13 -0700187 * the initial Interest will be forced to include the parameters
188 * "CanBePrefix=true" and "MustBeFresh=true", which will be turned off in
189 * subsequent Interests.
Eric Newberrye345baa2018-05-23 18:17:07 -0700190 * @param validator Reference to the Validator that should be used to validate data. Caller
191 * must ensure validator is valid until either completeCallback or
192 * errorCallback is invoked.
193 * @param completeCallback Callback to be fired when all segments are fetched
194 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500195 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700196 * @return A shared_ptr to the constructed SegmentFetcher.
197 * This shared_ptr is kept internally for the lifetime of the transfer.
198 * Therefore, it does not need to be saved and is provided here so that
199 * the SegmentFetcher's signals can be connected to.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500200 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400201 [[deprecated("use SegmentFetcher::start instead")]]
Eric Newberrye345baa2018-05-23 18:17:07 -0700202 static shared_ptr<SegmentFetcher>
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500203 fetch(Face& face,
204 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800205 security::v2::Validator& validator,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500206 const CompleteCallback& completeCallback,
207 const ErrorCallback& errorCallback);
208
209 /**
210 * @brief Initiate segment fetching
211 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700212 * @deprecated Use @c start
213 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700214 * @param face Reference to the Face that should be used to fetch data
215 * @param baseInterest An Interest for the initial segment of requested data.
Eric Newberry2b765f82018-06-25 14:51:13 -0700216 * This interest may include a custom InterestLifetime and parameters that
Eric Newberrye345baa2018-05-23 18:17:07 -0700217 * will propagate to all subsequent Interests. The only exception is that
Eric Newberry2b765f82018-06-25 14:51:13 -0700218 * the initial Interest will be forced to include the parameters
219 * "CanBePrefix=true" and "MustBeFresh=true", which will both be set to
220 * false in subsequent Interests.
Eric Newberrye345baa2018-05-23 18:17:07 -0700221 * @param validator A shared_ptr to the Validator that should be used to validate data.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500222 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700223 * @param completeCallback Callback to be fired when all segments are fetched
224 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
225 *
226 * @return A shared_ptr to the constructed SegmentFetcher.
227 * This shared_ptr is kept internally for the lifetime of the transfer.
228 * Therefore, it does not need to be saved and is provided here so that
229 * the SegmentFetcher's signals can be connected to.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700230 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400231 [[deprecated("use SegmentFetcher::start instead")]]
Eric Newberrye345baa2018-05-23 18:17:07 -0700232 static shared_ptr<SegmentFetcher>
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700233 fetch(Face& face,
234 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800235 shared_ptr<security::v2::Validator> validator,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700236 const CompleteCallback& completeCallback,
237 const ErrorCallback& errorCallback);
238
239private:
Eric Newberrye345baa2018-05-23 18:17:07 -0700240 class PendingSegment;
241
242 SegmentFetcher(Face& face, security::v2::Validator& validator, const Options& options);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700243
244 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700245 fetchFirstSegment(const Interest& baseInterest,
246 bool isRetransmission,
247 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700248
249 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700250 fetchSegmentsInWindow(const Interest& origInterest, shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700251
252 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000253 afterSegmentReceivedCb(const Interest& origInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700254 const Data& data,
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000255 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500256 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800257 afterValidationSuccess(const Data& data,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500258 const Interest& origInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700259 std::map<uint64_t, PendingSegment>::iterator pendingSegmentIt,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500260 shared_ptr<SegmentFetcher> self);
261
262 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700263 afterValidationFailure(const Data& data,
264 const security::v2::ValidationError& error,
265 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500266
267 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700268 afterNackReceivedCb(const Interest& origInterest,
269 const lp::Nack& nack,
270 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500271
272 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700273 afterTimeoutCb(const Interest& origInterest,
274 shared_ptr<SegmentFetcher> self);
275
276 void
277 afterNackOrTimeout(const Interest& origInterest,
278 shared_ptr<SegmentFetcher> self);
279
280 void
281 finalizeFetch(shared_ptr<SegmentFetcher> self);
282
283 void
284 windowIncrease();
285
286 void
287 windowDecrease();
288
289 void
290 signalError(uint32_t code, const std::string& msg);
291
292 void
293 updateRetransmittedSegment(uint64_t segmentNum,
294 const PendingInterestId* pendingInterest,
295 scheduler::EventId timeoutEvent);
296
297 void
298 cancelExcessInFlightSegments();
299
300 bool
301 checkAllSegmentsReceived();
302
303 time::milliseconds
304 getEstimatedRto();
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700305
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000306public:
307 /**
Eric Newberrycc910cd2018-05-06 17:01:40 -0700308 * @brief Emits upon successful retrieval of the complete data
309 */
310 Signal<SegmentFetcher, ConstBufferPtr> onComplete;
311
312 /**
313 * @brief Emits when the retrieval could not be completed due to an error
314 *
315 * Handler(s) are provided with an error code and a string error message.
316 */
317 Signal<SegmentFetcher, uint32_t, std::string> onError;
318
319 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000320 * @brief Emits whenever a data segment received
321 */
322 Signal<SegmentFetcher, Data> afterSegmentReceived;
323
324 /**
325 * @brief Emits whenever a received data segment has been successfully validated
326 */
327 Signal<SegmentFetcher, Data> afterSegmentValidated;
328
Eric Newberrye345baa2018-05-23 18:17:07 -0700329 /**
330 * @brief Emits whenever an Interest for a data segment is nacked
331 */
332 Signal<SegmentFetcher> afterSegmentNacked;
333
334 /**
335 * @brief Emits whenever an Interest for a data segment times out
336 */
337 Signal<SegmentFetcher> afterSegmentTimedOut;
338
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700339private:
Eric Newberrye345baa2018-05-23 18:17:07 -0700340 enum class SegmentState {
341 FirstInterest, ///< the first Interest for this segment has been sent
342 InRetxQueue, ///< the segment is awaiting Interest retransmission
343 Retransmitted, ///< one or more retransmitted Interests have been sent for this segment
344 };
345
346 class PendingSegment
347 {
348 public:
349 SegmentState state;
350 time::steady_clock::TimePoint sendTime;
351 const PendingInterestId* id;
352 scheduler::EventId timeoutEvent;
353 };
354
355NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
356 static constexpr double MIN_SSTHRESH = 2.0;
357
358 Options m_options;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700359 Face& m_face;
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500360 Scheduler m_scheduler;
Eric Newberrycc910cd2018-05-06 17:01:40 -0700361 security::v2::Validator& m_validator;
Eric Newberrye345baa2018-05-23 18:17:07 -0700362 RttEstimator m_rttEstimator;
363 time::milliseconds m_timeout;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700364
Eric Newberrye345baa2018-05-23 18:17:07 -0700365 time::steady_clock::TimePoint m_timeLastSegmentReceived;
366 std::queue<uint64_t> m_retxQueue;
367 Name m_versionedDataName;
368 uint64_t m_nextSegmentNum;
369 double m_cwnd;
370 double m_ssthresh;
371 int64_t m_nSegmentsInFlight;
372 int64_t m_nSegments;
373 uint64_t m_highInterest;
374 uint64_t m_highData;
375 uint64_t m_recPoint;
376 int64_t m_nReceived;
377 int64_t m_nBytesReceived;
378
379 std::map<uint64_t, Buffer> m_receivedSegments;
380 std::map<uint64_t, PendingSegment> m_pendingSegments;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700381};
382
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500383} // namespace util
384} // namespace ndn
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700385
386#endif // NDN_UTIL_SEGMENT_FETCHER_HPP