blob: e3df0c59c9c7e5d42d0568583df888caea167b23 [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 Newberrye345baa2018-05-23 18:17:07 -070044 * @brief Utility class to fetch the latest version of segmented data
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070045 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070046 * SegmentFetcher assumes that the data is 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
50 * - `<segment>` is a segment number (number of segments is unknown and is controlled
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070051 * by `FinalBlockId` field in at least the last Data packet
52 *
53 * The following logic is implemented in SegmentFetcher:
54 *
55 * 1. Express first interest to discover version:
56 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070057 * >> Interest: `/<prefix>?ChildSelector=1&MustBeFresh=yes`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070058 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070059 * 2. Infer the latest version of Data: `<version> = Data.getName().get(-2)`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070060 *
61 * 3. If segment number in the retrieved packet == 0, go to step 5.
62 *
63 * 4. Send Interest for segment 0:
64 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070065 * >> Interest: `/<prefix>/<version>/<segment=0>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070066 *
67 * 5. Keep sending Interests for the next segment while the retrieved Data does not have
68 * FinalBlockId or FinalBlockId != Data.getName().get(-1).
69 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070070 * >> Interest: `/<prefix>/<version>/<segment=(N+1))>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070071 *
Eric Newberrye345baa2018-05-23 18:17:07 -070072 * 6. Signal `onComplete` with a memory block that combines the content of all segments of the
73 * object.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070074 *
Eric Newberrye345baa2018-05-23 18:17:07 -070075 * If an error occurs during the fetching process, `onError` is signaled with one of the error codes
76 * from `SegmentFetcher::ErrorCode`.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070077 *
Eric Newberrye345baa2018-05-23 18:17:07 -070078 * A Validator instance must be specified to validate individual segments. Every time a segment has
79 * been successfully validated, `afterValidationSuccess` will be signaled. If a segment fails
80 * validation, `afterValidationFailure` will be signaled.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070081 *
82 * Examples:
83 *
84 * void
Eric Newberrye345baa2018-05-23 18:17:07 -070085 * afterFetchComplete(ConstBufferPtr data)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070086 * {
87 * ...
88 * }
89 *
90 * void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050091 * afterFetchError(uint32_t errorCode, const std::string& errorMsg)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070092 * {
93 * ...
94 * }
95 *
96 * ...
Eric Newberrye345baa2018-05-23 18:17:07 -070097 * auto fetcher = SegmentFetcher::start(face, Interest("/data/prefix"), validator);
98 * fetcher->onComplete.connect(bind(&afterFetchComplete, this, _1));
99 * fetcher->onError.connect(bind(&afterFetchError, this, _1, _2));
100 *
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700101 *
102 */
103class SegmentFetcher : noncopyable
104{
105public:
Eric Newberrye345baa2018-05-23 18:17:07 -0700106 // Deprecated: will be removed when deprecated fetch() API is removed - use start() instead
Eric Newberrycc910cd2018-05-06 17:01:40 -0700107 typedef function<void (ConstBufferPtr data)> CompleteCallback;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700108 typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
109
110 /**
Eric Newberrye345baa2018-05-23 18:17:07 -0700111 * @brief Error codes passed to `onError`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700112 */
113 enum ErrorCode {
Eric Newberrye345baa2018-05-23 18:17:07 -0700114 /// retrieval timed out because the maximum timeout between the successful receipt of segments was exceeded
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700115 INTEREST_TIMEOUT = 1,
Eric Newberrye345baa2018-05-23 18:17:07 -0700116 /// 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 -0700117 DATA_HAS_NO_SEGMENT = 2,
Eric Newberrye345baa2018-05-23 18:17:07 -0700118 /// one of the retrieved segments failed user-provided validation
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500119 SEGMENT_VALIDATION_FAIL = 3,
Eric Newberrye345baa2018-05-23 18:17:07 -0700120 /// an unrecoverable Nack was received during retrieval
121 NACK_ERROR = 4,
122 /// a received FinalBlockId did not contain a segment component
123 FINALBLOCKID_NOT_SEGMENT = 5
124 };
125
126 class Options
127 {
128 public:
129 Options()
130 {
131 }
132
133 void
134 validate();
135
136 public:
137 bool useConstantCwnd = false; ///< if true, window size is kept at `initCwnd`
138 bool useConstantInterestTimeout = false; ///< if true, Interest timeout is kept at `maxTimeout`
139 time::milliseconds maxTimeout = 60_s; ///< maximum allowed time between successful receipt of segments
140 time::milliseconds interestLifetime = 4_s; ///< lifetime of sent Interests - independent of Interest timeout
141 double initCwnd = 1.0; ///< initial congestion window size
142 double initSsthresh = std::numeric_limits<double>::max(); ///< initial slow start threshold
143 double aiStep = 1.0; ///< additive increase step (in segments)
144 double mdCoef = 0.5; ///< multiplicative decrease coefficient
145 bool disableCwa = false; ///< disable Conservative Window Adaptation
146 bool resetCwndToInit = false; ///< reduce cwnd to initCwnd when loss event occurs
147 bool ignoreCongMarks = false; ///< disable window decrease after congestion mark received
148 RttEstimator::Options rttOptions; ///< options for RTT estimator
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700149 };
150
151 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000152 * @brief Initiates segment fetching
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700153 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700154 * @param face Reference to the Face that should be used to fetch data
Eric Newberrye345baa2018-05-23 18:17:07 -0700155 * @param baseInterest Interest for the initial segment of requested data.
Eric Newberrycc910cd2018-05-06 17:01:40 -0700156 * This interest may include a custom InterestLifetime and selectors that will
157 * propagate to all subsequent Interests. The only exception is that the
158 * initial Interest will be forced to include the "ChildSelector=1" and
Eric Newberrye345baa2018-05-23 18:17:07 -0700159 * "MustBeFresh=true" selectors, which will not be included in subsequent
Eric Newberrycc910cd2018-05-06 17:01:40 -0700160 * Interests.
Eric Newberrye345baa2018-05-23 18:17:07 -0700161 * @param validator Reference to the Validator the fetcher will use to validate data.
162 * The caller must ensure the validator is valid until either `onComplete` or
163 * `onError` has been signaled.
164 * @param options Options controlling the transfer
Eric Newberrycc910cd2018-05-06 17:01:40 -0700165 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700166 * @return A shared_ptr to the constructed SegmentFetcher.
167 * This shared_ptr is kept internally for the lifetime of the transfer.
168 * Therefore, it does not need to be saved and is provided here so that the
169 * SegmentFetcher's signals can be connected to.
Eric Newberrycc910cd2018-05-06 17:01:40 -0700170 *
171 * Transfer completion, failure, and progress are indicated via signals.
172 */
Eric Newberrye345baa2018-05-23 18:17:07 -0700173 static shared_ptr<SegmentFetcher>
Eric Newberrycc910cd2018-05-06 17:01:40 -0700174 start(Face& face,
175 const Interest& baseInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700176 security::v2::Validator& validator,
177 const Options& options = Options());
Eric Newberrycc910cd2018-05-06 17:01:40 -0700178
179 /**
180 * @brief Initiates segment fetching
181 *
182 * @deprecated Use @c start
183 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700184 * @param face Reference to the Face that should be used to fetch data
185 * @param baseInterest An Interest for the initial segment of requested data.
186 * This interest may include custom InterestLifetime and selectors that
187 * will propagate to all subsequent Interests. The only exception is that
188 * the initial Interest will be forced to include
189 * "ChildSelector=rightmost" and "MustBeFresh=true" selectors, which will
190 * be turned off in subsequent Interests.
191 * @param validator Reference to the Validator that should be used to validate data. Caller
192 * must ensure validator is valid until either completeCallback or
193 * errorCallback is invoked.
194 * @param completeCallback Callback to be fired when all segments are fetched
195 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500196 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700197 * @return A shared_ptr to the constructed SegmentFetcher.
198 * This shared_ptr is kept internally for the lifetime of the transfer.
199 * Therefore, it does not need to be saved and is provided here so that
200 * the SegmentFetcher's signals can be connected to.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500201 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400202 [[deprecated("use SegmentFetcher::start instead")]]
Eric Newberrye345baa2018-05-23 18:17:07 -0700203 static shared_ptr<SegmentFetcher>
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500204 fetch(Face& face,
205 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800206 security::v2::Validator& validator,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500207 const CompleteCallback& completeCallback,
208 const ErrorCallback& errorCallback);
209
210 /**
211 * @brief Initiate segment fetching
212 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700213 * @deprecated Use @c start
214 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700215 * @param face Reference to the Face that should be used to fetch data
216 * @param baseInterest An Interest for the initial segment of requested data.
217 * This interest may include custom InterestLifetime and selectors that
218 * will propagate to all subsequent Interests. The only exception is that
219 * the initial Interest will be forced to include "ChildSelector=1" and
220 * "MustBeFresh=true" selectors, which will be turned off in subsequent
221 * Interests.
222 * @param validator A shared_ptr to the Validator that should be used to validate data.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500223 *
Eric Newberrye345baa2018-05-23 18:17:07 -0700224 * @param completeCallback Callback to be fired when all segments are fetched
225 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
226 *
227 * @return A shared_ptr to the constructed SegmentFetcher.
228 * This shared_ptr is kept internally for the lifetime of the transfer.
229 * Therefore, it does not need to be saved and is provided here so that
230 * the SegmentFetcher's signals can be connected to.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700231 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400232 [[deprecated("use SegmentFetcher::start instead")]]
Eric Newberrye345baa2018-05-23 18:17:07 -0700233 static shared_ptr<SegmentFetcher>
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700234 fetch(Face& face,
235 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800236 shared_ptr<security::v2::Validator> validator,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700237 const CompleteCallback& completeCallback,
238 const ErrorCallback& errorCallback);
239
240private:
Eric Newberrye345baa2018-05-23 18:17:07 -0700241 class PendingSegment;
242
243 SegmentFetcher(Face& face, security::v2::Validator& validator, const Options& options);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700244
245 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700246 fetchFirstSegment(const Interest& baseInterest,
247 bool isRetransmission,
248 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700249
250 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700251 fetchSegmentsInWindow(const Interest& origInterest, shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700252
253 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000254 afterSegmentReceivedCb(const Interest& origInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700255 const Data& data,
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000256 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500257 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800258 afterValidationSuccess(const Data& data,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500259 const Interest& origInterest,
Eric Newberrye345baa2018-05-23 18:17:07 -0700260 std::map<uint64_t, PendingSegment>::iterator pendingSegmentIt,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500261 shared_ptr<SegmentFetcher> self);
262
263 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700264 afterValidationFailure(const Data& data,
265 const security::v2::ValidationError& error,
266 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500267
268 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700269 afterNackReceivedCb(const Interest& origInterest,
270 const lp::Nack& nack,
271 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500272
273 void
Eric Newberrye345baa2018-05-23 18:17:07 -0700274 afterTimeoutCb(const Interest& origInterest,
275 shared_ptr<SegmentFetcher> self);
276
277 void
278 afterNackOrTimeout(const Interest& origInterest,
279 shared_ptr<SegmentFetcher> self);
280
281 void
282 finalizeFetch(shared_ptr<SegmentFetcher> self);
283
284 void
285 windowIncrease();
286
287 void
288 windowDecrease();
289
290 void
291 signalError(uint32_t code, const std::string& msg);
292
293 void
294 updateRetransmittedSegment(uint64_t segmentNum,
295 const PendingInterestId* pendingInterest,
296 scheduler::EventId timeoutEvent);
297
298 void
299 cancelExcessInFlightSegments();
300
301 bool
302 checkAllSegmentsReceived();
303
304 time::milliseconds
305 getEstimatedRto();
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700306
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000307public:
308 /**
Eric Newberrycc910cd2018-05-06 17:01:40 -0700309 * @brief Emits upon successful retrieval of the complete data
310 */
311 Signal<SegmentFetcher, ConstBufferPtr> onComplete;
312
313 /**
314 * @brief Emits when the retrieval could not be completed due to an error
315 *
316 * Handler(s) are provided with an error code and a string error message.
317 */
318 Signal<SegmentFetcher, uint32_t, std::string> onError;
319
320 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000321 * @brief Emits whenever a data segment received
322 */
323 Signal<SegmentFetcher, Data> afterSegmentReceived;
324
325 /**
326 * @brief Emits whenever a received data segment has been successfully validated
327 */
328 Signal<SegmentFetcher, Data> afterSegmentValidated;
329
Eric Newberrye345baa2018-05-23 18:17:07 -0700330 /**
331 * @brief Emits whenever an Interest for a data segment is nacked
332 */
333 Signal<SegmentFetcher> afterSegmentNacked;
334
335 /**
336 * @brief Emits whenever an Interest for a data segment times out
337 */
338 Signal<SegmentFetcher> afterSegmentTimedOut;
339
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700340private:
Eric Newberrye345baa2018-05-23 18:17:07 -0700341 enum class SegmentState {
342 FirstInterest, ///< the first Interest for this segment has been sent
343 InRetxQueue, ///< the segment is awaiting Interest retransmission
344 Retransmitted, ///< one or more retransmitted Interests have been sent for this segment
345 };
346
347 class PendingSegment
348 {
349 public:
350 SegmentState state;
351 time::steady_clock::TimePoint sendTime;
352 const PendingInterestId* id;
353 scheduler::EventId timeoutEvent;
354 };
355
356NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
357 static constexpr double MIN_SSTHRESH = 2.0;
358
359 Options m_options;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700360 Face& m_face;
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500361 Scheduler m_scheduler;
Eric Newberrycc910cd2018-05-06 17:01:40 -0700362 security::v2::Validator& m_validator;
Eric Newberrye345baa2018-05-23 18:17:07 -0700363 RttEstimator m_rttEstimator;
364 time::milliseconds m_timeout;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700365
Eric Newberrye345baa2018-05-23 18:17:07 -0700366 time::steady_clock::TimePoint m_timeLastSegmentReceived;
367 std::queue<uint64_t> m_retxQueue;
368 Name m_versionedDataName;
369 uint64_t m_nextSegmentNum;
370 double m_cwnd;
371 double m_ssthresh;
372 int64_t m_nSegmentsInFlight;
373 int64_t m_nSegments;
374 uint64_t m_highInterest;
375 uint64_t m_highData;
376 uint64_t m_recPoint;
377 int64_t m_nReceived;
378 int64_t m_nBytesReceived;
379
380 std::map<uint64_t, Buffer> m_receivedSegments;
381 std::map<uint64_t, PendingSegment> m_pendingSegments;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700382};
383
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500384} // namespace util
385} // namespace ndn
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700386
387#endif // NDN_UTIL_SEGMENT_FETCHER_HPP