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-2021 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 {
29 namespace nfd {
30 
32 
33 const uint32_t Controller::ERROR_TIMEOUT = 10060; // WinSock ESAETIMEDOUT
34 const uint32_t Controller::ERROR_NACK = 10800; // 10000 + TLV-TYPE of Nack header
35 const uint32_t Controller::ERROR_VALIDATION = 10021; // 10000 + TLS1_ALERT_DECRYPTION_FAILED
36 const uint32_t Controller::ERROR_SERVER = 500;
37 const uint32_t Controller::ERROR_LBOUND = 400;
38 
39 Controller::Controller(Face& face, KeyChain& keyChain, security::Validator& validator)
40  : m_face(face)
41  , m_keyChain(keyChain)
42  , m_validator(validator)
43  , m_signer(keyChain)
44 {
45 }
46 
48 {
49  for (const auto& sp : m_fetchers) {
50  sp->stop();
51  }
52 }
53 
54 void
55 Controller::startCommand(const shared_ptr<ControlCommand>& command,
56  const ControlParameters& parameters,
57  const CommandSucceedCallback& onSuccess,
58  const CommandFailCallback& onFailure,
59  const CommandOptions& options)
60 {
61  Name requestName = command->getRequestName(options.getPrefix(), parameters);
62  Interest interest = m_signer.makeCommandInterest(requestName, options.getSigningInfo());
63  interest.setInterestLifetime(options.getTimeout());
64 
65  m_face.expressInterest(interest,
66  [=] (const Interest&, const Data& data) {
67  processCommandResponse(data, command, onSuccess, onFailure);
68  },
69  [=] (const Interest&, const lp::Nack&) {
70  if (onFailure)
71  onFailure(ControlResponse(Controller::ERROR_NACK, "network Nack received"));
72  },
73  [=] (const Interest&) {
74  if (onFailure)
75  onFailure(ControlResponse(Controller::ERROR_TIMEOUT, "request timed out"));
76  });
77 }
78 
79 void
80 Controller::processCommandResponse(const Data& data,
81  const shared_ptr<ControlCommand>& command,
82  const CommandSucceedCallback& onSuccess,
83  const CommandFailCallback& onFailure)
84 {
85  m_validator.validate(data,
86  [=] (const Data& data) {
87  processValidatedCommandResponse(data, command, onSuccess, onFailure);
88  },
89  [=] (const Data&, const auto& error) {
90  if (onFailure)
91  onFailure(ControlResponse(ERROR_VALIDATION, boost::lexical_cast<std::string>(error)));
92  }
93  );
94 }
95 
96 void
97 Controller::processValidatedCommandResponse(const Data& data,
98  const shared_ptr<ControlCommand>& command,
99  const CommandSucceedCallback& onSuccess,
100  const CommandFailCallback& onFailure)
101 {
102  ControlResponse response;
103  try {
104  response.wireDecode(data.getContent().blockFromValue());
105  }
106  catch (const tlv::Error& e) {
107  if (onFailure)
108  onFailure(ControlResponse(ERROR_SERVER, e.what()));
109  return;
110  }
111 
112  uint32_t code = response.getCode();
113  if (code >= ERROR_LBOUND) {
114  if (onFailure)
115  onFailure(response);
116  return;
117  }
118 
119  ControlParameters parameters;
120  try {
121  parameters.wireDecode(response.getBody());
122  }
123  catch (const tlv::Error& e) {
124  if (onFailure)
125  onFailure(ControlResponse(ERROR_SERVER, e.what()));
126  return;
127  }
128 
129  try {
130  command->validateResponse(parameters);
131  }
132  catch (const ControlCommand::ArgumentError& e) {
133  if (onFailure)
134  onFailure(ControlResponse(ERROR_SERVER, e.what()));
135  return;
136  }
137 
138  if (onSuccess)
139  onSuccess(parameters);
140 }
141 
142 void
143 Controller::fetchDataset(const Name& prefix,
144  const std::function<void(ConstBufferPtr)>& processResponse,
145  const DatasetFailCallback& onFailure,
146  const CommandOptions& options)
147 {
148  SegmentFetcher::Options fetcherOptions;
149  fetcherOptions.maxTimeout = options.getTimeout();
150 
151  auto fetcher = SegmentFetcher::start(m_face, Interest(prefix), m_validator, fetcherOptions);
152  if (processResponse) {
153  fetcher->onComplete.connect(processResponse);
154  }
155  if (onFailure) {
156  fetcher->onError.connect([=] (uint32_t code, const std::string& msg) {
157  processDatasetFetchError(onFailure, code, msg);
158  });
159  }
160 
161  auto it = m_fetchers.insert(fetcher).first;
162  fetcher->onComplete.connect([this, it] (ConstBufferPtr) { m_fetchers.erase(it); });
163  fetcher->onError.connect([this, it] (uint32_t, const std::string&) { m_fetchers.erase(it); });
164 }
165 
166 void
167 Controller::processDatasetFetchError(const DatasetFailCallback& onFailure,
168  uint32_t code, std::string msg)
169 {
170  BOOST_ASSERT(onFailure);
171 
172  switch (static_cast<SegmentFetcher::ErrorCode>(code)) {
173  // It's intentional to cast as SegmentFetcher::ErrorCode, and to not have a 'default' clause.
174  // This forces the switch statement to handle every defined SegmentFetcher::ErrorCode,
175  // and breaks compilation if it does not.
176  case SegmentFetcher::ErrorCode::INTEREST_TIMEOUT:
177  onFailure(ERROR_TIMEOUT, msg);
178  break;
179  case SegmentFetcher::ErrorCode::DATA_HAS_NO_SEGMENT:
180  case SegmentFetcher::ErrorCode::FINALBLOCKID_NOT_SEGMENT:
181  onFailure(ERROR_SERVER, msg);
182  break;
183  case SegmentFetcher::ErrorCode::SEGMENT_VALIDATION_FAIL:
186  onFailure(ERROR_VALIDATION, msg);
187  break;
188  case SegmentFetcher::ErrorCode::NACK_ERROR:
189  onFailure(ERROR_NACK, msg);
190  break;
191  }
192 }
193 
194 } // namespace nfd
195 } // namespace ndn
Represents a Data packet.
Definition: data.hpp:38
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 Interest.
Definition: face.cpp:164
Represents an Interest packet.
Definition: interest.hpp:50
Interest & setInterestLifetime(time::milliseconds lifetime)
Set the Interest's lifetime.
Definition: interest.cpp:440
Represents an absolute name.
Definition: name.hpp:46
represents a Network Nack
Definition: nack.hpp:39
void wireDecode(const Block &block)
contains options for ControlCommand execution
const Name & getPrefix() const
const time::milliseconds & getTimeout() const
const security::SigningInfo & getSigningInfo() const
represents parameters in a ControlCommand request or response
void wireDecode(const Block &wire) final
static const uint32_t ERROR_TIMEOUT
error code for timeout
Definition: controller.hpp:155
static const uint32_t ERROR_SERVER
error code for server error
Definition: controller.hpp:167
static const uint32_t ERROR_LBOUND
inclusive lower bound of error codes
Definition: controller.hpp:171
Controller(Face &face, KeyChain &keyChain, security::Validator &validator=security::getAcceptAllValidator())
construct a Controller that uses face for transport, and uses the passed KeyChain to sign commands
Definition: controller.cpp:39
static const uint32_t ERROR_VALIDATION
error code for response validation failure
Definition: controller.hpp:163
security::InterestSigner m_signer
Definition: controller.hpp:177
static const uint32_t ERROR_NACK
error code for network Nack
Definition: controller.hpp:159
std::set< shared_ptr< util::SegmentFetcher > > m_fetchers
Definition: controller.hpp:180
security::Validator & m_validator
Definition: controller.hpp:176
Interest makeCommandInterest(Name name, const SigningInfo &params=SigningInfo())
Creates and signs a command Interest.
Interface for validating data and interest packets.
Definition: validator.hpp:62
void validate(const Data &data, const DataValidationSuccessCallback &successCb, const DataValidationFailureCallback &failureCb)
Asynchronously validate data.
Definition: validator.cpp:75
Utility class to fetch the latest version of a segmented object.
static shared_ptr< SegmentFetcher > start(Face &face, const Interest &baseInterest, security::Validator &validator, const Options &options=Options())
Initiates segment fetching.
ErrorCode
Error codes passed to onError.
mgmt::ControlResponse ControlResponse
@ ControlParameters
Definition: tlv-nfd.hpp:35
@ Name
Definition: tlv.hpp:67
@ Data
Definition: tlv.hpp:66
@ Interest
Definition: tlv.hpp:65
Definition: data.cpp:25
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:139