blob: cc9725a739d2b80ecd588a7f15f52fd3734e1963 [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"
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -080027#include "../security/v2/validator.hpp"
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +000028#include "scheduler.hpp"
29#include "signal.hpp"
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070030
31namespace ndn {
32
33class OBufferStream;
34
35namespace util {
36
37/**
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070038 * @brief Utility class to fetch latest version of the segmented data
39 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070040 * SegmentFetcher assumes that the data is named `/<prefix>/<version>/<segment>`,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070041 * where:
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070042 * - `<prefix>` is the specified prefix,
43 * - `<version>` is an unknown version that needs to be discovered, and
44 * - `<segment>` is a segment number (number of segments is unknown and is controlled
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070045 * by `FinalBlockId` field in at least the last Data packet
46 *
47 * The following logic is implemented in SegmentFetcher:
48 *
49 * 1. Express first interest to discover version:
50 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070051 * >> Interest: `/<prefix>?ChildSelector=1&MustBeFresh=yes`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070052 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070053 * 2. Infer the latest version of Data: `<version> = Data.getName().get(-2)`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070054 *
55 * 3. If segment number in the retrieved packet == 0, go to step 5.
56 *
57 * 4. Send Interest for segment 0:
58 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070059 * >> Interest: `/<prefix>/<version>/<segment=0>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070060 *
61 * 5. Keep sending Interests for the next segment while the retrieved Data does not have
62 * FinalBlockId or FinalBlockId != Data.getName().get(-1).
63 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070064 * >> Interest: `/<prefix>/<version>/<segment=(N+1))>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070065 *
66 * 6. Fire onCompletion callback with memory block that combines content part from all
67 * segmented objects.
68 *
69 * If an error occurs during the fetching process, an error callback is fired
70 * with a proper error code. The following errors are possible:
71 *
72 * - `INTEREST_TIMEOUT`: if any of the Interests times out
73 * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have segment
74 * as a last component of the name (not counting implicit digest)
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050075 * - `SEGMENT_VALIDATION_FAIL`: if any retrieved segment fails user-provided validation
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070076 *
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050077 * In order to validate individual segments, a Validator instance needs to be specified.
78 * If the segment validation is successful, afterValidationSuccess callback is fired, otherwise
79 * afterValidationFailure callback.
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070080 *
81 * Examples:
82 *
83 * void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050084 * afterFetchComplete(const 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 * ...
96 * SegmentFetcher::fetch(face, Interest("/data/prefix", time::seconds(1000)),
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -050097 * validator,
98 * bind(&afterFetchComplete, this, _1),
99 * bind(&afterFetchError, this, _1, _2));
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700100 *
101 */
102class SegmentFetcher : noncopyable
103{
104public:
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500105 /**
106 * @brief Maximum number of times an interest will be reexpressed incase of NackCallback
107 */
108 static const uint32_t MAX_INTEREST_REEXPRESS;
109
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700110 typedef function<void (const ConstBufferPtr& data)> CompleteCallback;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700111 typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
112
113 /**
114 * @brief Error codes that can be passed to ErrorCallback
115 */
116 enum ErrorCode {
117 INTEREST_TIMEOUT = 1,
118 DATA_HAS_NO_SEGMENT = 2,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500119 SEGMENT_VALIDATION_FAIL = 3,
120 NACK_ERROR = 4
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700121 };
122
123 /**
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000124 * @brief Initiates segment fetching
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700125 *
126 * @param face Reference to the Face that should be used to fetch data
127 * @param baseInterest An Interest for the initial segment of requested data.
128 * This interest may include custom InterestLifetime and selectors that
129 * will propagate to all subsequent Interests. The only exception is that
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500130 * the initial Interest will be forced to include "ChildSelector=rightmost" and
131 * "MustBeFresh=true" selectors, which will be turned off in subsequent
132 * Interests.
133 * @param validator Reference to the Validator that should be used to validate data. Caller
134 * must ensure validator is valid until either completeCallback or errorCallback
135 * is invoked.
136 *
137 * @param completeCallback Callback to be fired when all segments are fetched
138 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000139 * @return A shared_ptr to the constructed SegmentFetcher
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500140 */
141 static
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000142 shared_ptr<SegmentFetcher>
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500143 fetch(Face& face,
144 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800145 security::v2::Validator& validator,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500146 const CompleteCallback& completeCallback,
147 const ErrorCallback& errorCallback);
148
149 /**
150 * @brief Initiate segment fetching
151 *
152 * @param face Reference to the Face that should be used to fetch data
153 * @param baseInterest An Interest for the initial segment of requested data.
154 * This interest may include custom InterestLifetime and selectors that
155 * will propagate to all subsequent Interests. The only exception is that
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700156 * the initial Interest will be forced to include "ChildSelector=1" and
157 * "MustBeFresh=true" selectors, which will be turned off in subsequent
158 * Interests.
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500159 * @param validator A shared_ptr to the Validator that should be used to validate data.
160 *
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700161 * @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
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700164 */
165 static
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000166 shared_ptr<SegmentFetcher>
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700167 fetch(Face& face,
168 const Interest& baseInterest,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800169 shared_ptr<security::v2::Validator> validator,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700170 const CompleteCallback& completeCallback,
171 const ErrorCallback& errorCallback);
172
173private:
174 SegmentFetcher(Face& face,
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800175 shared_ptr<security::v2::Validator> validator,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700176 const CompleteCallback& completeCallback,
177 const ErrorCallback& errorCallback);
178
179 void
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500180 fetchFirstSegment(const Interest& baseInterest, shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700181
182 void
183 fetchNextSegment(const Interest& origInterest, const Name& dataName, uint64_t segmentNo,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500184 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700185
186 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000187 afterSegmentReceivedCb(const Interest& origInterest,
188 const Data& data, bool isSegmentZeroExpected,
189 shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500190 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800191 afterValidationSuccess(const Data& data,
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500192 bool isSegmentZeroExpected,
193 const Interest& origInterest,
194 shared_ptr<SegmentFetcher> self);
195
196 void
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800197 afterValidationFailure(const Data& data, const security::v2::ValidationError& error);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500198
199 void
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000200 afterNackReceivedCb(const Interest& origInterest, const lp::Nack& nack,
201 uint32_t reExpressCount, shared_ptr<SegmentFetcher> self);
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500202
203 void
204 reExpressInterest(Interest interest, uint32_t reExpressCount,
205 shared_ptr<SegmentFetcher> self);
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700206
Muktadir Chowdhury1c109b42018-01-10 08:36:00 +0000207public:
208 /**
209 * @brief Emits whenever a data segment received
210 */
211 Signal<SegmentFetcher, Data> afterSegmentReceived;
212
213 /**
214 * @brief Emits whenever a received data segment has been successfully validated
215 */
216 Signal<SegmentFetcher, Data> afterSegmentValidated;
217
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700218private:
219 Face& m_face;
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500220 Scheduler m_scheduler;
Alexander Afanasyev6dfeffe2017-01-30 22:40:32 -0800221 shared_ptr<security::v2::Validator> m_validator;
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700222 CompleteCallback m_completeCallback;
223 ErrorCallback m_errorCallback;
224
225 shared_ptr<OBufferStream> m_buffer;
226};
227
Muktadir R Chowdhuryf58f8f42015-09-02 11:56:49 -0500228} // namespace util
229} // namespace ndn
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -0700230
231#endif // NDN_UTIL_SEGMENT_FETCHER_HPP