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-2018 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 #include <cmath>
30 
31 namespace ndn {
32 namespace util {
33 
35 
36 SegmentFetcher::SegmentFetcher(Face& face,
37  shared_ptr<security::v2::Validator> validator,
38  const CompleteCallback& completeCallback,
39  const ErrorCallback& errorCallback)
40  : m_face(face)
41  , m_scheduler(m_face.getIoService())
42  , m_validator(validator)
43  , m_completeCallback(completeCallback)
44  , m_errorCallback(errorCallback)
45  , m_buffer(make_shared<OBufferStream>())
46 {
47 }
48 
49 shared_ptr<SegmentFetcher>
50 SegmentFetcher::fetch(Face& face,
51  const Interest& baseInterest,
52  security::v2::Validator& validator,
53  const CompleteCallback& completeCallback,
54  const ErrorCallback& errorCallback)
55 {
56  shared_ptr<security::v2::Validator> validatorPtr(&validator, [] (security::v2::Validator*) {});
57  return fetch(face, baseInterest, validatorPtr, completeCallback, errorCallback);
58 }
59 
60 shared_ptr<SegmentFetcher>
61 SegmentFetcher::fetch(Face& face,
62  const Interest& baseInterest,
63  shared_ptr<security::v2::Validator> validator,
64  const CompleteCallback& completeCallback,
65  const ErrorCallback& errorCallback)
66 {
67  shared_ptr<SegmentFetcher> fetcher(new SegmentFetcher(face, validator, completeCallback,
68  errorCallback));
69 
70  fetcher->fetchFirstSegment(baseInterest, fetcher);
71 
72  return fetcher;
73 }
74 
75 void
76 SegmentFetcher::fetchFirstSegment(const Interest& baseInterest,
77  shared_ptr<SegmentFetcher> self)
78 {
79  Interest interest(baseInterest);
80  interest.setChildSelector(1);
81  interest.setMustBeFresh(true);
82 
83  m_face.expressInterest(interest,
84  bind(&SegmentFetcher::afterSegmentReceivedCb, this, _1, _2, true, self),
85  bind(&SegmentFetcher::afterNackReceivedCb, this, _1, _2, 0, self),
86  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
87 }
88 
89 void
90 SegmentFetcher::fetchNextSegment(const Interest& origInterest, const Name& dataName,
91  uint64_t segmentNo,
92  shared_ptr<SegmentFetcher> self)
93 {
94  Interest interest(origInterest); // to preserve any selectors
95  interest.refreshNonce();
96  interest.setChildSelector(0);
97  interest.setMustBeFresh(false);
98  interest.setName(dataName.getPrefix(-1).appendSegment(segmentNo));
99  m_face.expressInterest(interest,
100  bind(&SegmentFetcher::afterSegmentReceivedCb, this, _1, _2, false, self),
101  bind(&SegmentFetcher::afterNackReceivedCb, this, _1, _2, 0, self),
102  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
103 }
104 
105 void
106 SegmentFetcher::afterSegmentReceivedCb(const Interest& origInterest,
107  const Data& data, bool isSegmentZeroExpected,
108  shared_ptr<SegmentFetcher> self)
109 {
110  afterSegmentReceived(data);
111  m_validator->validate(data,
112  bind(&SegmentFetcher::afterValidationSuccess, this, _1,
113  isSegmentZeroExpected, origInterest, self),
114  bind(&SegmentFetcher::afterValidationFailure, this, _1, _2));
115 
116 }
117 
118 void
119 SegmentFetcher::afterValidationSuccess(const Data& data,
120  bool isSegmentZeroExpected,
121  const Interest& origInterest,
122  shared_ptr<SegmentFetcher> self)
123 {
124  name::Component currentSegment = data.getName().get(-1);
125 
126  if (currentSegment.isSegment()) {
127  if (isSegmentZeroExpected && currentSegment.toSegment() != 0) {
128  fetchNextSegment(origInterest, data.getName(), 0, self);
129  }
130  else {
131  m_buffer->write(reinterpret_cast<const char*>(data.getContent().value()),
132  data.getContent().value_size());
133  afterSegmentValidated(data);
134  const auto& finalBlockId = data.getFinalBlock();
135  if (!finalBlockId || (*finalBlockId > currentSegment)) {
136  fetchNextSegment(origInterest, data.getName(), currentSegment.toSegment() + 1, self);
137  }
138  else {
139  return m_completeCallback(m_buffer->buf());
140  }
141  }
142  }
143  else {
144  m_errorCallback(DATA_HAS_NO_SEGMENT, "Data Name has no segment number.");
145  }
146 }
147 
148 void
149 SegmentFetcher::afterValidationFailure(const Data& data, const security::v2::ValidationError& error)
150 {
151  return m_errorCallback(SEGMENT_VALIDATION_FAIL, "Segment validation fail " +
152  boost::lexical_cast<std::string>(error));
153 }
154 
155 
156 void
157 SegmentFetcher::afterNackReceivedCb(const Interest& origInterest, const lp::Nack& nack,
158  uint32_t reExpressCount, shared_ptr<SegmentFetcher> self)
159 {
160  if (reExpressCount >= MAX_INTEREST_REEXPRESS) {
161  m_errorCallback(NACK_ERROR, "Nack Error");
162  }
163  else {
164  switch (nack.getReason()) {
166  reExpressInterest(origInterest, reExpressCount, self);
167  break;
169  using ms = time::milliseconds;
170  m_scheduler.scheduleEvent(ms(static_cast<ms::rep>(std::pow(2, reExpressCount + 1))),
171  bind(&SegmentFetcher::reExpressInterest, this,
172  origInterest, reExpressCount, self));
173  break;
174  default:
175  m_errorCallback(NACK_ERROR, "Nack Error");
176  break;
177  }
178  }
179 }
180 
181 void
182 SegmentFetcher::reExpressInterest(Interest interest, uint32_t reExpressCount,
183  shared_ptr<SegmentFetcher> self)
184 {
185  interest.refreshNonce();
186  BOOST_ASSERT(interest.hasNonce());
187 
188  bool isSegmentZeroExpected = true;
189  if (!interest.getName().empty()) {
190  name::Component lastComponent = interest.getName().get(-1);
191  isSegmentZeroExpected = !lastComponent.isSegment();
192  }
193 
194  m_face.expressInterest(interest,
195  bind(&SegmentFetcher::afterSegmentReceivedCb, this, _1, _2,
196  isSegmentZeroExpected, self),
197  bind(&SegmentFetcher::afterNackReceivedCb, this, _1, _2,
198  ++reExpressCount, self),
199  bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout"));
200 }
201 
202 } // namespace util
203 } // namespace ndn
const Name & getName() const
Definition: interest.hpp:137
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
Interest & setMustBeFresh(bool mustBeFresh)
Add or remove MustBeFresh element.
Definition: interest.hpp:197
function< void(uint32_t code, const std::string &msg)> ErrorCallback
void refreshNonce()
Change nonce value.
Definition: interest.cpp:462
Utility class to fetch latest version of the segmented data.
Represents an Interest packet.
Definition: interest.hpp:42
const optional< name::Component > & getFinalBlock() const
Definition: data.hpp:226
function< void(const std::string &reason)> ErrorCallback
Definition: dns.hpp:73
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:371
Interest & setName(const Name &name)
Definition: interest.hpp:143
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:90
Represents an absolute name.
Definition: name.hpp:42
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:319
const Name & getName() const
Get name.
Definition: data.hpp:128
Represents a name component.
Validation error code and optional detailed error message.
const Block & getContent() const
Get Content.
Definition: data.cpp:234
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:313
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 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:389
Interface for validating data and interest packets.
Definition: validator.hpp:61
function< void(const ConstBufferPtr &data)> CompleteCallback
bool hasNonce() const
Check if the Nonce element is present.
Definition: interest.hpp:235