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  * Colorado State University,
5  * University Pierre & Marie Curie, Sorbonne University.
6  *
7  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
8  *
9  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
10  * terms of the GNU Lesser General Public License as published by the Free Software
11  * Foundation, either version 3 of the License, or (at your option) any later version.
12  *
13  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16  *
17  * You should have received copies of the GNU General Public License and GNU Lesser
18  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
22  *
23  * @author Shuo Yang
24  * @author Weiwei Liu
25  * @author Chavoosh Ghasemi
26  */
27 
28 #include "segment-fetcher.hpp"
29 #include "../name-component.hpp"
30 #include "../encoding/buffer-stream.hpp"
31 #include "../lp/nack.hpp"
32 #include "../lp/nack-header.hpp"
33 
34 #include <boost/lexical_cast.hpp>
35 #include <cmath>
36 
37 namespace ndn {
38 namespace util {
39 
40 constexpr double SegmentFetcher::MIN_SSTHRESH;
41 
42 void
44 {
45  if (maxTimeout < 1_ms) {
46  BOOST_THROW_EXCEPTION(std::invalid_argument("maxTimeout must be greater than or equal to 1 millisecond"));
47  }
48 
49  if (initCwnd < 1.0) {
50  BOOST_THROW_EXCEPTION(std::invalid_argument("initCwnd must be greater than or equal to 1"));
51  }
52 
53  if (aiStep < 0.0) {
54  BOOST_THROW_EXCEPTION(std::invalid_argument("aiStep must be greater than or equal to 0"));
55  }
56 
57  if (mdCoef < 0.0 || mdCoef > 1.0) {
58  BOOST_THROW_EXCEPTION(std::invalid_argument("mdCoef must be in range [0, 1]"));
59  }
60 }
61 
62 SegmentFetcher::SegmentFetcher(Face& face,
63  security::v2::Validator& validator,
64  const SegmentFetcher::Options& options)
65  : m_options(options)
66  , m_face(face)
67  , m_scheduler(m_face.getIoService())
68  , m_validator(validator)
69  , m_rttEstimator(options.rttOptions)
70  , m_timeLastSegmentReceived(time::steady_clock::now())
71  , m_nextSegmentNum(0)
72  , m_cwnd(options.initCwnd)
73  , m_ssthresh(options.initSsthresh)
74  , m_nSegmentsInFlight(0)
75  , m_nSegments(0)
76  , m_highInterest(0)
77  , m_highData(0)
78  , m_recPoint(0)
79  , m_nReceived(0)
80  , m_nBytesReceived(0)
81 {
82  m_options.validate();
83 }
84 
85 shared_ptr<SegmentFetcher>
87  const Interest& baseInterest,
88  security::v2::Validator& validator,
89  const SegmentFetcher::Options& options)
90 {
91  shared_ptr<SegmentFetcher> fetcher(new SegmentFetcher(face, validator, options));
92  fetcher->fetchFirstSegment(baseInterest, false, fetcher);
93  return fetcher;
94 }
95 
96 shared_ptr<SegmentFetcher>
98  const Interest& baseInterest,
99  security::v2::Validator& validator,
100  const CompleteCallback& completeCallback,
101  const ErrorCallback& errorCallback)
102 {
103  Options options;
104  options.useConstantCwnd = true;
105  options.useConstantInterestTimeout = true;
106  options.maxTimeout = baseInterest.getInterestLifetime();
107  options.interestLifetime = baseInterest.getInterestLifetime();
108  shared_ptr<SegmentFetcher> fetcher = start(face, baseInterest, validator, options);
109  fetcher->onComplete.connect(completeCallback);
110  fetcher->onError.connect(errorCallback);
111  return fetcher;
112 }
113 
114 shared_ptr<SegmentFetcher>
116  const Interest& baseInterest,
117  shared_ptr<security::v2::Validator> validator,
118  const CompleteCallback& completeCallback,
119  const ErrorCallback& errorCallback)
120 {
121  auto fetcher = fetch(face, baseInterest, *validator, completeCallback, errorCallback);
122  // Ensure lifetime of validator shared_ptr
123  fetcher->onComplete.connect([validator] (ConstBufferPtr) {});
124  return fetcher;
125 }
126 
127 void
128 SegmentFetcher::fetchFirstSegment(const Interest& baseInterest,
129  bool isRetransmission,
130  shared_ptr<SegmentFetcher> self)
131 {
132  Interest interest(baseInterest);
133  interest.setCanBePrefix(true);
134  interest.setMustBeFresh(true);
135  interest.setInterestLifetime(m_options.interestLifetime);
136  if (isRetransmission) {
137  interest.refreshNonce();
138  }
139 
140  m_nSegmentsInFlight++;
141  auto pendingInterest = m_face.expressInterest(interest,
142  bind(&SegmentFetcher::afterSegmentReceivedCb,
143  this, _1, _2, self),
144  bind(&SegmentFetcher::afterNackReceivedCb,
145  this, _1, _2, self),
146  nullptr);
147  auto timeoutEvent =
148  m_scheduler.scheduleEvent(m_options.useConstantInterestTimeout ? m_options.maxTimeout : getEstimatedRto(),
149  bind(&SegmentFetcher::afterTimeoutCb, this, interest, self));
150  if (isRetransmission) {
151  updateRetransmittedSegment(0, pendingInterest, timeoutEvent);
152  }
153  else {
154  BOOST_ASSERT(m_pendingSegments.count(0) == 0);
155  m_pendingSegments.emplace(0, PendingSegment{SegmentState::FirstInterest, time::steady_clock::now(),
156  pendingInterest, timeoutEvent});
157  }
158 }
159 
160 void
161 SegmentFetcher::fetchSegmentsInWindow(const Interest& origInterest, shared_ptr<SegmentFetcher> self)
162 {
163  if (checkAllSegmentsReceived()) {
164  // All segments have been retrieved
165  finalizeFetch(self);
166  }
167 
168  int64_t availableWindowSize = static_cast<int64_t>(m_cwnd) - m_nSegmentsInFlight;
169 
170  std::vector<std::pair<uint64_t, bool>> segmentsToRequest; // The boolean indicates whether a retx or not
171 
172  while (availableWindowSize > 0) {
173  if (!m_retxQueue.empty()) {
174  auto pendingSegmentIt = m_pendingSegments.find(m_retxQueue.front());
175  m_retxQueue.pop();
176  if (pendingSegmentIt == m_pendingSegments.end()) {
177  // Skip re-requesting this segment, since it was received after RTO timeout
178  continue;
179  }
180  BOOST_ASSERT(pendingSegmentIt->second.state == SegmentState::InRetxQueue);
181  segmentsToRequest.emplace_back(pendingSegmentIt->first, true);
182  }
183  else if (m_nSegments == 0 || m_nextSegmentNum < static_cast<uint64_t>(m_nSegments)) {
184  if (m_receivedSegments.count(m_nextSegmentNum) > 0) {
185  // Don't request a segment a second time if received in response to first "discovery" Interest
186  m_nextSegmentNum++;
187  continue;
188  }
189  segmentsToRequest.emplace_back(m_nextSegmentNum++, false);
190  }
191  else {
192  break;
193  }
194  availableWindowSize--;
195  }
196 
197  for (const auto& segment : segmentsToRequest) {
198  Interest interest(origInterest); // to preserve Interest elements
199  interest.refreshNonce();
200  interest.setCanBePrefix(false);
201  interest.setMustBeFresh(false);
202 
203  Name interestName(m_versionedDataName);
204  interestName.appendSegment(segment.first);
205  interest.setName(interestName);
206  interest.setInterestLifetime(m_options.interestLifetime);
207  m_nSegmentsInFlight++;
208  auto pendingInterest = m_face.expressInterest(interest,
209  bind(&SegmentFetcher::afterSegmentReceivedCb,
210  this, _1, _2, self),
211  bind(&SegmentFetcher::afterNackReceivedCb,
212  this, _1, _2, self),
213  nullptr);
214  auto timeoutEvent =
215  m_scheduler.scheduleEvent(m_options.useConstantInterestTimeout ? m_options.maxTimeout : getEstimatedRto(),
216  bind(&SegmentFetcher::afterTimeoutCb, this, interest, self));
217  if (segment.second) { // Retransmission
218  updateRetransmittedSegment(segment.first, pendingInterest, timeoutEvent);
219  }
220  else { // First request for segment
221  BOOST_ASSERT(m_pendingSegments.count(segment.first) == 0);
222  m_pendingSegments.emplace(segment.first, PendingSegment{SegmentState::FirstInterest,
223  time::steady_clock::now(),
224  pendingInterest, timeoutEvent});
225  m_highInterest = segment.first;
226  }
227  }
228 }
229 
230 void
231 SegmentFetcher::afterSegmentReceivedCb(const Interest& origInterest,
232  const Data& data,
233  shared_ptr<SegmentFetcher> self)
234 {
235  afterSegmentReceived(data);
236  BOOST_ASSERT(m_nSegmentsInFlight > 0);
237  m_nSegmentsInFlight--;
238 
239  name::Component currentSegmentComponent = data.getName().get(-1);
240  if (!currentSegmentComponent.isSegment()) {
241  return signalError(DATA_HAS_NO_SEGMENT, "Data Name has no segment number");
242  }
243 
244  uint64_t currentSegment = currentSegmentComponent.toSegment();
245 
246  // The first received Interest could have any segment ID
247  std::map<uint64_t, PendingSegment>::iterator pendingSegmentIt;
248  if (m_receivedSegments.size() > 0) {
249  pendingSegmentIt = m_pendingSegments.find(currentSegment);
250  }
251  else {
252  pendingSegmentIt = m_pendingSegments.begin();
253  }
254 
255  // Cancel timeout event
256  m_scheduler.cancelEvent(pendingSegmentIt->second.timeoutEvent);
257  pendingSegmentIt->second.timeoutEvent = nullptr;
258 
259  m_validator.validate(data,
260  bind(&SegmentFetcher::afterValidationSuccess, this, _1, origInterest,
261  pendingSegmentIt, self),
262  bind(&SegmentFetcher::afterValidationFailure, this, _1, _2, self));
263 }
264 
265 void
266 SegmentFetcher::afterValidationSuccess(const Data& data,
267  const Interest& origInterest,
268  std::map<uint64_t, PendingSegment>::iterator pendingSegmentIt,
269  shared_ptr<SegmentFetcher> self)
270 {
271  // We update the last receive time here instead of in the segment received callback so that the
272  // transfer will not fail to terminate if we only received invalid Data packets.
273  m_timeLastSegmentReceived = time::steady_clock::now();
274 
275  m_nReceived++;
276 
277  // It was verified in afterSegmentReceivedCb that the last Data name component is a segment number
278  uint64_t currentSegment = data.getName().get(-1).toSegment();
279  // Add measurement to RTO estimator (if not retransmission)
280  if (pendingSegmentIt->second.state == SegmentState::FirstInterest) {
281  m_rttEstimator.addMeasurement(m_timeLastSegmentReceived - pendingSegmentIt->second.sendTime,
282  std::max<int64_t>(m_nSegmentsInFlight + 1, 1));
283  }
284 
285  // Remove from pending segments map
286  m_pendingSegments.erase(pendingSegmentIt);
287 
288  // Copy data in segment to temporary buffer
289  auto receivedSegmentIt = m_receivedSegments.emplace(std::piecewise_construct,
290  std::forward_as_tuple(currentSegment),
291  std::forward_as_tuple(data.getContent().value_size()));
292  std::copy(data.getContent().value_begin(), data.getContent().value_end(),
293  receivedSegmentIt.first->second.begin());
294  m_nBytesReceived += data.getContent().value_size();
295  afterSegmentValidated(data);
296 
297  if (data.getFinalBlock()) {
298  if (!data.getFinalBlock()->isSegment()) {
299  return signalError(FINALBLOCKID_NOT_SEGMENT,
300  "Received FinalBlockId did not contain a segment component");
301  }
302 
303  if (data.getFinalBlock()->toSegment() + 1 != static_cast<uint64_t>(m_nSegments)) {
304  m_nSegments = data.getFinalBlock()->toSegment() + 1;
305  cancelExcessInFlightSegments();
306  }
307  }
308 
309  if (m_receivedSegments.size() == 1) {
310  m_versionedDataName = data.getName().getPrefix(-1);
311  if (currentSegment == 0) {
312  // We received the first segment in response, so we can increment the next segment number
313  m_nextSegmentNum++;
314  }
315  }
316 
317  if (m_highData < currentSegment) {
318  m_highData = currentSegment;
319  }
320 
321  if (data.getCongestionMark() > 0 && !m_options.ignoreCongMarks) {
322  windowDecrease();
323  }
324  else {
325  windowIncrease();
326  }
327 
328  fetchSegmentsInWindow(origInterest, self);
329 }
330 
331 void
332 SegmentFetcher::afterValidationFailure(const Data& data,
333  const security::v2::ValidationError& error,
334  shared_ptr<SegmentFetcher> self)
335 {
336  signalError(SEGMENT_VALIDATION_FAIL, "Segment validation failed: " +
337  boost::lexical_cast<std::string>(error));
338 }
339 
340 
341 void
342 SegmentFetcher::afterNackReceivedCb(const Interest& origInterest,
343  const lp::Nack& nack,
344  shared_ptr<SegmentFetcher> self)
345 {
347  BOOST_ASSERT(m_nSegmentsInFlight > 0);
348  m_nSegmentsInFlight--;
349 
350  switch (nack.getReason()) {
353  afterNackOrTimeout(origInterest, self);
354  break;
355  default:
356  signalError(NACK_ERROR, "Nack Error");
357  break;
358  }
359 }
360 
361 void
362 SegmentFetcher::afterTimeoutCb(const Interest& origInterest,
363  shared_ptr<SegmentFetcher> self)
364 {
366  BOOST_ASSERT(m_nSegmentsInFlight > 0);
367  m_nSegmentsInFlight--;
368  afterNackOrTimeout(origInterest, self);
369 }
370 
371 void
372 SegmentFetcher::afterNackOrTimeout(const Interest& origInterest, shared_ptr<SegmentFetcher> self)
373 {
374  if (time::steady_clock::now() >= m_timeLastSegmentReceived + m_options.maxTimeout) {
375  // Fail transfer due to exceeding the maximum timeout between the succesful receipt of segments
376  return signalError(INTEREST_TIMEOUT, "Timeout exceeded");
377  }
378 
379  name::Component lastNameComponent = origInterest.getName().get(-1);
380  std::map<uint64_t, PendingSegment>::iterator pendingSegmentIt;
381  BOOST_ASSERT(m_pendingSegments.size() > 0);
382  if (lastNameComponent.isSegment()) {
383  BOOST_ASSERT(m_pendingSegments.count(lastNameComponent.toSegment()) > 0);
384  pendingSegmentIt = m_pendingSegments.find(lastNameComponent.toSegment());
385  }
386  else { // First Interest
387  BOOST_ASSERT(m_pendingSegments.size() > 0);
388  pendingSegmentIt = m_pendingSegments.begin();
389  }
390 
391  // Cancel timeout event and set status to InRetxQueue
392  m_scheduler.cancelEvent(pendingSegmentIt->second.timeoutEvent);
393  pendingSegmentIt->second.timeoutEvent = nullptr;
394  pendingSegmentIt->second.state = SegmentState::InRetxQueue;
395 
396  m_rttEstimator.backoffRto();
397 
398  if (m_receivedSegments.size() == 0) {
399  // Resend first Interest (until maximum receive timeout exceeded)
400  fetchFirstSegment(origInterest, true, self);
401  }
402  else {
403  windowDecrease();
404  m_retxQueue.push(pendingSegmentIt->first);
405  fetchSegmentsInWindow(origInterest, self);
406  }
407 }
408 
409 void
410 SegmentFetcher::finalizeFetch(shared_ptr<SegmentFetcher> self)
411 {
412  // Combine segments into final buffer
413  OBufferStream buf;
414  // We may have received more segments than exist in the object.
415  BOOST_ASSERT(m_receivedSegments.size() >= static_cast<uint64_t>(m_nSegments));
416 
417  for (int64_t i = 0; i < m_nSegments; i++) {
418  buf.write(m_receivedSegments[i].get<const char>(), m_receivedSegments[i].size());
419  }
420 
421  onComplete(buf.buf());
422 }
423 
424 void
425 SegmentFetcher::windowIncrease()
426 {
427  if (m_options.useConstantCwnd) {
428  BOOST_ASSERT(m_cwnd == m_options.initCwnd);
429  return;
430  }
431 
432  if (m_cwnd < m_ssthresh) {
433  m_cwnd += m_options.aiStep; // additive increase
434  }
435  else {
436  m_cwnd += m_options.aiStep / std::floor(m_cwnd); // congestion avoidance
437  }
438 }
439 
440 void
441 SegmentFetcher::windowDecrease()
442 {
443  if (m_options.disableCwa || m_highData > m_recPoint) {
444  m_recPoint = m_highInterest;
445 
446  if (m_options.useConstantCwnd) {
447  BOOST_ASSERT(m_cwnd == m_options.initCwnd);
448  return;
449  }
450 
451  // Refer to RFC 5681, Section 3.1 for the rationale behind the code below
452  m_ssthresh = std::max(MIN_SSTHRESH, m_cwnd * m_options.mdCoef); // multiplicative decrease
453  m_cwnd = m_options.resetCwndToInit ? m_options.initCwnd : m_ssthresh;
454  }
455 }
456 
457 void
458 SegmentFetcher::signalError(uint32_t code, const std::string& msg)
459 {
460  // Cancel all pending Interests before signaling error
461  for (const auto& pendingSegment : m_pendingSegments) {
462  m_face.removePendingInterest(pendingSegment.second.id);
463  if (pendingSegment.second.timeoutEvent) {
464  m_scheduler.cancelEvent(pendingSegment.second.timeoutEvent);
465  }
466  }
467  onError(code, msg);
468 }
469 
470 void
471 SegmentFetcher::updateRetransmittedSegment(uint64_t segmentNum,
472  const PendingInterestId* pendingInterest,
473  scheduler::EventId timeoutEvent)
474 {
475  auto pendingSegmentIt = m_pendingSegments.find(segmentNum);
476  BOOST_ASSERT(pendingSegmentIt != m_pendingSegments.end());
477  BOOST_ASSERT(pendingSegmentIt->second.state == SegmentState::InRetxQueue);
478  pendingSegmentIt->second.state = SegmentState::Retransmitted;
479  pendingSegmentIt->second.id = pendingInterest;
480  pendingSegmentIt->second.timeoutEvent = timeoutEvent;
481 }
482 
483 void
484 SegmentFetcher::cancelExcessInFlightSegments()
485 {
486  for (auto it = m_pendingSegments.begin(); it != m_pendingSegments.end();) {
487  if (it->first >= static_cast<uint64_t>(m_nSegments)) {
488  m_face.removePendingInterest(it->second.id);
489  if (it->second.timeoutEvent) {
490  m_scheduler.cancelEvent(it->second.timeoutEvent);
491  }
492  it = m_pendingSegments.erase(it);
493  BOOST_ASSERT(m_nSegmentsInFlight > 0);
494  m_nSegmentsInFlight--;
495  }
496  else {
497  ++it;
498  }
499  }
500 }
501 
502 bool
503 SegmentFetcher::checkAllSegmentsReceived()
504 {
505  bool haveReceivedAllSegments = false;
506 
507  if (m_nSegments != 0 && m_nReceived >= m_nSegments) {
508  haveReceivedAllSegments = true;
509  // Verify that all segments in window have been received. If not, send Interests for missing segments.
510  for (uint64_t i = 0; i < static_cast<uint64_t>(m_nSegments); i++) {
511  if (m_receivedSegments.count(i) == 0) {
512  m_retxQueue.push(i);
513  haveReceivedAllSegments = false;
514  }
515  }
516  }
517 
518  return haveReceivedAllSegments;
519 }
520 
521 time::milliseconds
522 SegmentFetcher::getEstimatedRto()
523 {
524  // We don't want an Interest timeout greater than the maximum allowed timeout between the
525  // succesful receipt of segments
526  return std::min(m_options.maxTimeout,
527  time::duration_cast<time::milliseconds>(m_rttEstimator.getEstimatedRto()));
528 }
529 
530 } // namespace util
531 } // namespace ndn
const Name & getName() const
Definition: interest.hpp:133
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:65
uint64_t getCongestionMark() const
get the value of the CongestionMark tag
Definition: packet-base.cpp:28
time::milliseconds interestLifetime
lifetime of sent Interests - independent of Interest timeout
Interest & setMustBeFresh(bool mustBeFresh)
Add or remove MustBeFresh element.
Definition: interest.hpp:214
function< void(uint32_t code, const std::string &msg)> ErrorCallback
static time_point now() noexcept
Definition: time.cpp:80
an unrecoverable Nack was received during retrieval
void refreshNonce()
Change nonce value.
Definition: interest.cpp:564
static shared_ptr< SegmentFetcher > fetch(Face &face, const Interest &baseInterest, security::v2::Validator &validator, const CompleteCallback &completeCallback, const ErrorCallback &errorCallback)
Initiates segment fetching.
Signal< SegmentFetcher, ConstBufferPtr > onComplete
Emits upon successful retrieval of the complete data.
time::milliseconds maxTimeout
maximum allowed time between successful receipt of segments
bool useConstantInterestTimeout
if true, Interest timeout is kept at maxTimeout
Utility class to fetch the latest version of a segmented object.
Represents an Interest packet.
Definition: interest.hpp:43
const optional< name::Component > & getFinalBlock() const
Definition: data.hpp:222
Buffer::const_iterator value_begin() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:269
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:278
represents a Network Nack
Definition: nack.hpp:40
NackReason getReason() const
Definition: nack.hpp:92
double aiStep
additive increase step (in segments)
bool isSegment() const
Check if the component is segment number per NDN naming conventions.
one of the retrieved segments failed user-provided validation
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
Interest & setName(const Name &name)
Definition: interest.hpp:139
static shared_ptr< SegmentFetcher > start(Face &face, const Interest &baseInterest, security::v2::Validator &validator, const Options &options=Options())
Initiates segment fetching.
Signal< SegmentFetcher > afterSegmentNacked
Emits whenever an Interest for a data segment is nacked.
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:90
Signal< SegmentFetcher, Data > afterSegmentValidated
Emits whenever a received data segment has been successfully validated.
retrieval timed out because the maximum timeout between the successful receipt of segments was exceed...
function< void(ConstBufferPtr data)> CompleteCallback
one of the retrieved Data packets lacked a segment number in the last Name component (excl...
Represents an absolute name.
Definition: name.hpp:42
double initSsthresh
initial slow start threshold
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:316
double initCwnd
initial congestion window size
const Name & getName() const
Get name.
Definition: data.hpp:124
Represents a name component.
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
Signal< SegmentFetcher, Data > afterSegmentReceived
Emits whenever a data segment received.
Signal< SegmentFetcher > afterSegmentTimedOut
Emits whenever an Interest for a data segment times out.
RttEstimator::Options rttOptions
options for RTT estimator
Validation error code and optional detailed error message.
const Block & getContent() const
Get Content.
Definition: data.cpp:234
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix of the name.
Definition: name.hpp:202
Interest & setInterestLifetime(time::milliseconds lifetime)
Set Interest&#39;s lifetime.
Definition: interest.cpp:578
implements an output stream that constructs ndn::Buffer
time::milliseconds getInterestLifetime() const
Definition: interest.hpp:278
Signal< SegmentFetcher, uint32_t, std::string > onError
Emits when the retrieval could not be completed due to an error.
Identifies a scheduled event.
Definition: scheduler.hpp:53
Represents a Data packet.
Definition: data.hpp:35
a received FinalBlockId did not contain a segment component
bool useConstantCwnd
if true, window size is kept at initCwnd
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:156
Name & appendSegment(uint64_t segmentNo)
Append a segment number (sequential) component.
Definition: name.hpp:381
Interface for validating data and interest packets.
Definition: validator.hpp:61
Interest & setCanBePrefix(bool canBePrefix)
Add or remove CanBePrefix element.
Definition: interest.hpp:186
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:126