segment-fetcher.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2017 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 #include "segment-fetcher.hpp"
23 #include "../encoding/buffer-stream.hpp"
24 #include "../name-component.hpp"
25 #include "../lp/nack.hpp"
26 #include "../lp/nack-header.hpp"
27 
28 #include <boost/lexical_cast.hpp>
29 
30 namespace ndn {
31 namespace util {
32 
34 
35 SegmentFetcher::SegmentFetcher(Face& face,
36  shared_ptr<security::v2::Validator> validator,
37  const CompleteCallback& completeCallback,
38  const ErrorCallback& errorCallback)
39  : m_face(face)
40  , m_scheduler(m_face.getIoService())
41  , m_validator(validator)
42  , m_completeCallback(completeCallback)
43  , m_errorCallback(errorCallback)
44  , m_buffer(make_shared<OBufferStream>())
45 {
46 }
47 
48 void
49 SegmentFetcher::fetch(Face& face,
50  const Interest& baseInterest,
51  security::v2::Validator& validator,
52  const CompleteCallback& completeCallback,
53  const ErrorCallback& errorCallback)
54 {
55  shared_ptr<security::v2::Validator> validatorPtr(&validator, [] (security::v2::Validator*) {});
56  fetch(face, baseInterest, validatorPtr, completeCallback, errorCallback);
57 }
58 
59 void
60 SegmentFetcher::fetch(Face& face,
61  const Interest& baseInterest,
62  shared_ptr<security::v2::Validator> validator,
63  const CompleteCallback& completeCallback,
64  const ErrorCallback& errorCallback)
65 {
66  shared_ptr<SegmentFetcher> fetcher(new SegmentFetcher(face, validator, completeCallback,
67  errorCallback));
68 
69  fetcher->fetchFirstSegment(baseInterest, fetcher);
70 }
71 
72 void
73 SegmentFetcher::fetchFirstSegment(const Interest& baseInterest,
74  shared_ptr<SegmentFetcher> self)
75 {
76  Interest interest(baseInterest);
77  interest.setChildSelector(1);
78  interest.setMustBeFresh(true);
79 
80  m_face.expressInterest(interest,
81  bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2, true, self),
82  bind(&SegmentFetcher::afterNackReceived, this, _1, _2, 0, self),
83  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
84 }
85 
86 void
87 SegmentFetcher::fetchNextSegment(const Interest& origInterest, const Name& dataName,
88  uint64_t segmentNo,
89  shared_ptr<SegmentFetcher> self)
90 {
91  Interest interest(origInterest); // to preserve any selectors
92  interest.refreshNonce();
93  interest.setChildSelector(0);
94  interest.setMustBeFresh(false);
95  interest.setName(dataName.getPrefix(-1).appendSegment(segmentNo));
96  m_face.expressInterest(interest,
97  bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2, false, self),
98  bind(&SegmentFetcher::afterNackReceived, this, _1, _2, 0, self),
99  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
100 }
101 
102 void
103 SegmentFetcher::afterSegmentReceived(const Interest& origInterest,
104  const Data& data, bool isSegmentZeroExpected,
105  shared_ptr<SegmentFetcher> self)
106 {
107  m_validator->validate(data,
108  bind(&SegmentFetcher::afterValidationSuccess, this, _1,
109  isSegmentZeroExpected, origInterest, self),
110  bind(&SegmentFetcher::afterValidationFailure, this, _1, _2));
111 
112 }
113 
114 void
115 SegmentFetcher::afterValidationSuccess(const Data& data,
116  bool isSegmentZeroExpected,
117  const Interest& origInterest,
118  shared_ptr<SegmentFetcher> self)
119 {
120  name::Component currentSegment = data.getName().get(-1);
121 
122  if (currentSegment.isSegment()) {
123  if (isSegmentZeroExpected && currentSegment.toSegment() != 0) {
124  fetchNextSegment(origInterest, data.getName(), 0, self);
125  }
126  else {
127  m_buffer->write(reinterpret_cast<const char*>(data.getContent().value()),
128  data.getContent().value_size());
129 
130  const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
131  if (finalBlockId.empty() || (finalBlockId > currentSegment)) {
132  fetchNextSegment(origInterest, data.getName(), currentSegment.toSegment() + 1, self);
133  }
134  else {
135  return m_completeCallback(m_buffer->buf());
136  }
137  }
138  }
139  else {
140  m_errorCallback(DATA_HAS_NO_SEGMENT, "Data Name has no segment number.");
141  }
142 }
143 
144 void
145 SegmentFetcher::afterValidationFailure(const Data& data, const security::v2::ValidationError& error)
146 {
147  return m_errorCallback(SEGMENT_VALIDATION_FAIL, "Segment validation fail " +
148  boost::lexical_cast<std::string>(error));
149 }
150 
151 
152 void
153 SegmentFetcher::afterNackReceived(const Interest& origInterest, const lp::Nack& nack,
154  uint32_t reExpressCount, shared_ptr<SegmentFetcher> self)
155 {
156  if (reExpressCount >= MAX_INTEREST_REEXPRESS) {
157  m_errorCallback(NACK_ERROR, "Nack Error");
158  }
159  else {
160  switch (nack.getReason()) {
162  reExpressInterest(origInterest, reExpressCount, self);
163  break;
165  m_scheduler.scheduleEvent(time::milliseconds(static_cast<uint32_t>(pow(2, reExpressCount + 1))),
166  bind(&SegmentFetcher::reExpressInterest, this,
167  origInterest, reExpressCount, self));
168  break;
169  default:
170  m_errorCallback(NACK_ERROR, "Nack Error");
171  break;
172  }
173  }
174 }
175 
176 void
177 SegmentFetcher::reExpressInterest(Interest interest, uint32_t reExpressCount,
178  shared_ptr<SegmentFetcher> self)
179 {
180  interest.refreshNonce();
181  BOOST_ASSERT(interest.hasNonce());
182 
183  bool isSegmentZeroExpected = true;
184  if (!interest.getName().empty()) {
185  name::Component lastComponent = interest.getName().get(-1);
186  isSegmentZeroExpected = !lastComponent.isSegment();
187  }
188 
189  m_face.expressInterest(interest,
190  bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2,
191  isSegmentZeroExpected, self),
192  bind(&SegmentFetcher::afterNackReceived, this, _1, _2,
193  ++reExpressCount, self),
194  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
195 }
196 
197 } // namespace util
198 } // namespace ndn
const Name & getName() const
Definition: interest.hpp:139
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
Interest & setMustBeFresh(bool mustBeFresh)
Definition: interest.hpp:324
function< void(uint32_t code, const std::string &msg)> ErrorCallback
void refreshNonce()
Refresh nonce.
Definition: interest.cpp:318
Utility class to fetch latest version of the segmented data.
represents an Interest packet
Definition: interest.hpp:42
const MetaInfo & getMetaInfo() const
Get MetaInfo.
Definition: data.hpp:135
function< void(const std::string &reason)> ErrorCallback
Definition: dns.hpp:79
represents a Network Nack
Definition: nack.hpp:40
NackReason getReason() const
Definition: nack.hpp:92
bool isSegment() const
Check if the component is segment number per NDN naming conventions.
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
Interest & setChildSelector(int childSelector)
Definition: interest.hpp:310
Interest & setName(const Name &name)
Definition: interest.hpp:145
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:95
Represents an absolute name.
Definition: name.hpp:42
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:317
const Name & getName() const
Get name.
Definition: data.hpp:121
Component holds a read-only name component value.
Validation error code and optional detailed error message.
const Block & getContent() const
Get Content.
Definition: data.cpp:185
bool empty() const
Check if name is empty.
Definition: name.hpp:146
const uint8_t * value() const
Get pointer to TLV-VALUE.
Definition: block.cpp:311
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix of the name.
Definition: name.hpp:210
static const uint32_t MAX_INTEREST_REEXPRESS
Maximum number of times an interest will be reexpressed incase of NackCallback.
Represents a Data packet.
Definition: data.hpp:35
const name::Component & getFinalBlockId() const
Definition: meta-info.hpp:219
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:164
Name & appendSegment(uint64_t segmentNo)
Append a segment number (sequential) component.
Definition: name.hpp:369
Interface for validating data and interest packets.
Definition: validator.hpp:61
function< void(const ConstBufferPtr &data)> CompleteCallback
bool hasNonce() const
Check if Nonce set.
Definition: interest.hpp:155