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-2022 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  Interest interest;
62  interest.setName(command->getRequestName(options.getPrefix(), parameters));
63  interest.setInterestLifetime(options.getTimeout());
64  m_signer.makeSignedInterest(interest, options.getSigningInfo());
65 
66  m_face.expressInterest(interest,
67  [=] (const Interest&, const Data& data) {
68  processCommandResponse(data, command, onSuccess, onFailure);
69  },
70  [=] (const Interest&, const lp::Nack& nack) {
71  if (onFailure)
73  "received Nack: " + boost::lexical_cast<std::string>(nack.getReason())));
74  },
75  [=] (const Interest&) {
76  if (onFailure)
77  onFailure(ControlResponse(Controller::ERROR_TIMEOUT, "request timed out"));
78  });
79 }
80 
81 void
82 Controller::processCommandResponse(const Data& data,
83  const shared_ptr<ControlCommand>& command,
84  const CommandSucceedCallback& onSuccess,
85  const CommandFailCallback& onFailure)
86 {
87  m_validator.validate(data,
88  [=] (const Data& data) {
89  processValidatedCommandResponse(data, command, onSuccess, onFailure);
90  },
91  [=] (const Data&, const auto& error) {
92  if (onFailure)
93  onFailure(ControlResponse(ERROR_VALIDATION, boost::lexical_cast<std::string>(error)));
94  }
95  );
96 }
97 
98 void
99 Controller::processValidatedCommandResponse(const Data& data,
100  const shared_ptr<ControlCommand>& command,
101  const CommandSucceedCallback& onSuccess,
102  const CommandFailCallback& onFailure)
103 {
104  ControlResponse response;
105  try {
106  response.wireDecode(data.getContent().blockFromValue());
107  }
108  catch (const tlv::Error& e) {
109  if (onFailure)
110  onFailure(ControlResponse(ERROR_SERVER, e.what()));
111  return;
112  }
113 
114  uint32_t code = response.getCode();
115  if (code >= ERROR_LBOUND) {
116  if (onFailure)
117  onFailure(response);
118  return;
119  }
120 
121  ControlParameters parameters;
122  try {
123  parameters.wireDecode(response.getBody());
124  }
125  catch (const tlv::Error& e) {
126  if (onFailure)
127  onFailure(ControlResponse(ERROR_SERVER, e.what()));
128  return;
129  }
130 
131  try {
132  command->validateResponse(parameters);
133  }
134  catch (const ControlCommand::ArgumentError& e) {
135  if (onFailure)
136  onFailure(ControlResponse(ERROR_SERVER, e.what()));
137  return;
138  }
139 
140  if (onSuccess)
141  onSuccess(parameters);
142 }
143 
144 void
145 Controller::fetchDataset(const Name& prefix,
146  const std::function<void(ConstBufferPtr)>& processResponse,
147  const DatasetFailCallback& onFailure,
148  const CommandOptions& options)
149 {
150  SegmentFetcher::Options fetcherOptions;
151  fetcherOptions.maxTimeout = options.getTimeout();
152 
153  auto fetcher = SegmentFetcher::start(m_face, Interest(prefix), m_validator, fetcherOptions);
154  if (processResponse) {
155  fetcher->onComplete.connect(processResponse);
156  }
157  if (onFailure) {
158  fetcher->onError.connect([=] (uint32_t code, const std::string& msg) {
159  processDatasetFetchError(onFailure, code, msg);
160  });
161  }
162 
163  auto it = m_fetchers.insert(fetcher).first;
164  fetcher->onComplete.connect([this, it] (auto&&...) { m_fetchers.erase(it); });
165  fetcher->onError.connect([this, it] (auto&&...) { m_fetchers.erase(it); });
166 }
167 
168 void
169 Controller::processDatasetFetchError(const DatasetFailCallback& onFailure,
170  uint32_t code, std::string msg)
171 {
172  BOOST_ASSERT(onFailure);
173 
174  switch (static_cast<SegmentFetcher::ErrorCode>(code)) {
175  // It's intentional to cast to SegmentFetcher::ErrorCode and to not have a 'default' clause.
176  // This forces the switch statement to handle every defined SegmentFetcher::ErrorCode,
177  // and breaks compilation if it does not.
178  case SegmentFetcher::ErrorCode::INTEREST_TIMEOUT:
179  onFailure(ERROR_TIMEOUT, msg);
180  break;
181  case SegmentFetcher::ErrorCode::DATA_HAS_NO_SEGMENT:
182  case SegmentFetcher::ErrorCode::FINALBLOCKID_NOT_SEGMENT:
183  onFailure(ERROR_SERVER, msg);
184  break;
185  case SegmentFetcher::ErrorCode::SEGMENT_VALIDATION_FAIL:
186  // TODO: When SegmentFetcher exposes validator error code, Controller::ERROR_VALIDATION
187  // should be replaced with a range that corresponds to validator error codes.
188  onFailure(ERROR_VALIDATION, msg);
189  break;
190  case SegmentFetcher::ErrorCode::NACK_ERROR:
191  onFailure(ERROR_NACK, msg);
192  break;
193  }
194 }
195 
196 } // namespace nfd
197 } // namespace ndn
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:164
Represents an Interest packet.
Definition: interest.hpp:50
Interest & setName(const Name &name)
Set the Interest's name.
Definition: interest.cpp:369
Interest & setInterestLifetime(time::milliseconds lifetime)
Set the Interest's lifetime.
Definition: interest.cpp:437
Represents a Network Nack.
Definition: nack.hpp:40
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
static const uint32_t ERROR_TIMEOUT
Error code for timeout.
Definition: controller.hpp:157
static const uint32_t ERROR_SERVER
Error code for server error.
Definition: controller.hpp:166
static const uint32_t ERROR_LBOUND
Inclusive lower bound of error codes.
Definition: controller.hpp:169
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:39
static const uint32_t ERROR_VALIDATION
Error code for response validation failure.
Definition: controller.hpp:163
security::InterestSigner m_signer
Definition: controller.hpp:175
static const uint32_t ERROR_NACK
Error code for network Nack.
Definition: controller.hpp:160
std::set< shared_ptr< util::SegmentFetcher > > m_fetchers
Definition: controller.hpp:178
security::Validator & m_validator
Definition: controller.hpp:174
void makeSignedInterest(Interest &interest, SigningInfo params=SigningInfo(), uint32_t signingFlags=WantNonce|WantTime)
Signs an Interest (following Packet Specification v0.3 or newer)
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:49
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:71
@ Data
Definition: tlv.hpp:69
@ Interest
Definition: tlv.hpp:68
Definition: data.cpp:25
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:139