blob: 3b81cb41aa1ad554e51028ac165da957525e37e9 [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/*
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +00003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_UTIL_SEGMENT_FETCHER_HPP
23#define NDN_UTIL_SEGMENT_FETCHER_HPP
24
25#include "../common.hpp"
26#include "../face.hpp"
Eric Newberrycc910cd2018-05-06 17:01:40 -070027#include "../encoding/buffer-stream.hpp"
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -080028#include "../security/v2/validator.hpp"
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +000029#include "scheduler.hpp"
30#include "signal.hpp"
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070031
32namespace ndn {
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070033namespace util {
34
35/**
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070036 * @brief Utility class to fetch latest version of the segmented data
37 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070038 * SegmentFetcher assumes that the data is named `/<prefix>/<version>/<segment>`,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070039 * where:
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070040 * - `<prefix>` is the specified prefix,
41 * - `<version>` is an unknown version that needs to be discovered, and
42 * - `<segment>` is a segment number (number of segments is unknown and is controlled
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070043 * by `FinalBlockId` field in at least the last Data packet
44 *
45 * The following logic is implemented in SegmentFetcher:
46 *
47 * 1. Express first interest to discover version:
48 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070049 * >> Interest: `/<prefix>?ChildSelector=1&MustBeFresh=yes`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070050 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070051 * 2. Infer the latest version of Data: `<version> = Data.getName().get(-2)`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070052 *
53 * 3. If segment number in the retrieved packet == 0, go to step 5.
54 *
55 * 4. Send Interest for segment 0:
56 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070057 * >> Interest: `/<prefix>/<version>/<segment=0>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070058 *
59 * 5. Keep sending Interests for the next segment while the retrieved Data does not have
60 * FinalBlockId or FinalBlockId != Data.getName().get(-1).
61 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070062 * >> Interest: `/<prefix>/<version>/<segment=(N+1))>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070063 *
64 * 6. Fire onCompletion callback with memory block that combines content part from all
65 * segmented objects.
66 *
67 * If an error occurs during the fetching process, an error callback is fired
68 * with a proper error code. The following errors are possible:
69 *
70 * - `INTEREST_TIMEOUT`: if any of the Interests times out
71 * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have segment
72 * as a last component of the name (not counting implicit digest)
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050073 * - `SEGMENT_VALIDATION_FAIL`: if any retrieved segment fails user-provided validation
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070074 *
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050075 * In order to validate individual segments, a Validator instance needs to be specified.
76 * If the segment validation is successful, afterValidationSuccess callback is fired, otherwise
77 * afterValidationFailure callback.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070078 *
79 * Examples:
80 *
81 * void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050082 * afterFetchComplete(const ConstBufferPtr& data)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070083 * {
84 * ...
85 * }
86 *
87 * void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050088 * afterFetchError(uint32_t errorCode, const std::string& errorMsg)
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070089 * {
90 * ...
91 * }
92 *
93 * ...
Davide Pesavento0f830802018-01-16 23:58:58 -050094 * SegmentFetcher::fetch(face, Interest("/data/prefix", 30_s),
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050095 * validator,
96 * bind(&afterFetchComplete, this, _1),
97 * bind(&afterFetchError, this, _1, _2));
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070098 *
99 */
100class SegmentFetcher : noncopyable
101{
102public:
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500103 /**
104 * @brief Maximum number of times an interest will be reexpressed incase of NackCallback
105 */
106 static const uint32_t MAX_INTEREST_REEXPRESS;
107
Eric Newberrycc910cd2018-05-06 17:01:40 -0700108 typedef function<void (ConstBufferPtr data)> CompleteCallback;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700109 typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
110
111 /**
112 * @brief Error codes that can be passed to ErrorCallback
113 */
114 enum ErrorCode {
115 INTEREST_TIMEOUT = 1,
116 DATA_HAS_NO_SEGMENT = 2,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500117 SEGMENT_VALIDATION_FAIL = 3,
118 NACK_ERROR = 4
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700119 };
120
121 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000122 * @brief Initiates segment fetching
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700123 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700124 * @param face Reference to the Face that should be used to fetch data
125 * @param baseInterest An Interest for the initial segment of requested data.
126 * This interest may include a custom InterestLifetime and selectors that will
127 * propagate to all subsequent Interests. The only exception is that the
128 * initial Interest will be forced to include the "ChildSelector=1" and
129 * "MustBeFresh=true" selectors, which will be turned off in subsequent
130 * Interests.
131 * @param validator Reference to the Validator that should be used to validate data. Caller
132 * must ensure validator is valid until either onComplete or onError has been
133 * signaled.
134 *
135 * @return A shared_ptr to the constructed SegmentFetcher
136 *
137 * Transfer completion, failure, and progress are indicated via signals.
138 */
139 static
140 shared_ptr<SegmentFetcher>
141 start(Face& face,
142 const Interest& baseInterest,
143 security::v2::Validator& validator);
144
145 /**
146 * @brief Initiates segment fetching
147 *
148 * @deprecated Use @c start
149 *
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700150 * @param face Reference to the Face that should be used to fetch data
151 * @param baseInterest An Interest for the initial segment of requested data.
152 * This interest may include custom InterestLifetime and selectors that
153 * will propagate to all subsequent Interests. The only exception is that
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500154 * the initial Interest will be forced to include "ChildSelector=rightmost" and
155 * "MustBeFresh=true" selectors, which will be turned off in subsequent
156 * Interests.
157 * @param validator Reference to the Validator that should be used to validate data. Caller
158 * must ensure validator is valid until either completeCallback or errorCallback
159 * is invoked.
160 *
161 * @param completeCallback Callback to be fired when all segments are fetched
162 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000163 * @return A shared_ptr to the constructed SegmentFetcher
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500164 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400165 [[deprecated("use SegmentFetcher::start instead")]]
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500166 static
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000167 shared_ptr<SegmentFetcher>
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500168 fetch(Face& face,
169 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800170 security::v2::Validator& validator,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500171 const CompleteCallback& completeCallback,
172 const ErrorCallback& errorCallback);
173
174 /**
175 * @brief Initiate segment fetching
176 *
Eric Newberrycc910cd2018-05-06 17:01:40 -0700177 * @deprecated Use @c start
178 *
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500179 * @param face Reference to the Face that should be used to fetch data
180 * @param baseInterest An Interest for the initial segment of requested data.
181 * This interest may include custom InterestLifetime and selectors that
182 * will propagate to all subsequent Interests. The only exception is that
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700183 * the initial Interest will be forced to include "ChildSelector=1" and
184 * "MustBeFresh=true" selectors, which will be turned off in subsequent
185 * Interests.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500186 * @param validator A shared_ptr to the Validator that should be used to validate data.
187 *
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700188 * @param completeCallback Callback to be fired when all segments are fetched
189 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000190 * @return A shared_ptr to the constructed SegmentFetcher
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700191 */
Davide Pesavento1fd00242018-05-20 00:11:01 -0400192 [[deprecated("use SegmentFetcher::start instead")]]
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700193 static
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000194 shared_ptr<SegmentFetcher>
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700195 fetch(Face& face,
196 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800197 shared_ptr<security::v2::Validator> validator,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700198 const CompleteCallback& completeCallback,
199 const ErrorCallback& errorCallback);
200
201private:
Eric Newberrycc910cd2018-05-06 17:01:40 -0700202 SegmentFetcher(Face& face, security::v2::Validator& validator);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700203
204 void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500205 fetchFirstSegment(const Interest& baseInterest, shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700206
207 void
208 fetchNextSegment(const Interest& origInterest, const Name& dataName, uint64_t segmentNo,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500209 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700210
211 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000212 afterSegmentReceivedCb(const Interest& origInterest,
213 const Data& data, bool isSegmentZeroExpected,
214 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500215 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800216 afterValidationSuccess(const Data& data,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500217 bool isSegmentZeroExpected,
218 const Interest& origInterest,
219 shared_ptr<SegmentFetcher> self);
220
221 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800222 afterValidationFailure(const Data& data, const security::v2::ValidationError& error);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500223
224 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000225 afterNackReceivedCb(const Interest& origInterest, const lp::Nack& nack,
226 uint32_t reExpressCount, shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500227
228 void
229 reExpressInterest(Interest interest, uint32_t reExpressCount,
230 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700231
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000232public:
233 /**
Eric Newberrycc910cd2018-05-06 17:01:40 -0700234 * @brief Emits upon successful retrieval of the complete data
235 */
236 Signal<SegmentFetcher, ConstBufferPtr> onComplete;
237
238 /**
239 * @brief Emits when the retrieval could not be completed due to an error
240 *
241 * Handler(s) are provided with an error code and a string error message.
242 */
243 Signal<SegmentFetcher, uint32_t, std::string> onError;
244
245 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000246 * @brief Emits whenever a data segment received
247 */
248 Signal<SegmentFetcher, Data> afterSegmentReceived;
249
250 /**
251 * @brief Emits whenever a received data segment has been successfully validated
252 */
253 Signal<SegmentFetcher, Data> afterSegmentValidated;
254
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700255private:
256 Face& m_face;
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500257 Scheduler m_scheduler;
Eric Newberrycc910cd2018-05-06 17:01:40 -0700258 security::v2::Validator& m_validator;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700259
Eric Newberrycc910cd2018-05-06 17:01:40 -0700260 OBufferStream m_buffer;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700261};
262
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500263} // namespace util
264} // namespace ndn
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700265
266#endif // NDN_UTIL_SEGMENT_FETCHER_HPP