blob: fb8f6d7a72ededed4fdebc7e7c0491f1df66f5c1 [file] [log] [blame]
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2014 Regents of the University of California.
4 *
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"
27
28namespace ndn {
29
30class OBufferStream;
31
32namespace util {
33
34/**
35 * @brief Functor to skip validation of individual packets by SegmentFetcher
36 */
37class DontVerifySegment
38{
39public:
40 bool
41 operator()(const Data& data) const
42 {
43 return true;
44 }
45};
46
47/**
48 * @brief Utility class to fetch latest version of the segmented data
49 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070050 * SegmentFetcher assumes that the data is named `/<prefix>/<version>/<segment>`,
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070051 * where:
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070052 * - `<prefix>` is the specified prefix,
53 * - `<version>` is an unknown version that needs to be discovered, and
54 * - `<segment>` is a segment number (number of segments is unknown and is controlled
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070055 * by `FinalBlockId` field in at least the last Data packet
56 *
57 * The following logic is implemented in SegmentFetcher:
58 *
59 * 1. Express first interest to discover version:
60 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070061 * >> Interest: `/<prefix>?ChildSelector=1&MustBeFresh=yes`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070062 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070063 * 2. Infer the latest version of Data: `<version> = Data.getName().get(-2)`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070064 *
65 * 3. If segment number in the retrieved packet == 0, go to step 5.
66 *
67 * 4. Send Interest for segment 0:
68 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070069 * >> Interest: `/<prefix>/<version>/<segment=0>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070070 *
71 * 5. Keep sending Interests for the next segment while the retrieved Data does not have
72 * FinalBlockId or FinalBlockId != Data.getName().get(-1).
73 *
Alexander Afanasyevf2a46222015-09-17 18:01:30 -070074 * >> Interest: `/<prefix>/<version>/<segment=(N+1))>`
Alexander Afanasyevf3cfab52014-08-17 22:15:25 -070075 *
76 * 6. Fire onCompletion callback with memory block that combines content part from all
77 * segmented objects.
78 *
79 * If an error occurs during the fetching process, an error callback is fired
80 * with a proper error code. The following errors are possible:
81 *
82 * - `INTEREST_TIMEOUT`: if any of the Interests times out
83 * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have segment
84 * as a last component of the name (not counting implicit digest)
85 * - `SEGMENT_VERIFICATION_FAIL`: if any retrieved segment fails user-provided validation
86 *
87 * In order to validate individual segments, an VerifySegment callback needs to be specified.
88 * If the callback returns false, fetching process is aborted with SEGMENT_VERIFICATION_FAIL.
89 * If data validation is not required, provided DontVerifySegment() functor can be used.
90 *
91 * Examples:
92 *
93 * void
94 * onComplete(const ConstBufferPtr& data)
95 * {
96 * ...
97 * }
98 *
99 * void
100 * onError(uint32_t errorCode, const std::string& errorMsg)
101 * {
102 * ...
103 * }
104 *
105 * ...
106 * SegmentFetcher::fetch(face, Interest("/data/prefix", time::seconds(1000)),
107 * DontVerifySegment(),
108 * bind(&onComplete, this, _1),
109 * bind(&onError, this, _1, _2));
110 *
111 */
112class SegmentFetcher : noncopyable
113{
114public:
115 typedef function<void (const ConstBufferPtr& data)> CompleteCallback;
116 typedef function<bool (const Data& data)> VerifySegment;
117 typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
118
119 /**
120 * @brief Error codes that can be passed to ErrorCallback
121 */
122 enum ErrorCode {
123 INTEREST_TIMEOUT = 1,
124 DATA_HAS_NO_SEGMENT = 2,
125 SEGMENT_VERIFICATION_FAIL = 3
126 };
127
128 /**
129 * @brief Initiate segment fetching
130 *
131 * @param face Reference to the Face that should be used to fetch data
132 * @param baseInterest An Interest for the initial segment of requested data.
133 * This interest may include custom InterestLifetime and selectors that
134 * will propagate to all subsequent Interests. The only exception is that
135 * the initial Interest will be forced to include "ChildSelector=1" and
136 * "MustBeFresh=true" selectors, which will be turned off in subsequent
137 * Interests.
138 * @param verifySegment Functor to be called when Data segment is received. If
139 * functor return false, fetching will be aborted with
140 * SEGMENT_VERIFICATION_FAIL error
141 * @param completeCallback Callback to be fired when all segments are fetched
142 * @param errorCallback Callback to be fired when an error occurs (@see Errors)
143 */
144 static
145 void
146 fetch(Face& face,
147 const Interest& baseInterest,
148 const VerifySegment& verifySegment,
149 const CompleteCallback& completeCallback,
150 const ErrorCallback& errorCallback);
151
152private:
153 SegmentFetcher(Face& face,
154 const VerifySegment& verifySegment,
155 const CompleteCallback& completeCallback,
156 const ErrorCallback& errorCallback);
157
158 void
159 fetchFirstSegment(const Interest& baseInterest, const shared_ptr<SegmentFetcher>& self);
160
161 void
162 fetchNextSegment(const Interest& origInterest, const Name& dataName, uint64_t segmentNo,
163 const shared_ptr<SegmentFetcher>& self);
164
165 void
166 onSegmentReceived(const Interest& origInterest,
167 const Data& data, bool isSegmentZeroExpected,
168 const shared_ptr<SegmentFetcher>& self);
169
170private:
171 Face& m_face;
172 VerifySegment m_verifySegment;
173 CompleteCallback m_completeCallback;
174 ErrorCallback m_errorCallback;
175
176 shared_ptr<OBufferStream> m_buffer;
177};
178
179} // util
180} // ndn
181
182#endif // NDN_UTIL_SEGMENT_FETCHER_HPP