controller.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2023 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 
23 #include "ndn-cxx/face.hpp"
25 
26 #include <boost/lexical_cast.hpp>
27 
28 namespace ndn::nfd {
29 
31  : m_face(face)
32  , m_keyChain(keyChain)
33  , m_validator(validator)
34  , m_signer(keyChain)
35 {
36 }
37 
39 {
40  for (const auto& sp : m_fetchers) {
41  sp->stop();
42  }
43 }
44 
45 void
46 Controller::startCommand(const shared_ptr<ControlCommand>& command,
47  const ControlParameters& parameters,
48  const CommandSuccessCallback& onSuccess,
49  const CommandFailureCallback& onFailure,
50  const CommandOptions& options)
51 {
52  Interest interest;
53  interest.setName(command->getRequestName(options.getPrefix(), parameters));
54  interest.setInterestLifetime(options.getTimeout());
55  m_signer.makeSignedInterest(interest, options.getSigningInfo());
56 
57  m_face.expressInterest(interest,
58  [=] (const Interest&, const Data& data) {
59  processCommandResponse(data, command, onSuccess, onFailure);
60  },
61  [=] (const Interest&, const lp::Nack& nack) {
62  if (onFailure)
64  "received Nack: " + boost::lexical_cast<std::string>(nack.getReason())));
65  },
66  [=] (const Interest&) {
67  if (onFailure)
68  onFailure(ControlResponse(Controller::ERROR_TIMEOUT, "request timed out"));
69  });
70 }
71 
72 void
73 Controller::processCommandResponse(const Data& data,
74  const shared_ptr<ControlCommand>& command,
75  const CommandSuccessCallback& onSuccess,
76  const CommandFailureCallback& onFailure)
77 {
78  m_validator.validate(data,
79  [=] (const Data& d) {
80  processValidatedCommandResponse(d, command, onSuccess, onFailure);
81  },
82  [=] (const Data&, const auto& error) {
83  if (onFailure)
84  onFailure(ControlResponse(ERROR_VALIDATION, boost::lexical_cast<std::string>(error)));
85  }
86  );
87 }
88 
89 void
90 Controller::processValidatedCommandResponse(const Data& data,
91  const shared_ptr<ControlCommand>& command,
92  const CommandSuccessCallback& onSuccess,
93  const CommandFailureCallback& onFailure)
94 {
95  ControlResponse response;
96  try {
97  response.wireDecode(data.getContent().blockFromValue());
98  }
99  catch (const tlv::Error& e) {
100  if (onFailure)
101  onFailure(ControlResponse(ERROR_SERVER, "ControlResponse decoding failure: "s + e.what()));
102  return;
103  }
104 
105  if (response.getCode() >= ERROR_LBOUND) {
106  if (onFailure)
107  onFailure(response);
108  return;
109  }
110 
111  ControlParameters parameters;
112  try {
113  parameters.wireDecode(response.getBody());
114  }
115  catch (const tlv::Error& e) {
116  if (onFailure)
117  onFailure(ControlResponse(ERROR_SERVER, "ControlParameters decoding failure: "s + e.what()));
118  return;
119  }
120 
121  try {
122  command->validateResponse(parameters);
123  }
124  catch (const ControlCommand::ArgumentError& e) {
125  if (onFailure)
126  onFailure(ControlResponse(ERROR_SERVER, "Invalid response: "s + e.what()));
127  return;
128  }
129 
130  if (onSuccess)
131  onSuccess(parameters);
132 }
133 
134 void
135 Controller::fetchDataset(const Name& prefix,
136  const std::function<void(ConstBufferPtr)>& processResponse,
137  const DatasetFailureCallback& onFailure,
138  const CommandOptions& options)
139 {
140  SegmentFetcher::Options fetcherOptions;
141  fetcherOptions.maxTimeout = options.getTimeout();
142 
143  auto fetcher = SegmentFetcher::start(m_face, Interest(prefix), m_validator, fetcherOptions);
144  fetcher->onComplete.connect(processResponse);
145  if (onFailure) {
146  fetcher->onError.connect([onFailure] (uint32_t code, const std::string& msg) {
147  processDatasetFetchError(onFailure, code, msg);
148  });
149  }
150 
151  auto it = m_fetchers.insert(fetcher).first;
152  fetcher->onComplete.connect([this, it] (auto&&...) { m_fetchers.erase(it); });
153  fetcher->onError.connect([this, it] (auto&&...) { m_fetchers.erase(it); });
154 }
155 
156 void
157 Controller::processDatasetFetchError(const DatasetFailureCallback& onFailure,
158  uint32_t code, std::string msg)
159 {
160  BOOST_ASSERT(onFailure);
161 
162  switch (static_cast<SegmentFetcher::ErrorCode>(code)) {
163  // It's intentional to cast to SegmentFetcher::ErrorCode and to not have a 'default' clause.
164  // This forces the switch statement to handle every defined SegmentFetcher::ErrorCode,
165  // and breaks compilation if it does not.
166  case SegmentFetcher::ErrorCode::INTEREST_TIMEOUT:
167  onFailure(ERROR_TIMEOUT, msg);
168  break;
169  case SegmentFetcher::ErrorCode::DATA_HAS_NO_SEGMENT:
170  case SegmentFetcher::ErrorCode::FINALBLOCKID_NOT_SEGMENT:
171  onFailure(ERROR_SERVER, msg);
172  break;
173  case SegmentFetcher::ErrorCode::SEGMENT_VALIDATION_FAIL:
174  // TODO: When SegmentFetcher exposes validator error code, Controller::ERROR_VALIDATION
175  // should be replaced with a range that corresponds to validator error codes.
176  onFailure(ERROR_VALIDATION, msg);
177  break;
178  case SegmentFetcher::ErrorCode::NACK_ERROR:
179  onFailure(ERROR_NACK, msg);
180  break;
181  }
182 }
183 
184 } // namespace ndn::nfd
Represents a Data packet.
Definition: data.hpp:39
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:91
PendingInterestHandle expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express an Interest.
Definition: face.cpp:151
Represents an Interest packet.
Definition: interest.hpp:50
Interest & setName(const Name &name)
Set the Interest name.
Definition: interest.cpp:354
Interest & setInterestLifetime(time::milliseconds lifetime)
Set the Interest's lifetime.
Definition: interest.cpp:451
static shared_ptr< SegmentFetcher > start(Face &face, const Interest &baseInterest, security::Validator &validator, const Options &options={})
Initiates segment fetching.
ErrorCode
Error codes passed to onError.
SegmentFetcherOptions Options
Represents a Network Nack.
Definition: nack.hpp:39
void wireDecode(const Block &block)
Contains options for ControlCommand execution.
const Name & getPrefix() const
Returns the command prefix.
time::milliseconds getTimeout() const
Returns the command timeout.
const security::SigningInfo & getSigningInfo() const
Returns the signing parameters.
Represents parameters in a ControlCommand request or response.
void wireDecode(const Block &wire) final
Controller(Face &face, KeyChain &keyChain, security::Validator &validator=security::getAcceptAllValidator())
Construct a Controller that uses face as transport and keyChain to sign commands.
Definition: controller.cpp:30
@ ERROR_LBOUND
Inclusive lower bound of error codes.
Definition: controller.hpp:166
@ ERROR_VALIDATION
Error code for response validation failure.
Definition: controller.hpp:174
@ ERROR_SERVER
Error code for server error.
Definition: controller.hpp:168
@ ERROR_NACK
Error code for network Nack.
Definition: controller.hpp:172
@ ERROR_TIMEOUT
Error code for timeout.
Definition: controller.hpp:170
security::InterestSigner m_signer
Definition: controller.hpp:181
security::Validator & m_validator
Definition: controller.hpp:180
std::set< shared_ptr< SegmentFetcher > > m_fetchers
Definition: controller.hpp:184
void makeSignedInterest(Interest &interest, SigningInfo params=SigningInfo(), uint32_t signingFlags=WantNonce|WantTime)
Signs an Interest (following Packet Specification v0.3 or newer)
The main interface for signing key management.
Definition: key-chain.hpp:87
Interface for validating data and interest packets.
Definition: validator.hpp:61
void validate(const Data &data, const DataValidationSuccessCallback &successCb, const DataValidationFailureCallback &failureCb)
Asynchronously validate data.
Definition: validator.cpp:47
std::function< void(const ControlResponse &)> CommandFailureCallback
Callback on command failure.
Definition: controller.hpp:57
std::function< void(uint32_t code, const std::string &reason)> DatasetFailureCallback
Callback on dataset retrieval failure.
Definition: controller.hpp:71
std::function< void(const ControlParameters &)> CommandSuccessCallback
Callback on command success.
Definition: controller.hpp:51
Contains classes and functions related to the NFD Management protocol.
mgmt::ControlResponse ControlResponse
@ ControlParameters
Definition: tlv-nfd.hpp:35
@ Name
Definition: tlv.hpp:71
@ Data
Definition: tlv.hpp:69
@ Interest
Definition: tlv.hpp:68
std::shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:140
time::milliseconds maxTimeout
Maximum allowed time between successful receipt of segments.