face-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2017, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "face-manager.hpp"
29 #include "fw/face-table.hpp"
30 
31 #include <ndn-cxx/lp/tags.hpp>
32 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
33 
34 namespace nfd {
35 
36 NFD_LOG_INIT("FaceManager");
37 
38 FaceManager::FaceManager(FaceSystem& faceSystem,
39  Dispatcher& dispatcher, CommandAuthenticator& authenticator)
40  : NfdManagerBase(dispatcher, authenticator, "faces")
41  , m_faceSystem(faceSystem)
42  , m_faceTable(faceSystem.getFaceTable())
43 {
44  // register handlers for ControlCommand
45  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
46  bind(&FaceManager::createFace, this, _2, _3, _4, _5));
47 
48  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
49  bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
50 
51  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
52  bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
53 
54  // register handlers for StatusDataset
55  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
56  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
57  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
58 
59  // register notification stream
60  m_postNotification = registerNotificationStream("events");
61  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
62  connectFaceStateChangeSignal(face);
63  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
64  });
65  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
66  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
67  });
68 }
69 
70 void
72 {
73  m_faceSystem.setConfigFile(configFile);
74 }
75 
76 void
77 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
78  const ControlParameters& parameters,
79  const ndn::mgmt::CommandContinuation& done)
80 {
81  FaceUri remoteUri;
82  if (!remoteUri.parse(parameters.getUri())) {
83  NFD_LOG_TRACE("failed to parse remote URI: " << parameters.getUri());
84  done(ControlResponse(400, "Malformed command"));
85  return;
86  }
87 
88  if (!remoteUri.isCanonical()) {
89  NFD_LOG_TRACE("received non-canonical remote URI: " << remoteUri.toString());
90  done(ControlResponse(400, "Non-canonical remote URI"));
91  return;
92  }
93 
94  ndn::optional<FaceUri> localUri;
95  if (parameters.hasLocalUri()) {
96  localUri = FaceUri{};
97 
98  if (!localUri->parse(parameters.getLocalUri())) {
99  NFD_LOG_TRACE("failed to parse local URI: " << parameters.getLocalUri());
100  done(ControlResponse(400, "Malformed command"));
101  return;
102  }
103 
104  if (!localUri->isCanonical()) {
105  NFD_LOG_TRACE("received non-canonical local URI: " << localUri->toString());
106  done(ControlResponse(400, "Non-canonical local URI"));
107  return;
108  }
109  }
110 
111  face::ProtocolFactory* factory = m_faceSystem.getFactoryByScheme(remoteUri.getScheme());
112  if (factory == nullptr) {
113  NFD_LOG_TRACE("received create request for unsupported protocol: " << remoteUri.getScheme());
114  done(ControlResponse(406, "Unsupported protocol"));
115  return;
116  }
117 
118  try {
119  factory->createFace({remoteUri, localUri, parameters.getFacePersistency(),
120  parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
121  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED),
122  parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED) &&
123  parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)},
124  bind(&FaceManager::afterCreateFaceSuccess, this, parameters, _1, done),
125  bind(&FaceManager::afterCreateFaceFailure, this, _1, _2, done));
126  }
127  catch (const std::runtime_error& error) {
128  NFD_LOG_ERROR("Face creation failed: " << error.what());
129  done(ControlResponse(500, "Face creation failed due to internal error"));
130  return;
131  }
132  catch (const std::logic_error& error) {
133  NFD_LOG_ERROR("Face creation failed: " << error.what());
134  done(ControlResponse(500, "Face creation failed due to internal error"));
135  return;
136  }
137 }
138 
139 void
140 FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
141  const shared_ptr<Face>& face,
142  const ndn::mgmt::CommandContinuation& done)
143 {
144  if (face->getId() != face::INVALID_FACEID) {// Face already exists
145  NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
146 
147  ControlParameters response = collectFaceProperties(*face, true);
148  done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
149  return;
150  }
151 
152  // If scope non-local and flags set to enable local fields, request shouldn't
153  // have made it this far
154  BOOST_ASSERT(face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL ||
155  !parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ||
156  (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
157  !parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)));
158 
159  m_faceTable.add(face);
160 
161  ControlParameters response = collectFaceProperties(*face, true);
162  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
163 }
164 
165 void
166 FaceManager::afterCreateFaceFailure(uint32_t status,
167  const std::string& reason,
168  const ndn::mgmt::CommandContinuation& done)
169 {
170  NFD_LOG_DEBUG("Face creation failed: " << reason);
171 
172  done(ControlResponse(status, reason));
173 }
174 
175 void
176 FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
177  const ControlParameters& parameters,
178  const ndn::mgmt::CommandContinuation& done)
179 {
180  FaceId faceId = parameters.getFaceId();
181  if (faceId == 0) {
182  // Self-updating
183  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
184  if (incomingFaceIdTag == nullptr) {
185  NFD_LOG_TRACE("unable to determine face for self-update");
186  done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
187  return;
188  }
189  faceId = *incomingFaceIdTag;
190  }
191 
192  Face* face = m_faceTable.get(faceId);
193 
194  if (face == nullptr) {
195  NFD_LOG_TRACE("invalid face specified");
196  done(ControlResponse(404, "Specified face does not exist"));
197  return;
198  }
199 
200  // Verify validity of requested changes
201  ControlParameters response;
202  bool areParamsValid = true;
203 
204  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
205  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
206  face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
207  NFD_LOG_TRACE("received request to enable local fields on non-local face");
208  areParamsValid = false;
209  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
210  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
211  }
212 
213  // check whether the requested FacePersistency change is valid if it's present
214  if (parameters.hasFacePersistency()) {
215  auto persistency = parameters.getFacePersistency();
216  if (!face->getTransport()->canChangePersistencyTo(persistency)) {
217  NFD_LOG_TRACE("cannot change face persistency to " << persistency);
218  areParamsValid = false;
219  response.setFacePersistency(persistency);
220  }
221  }
222 
223  if (!areParamsValid) {
224  done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
225  return;
226  }
227 
228  // All specified properties are valid, so make changes
229  if (parameters.hasFacePersistency()) {
230  face->setPersistency(parameters.getFacePersistency());
231  }
232  setLinkServiceOptions(*face, parameters);
233 
234  // Set ControlResponse fields
235  response = collectFaceProperties(*face, false);
236 
237  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
238 }
239 
240 void
241 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
242  const ControlParameters& parameters,
243  const ndn::mgmt::CommandContinuation& done)
244 {
245  Face* face = m_faceTable.get(parameters.getFaceId());
246  if (face != nullptr) {
247  face->close();
248  }
249 
250  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
251 }
252 
253 void
254 FaceManager::setLinkServiceOptions(Face& face,
255  const ControlParameters& parameters)
256 {
257  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
258  BOOST_ASSERT(linkService != nullptr);
259 
260  auto options = linkService->getOptions();
261  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
262  face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
263  options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
264  }
265  if (parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
266  options.reliabilityOptions.isEnabled = parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
267  }
268  linkService->setOptions(options);
269 }
270 
271 ControlParameters
272 FaceManager::collectFaceProperties(const Face& face, bool wantUris)
273 {
274  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
275  BOOST_ASSERT(linkService != nullptr);
276  auto options = linkService->getOptions();
277 
278  ControlParameters params;
279  params.setFaceId(face.getId())
280  .setFacePersistency(face.getPersistency())
281  .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false)
282  .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled, false);
283  if (wantUris) {
284  params.setUri(face.getRemoteUri().toString())
285  .setLocalUri(face.getLocalUri().toString());
286  }
287  return params;
288 }
289 
290 void
291 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
292  ndn::mgmt::StatusDatasetContext& context)
293 {
294  auto now = time::steady_clock::now();
295  for (const Face& face : m_faceTable) {
296  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
297  context.append(status.wireEncode());
298  }
299  context.end();
300 }
301 
302 void
303 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
304  ndn::mgmt::StatusDatasetContext& context)
305 {
306  std::set<const face::ProtocolFactory*> factories = m_faceSystem.listProtocolFactories();
307  for (const auto* factory : factories) {
308  for (const auto& channel : factory->getChannels()) {
309  ndn::nfd::ChannelStatus entry;
310  entry.setLocalUri(channel->getUri().toString());
311  context.append(entry.wireEncode());
312  }
313  }
314  context.end();
315 }
316 
317 void
318 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
319  ndn::mgmt::StatusDatasetContext& context)
320 {
321  ndn::nfd::FaceQueryFilter faceFilter;
322  const Name& query = interest.getName();
323  try {
324  faceFilter.wireDecode(query[-1].blockFromValue());
325  }
326  catch (const tlv::Error& e) {
327  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
328  return context.reject(ControlResponse(400, "Malformed filter"));
329  }
330 
331  auto now = time::steady_clock::now();
332  for (const Face& face : m_faceTable) {
333  if (!matchFilter(faceFilter, face)) {
334  continue;
335  }
336  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
337  context.append(status.wireEncode());
338  }
339 
340  context.end();
341 }
342 
343 bool
344 FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
345 {
346  if (filter.hasFaceId() &&
347  filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
348  return false;
349  }
350 
351  if (filter.hasUriScheme() &&
352  filter.getUriScheme() != face.getRemoteUri().getScheme() &&
353  filter.getUriScheme() != face.getLocalUri().getScheme()) {
354  return false;
355  }
356 
357  if (filter.hasRemoteUri() &&
358  filter.getRemoteUri() != face.getRemoteUri().toString()) {
359  return false;
360  }
361 
362  if (filter.hasLocalUri() &&
363  filter.getLocalUri() != face.getLocalUri().toString()) {
364  return false;
365  }
366 
367  if (filter.hasFaceScope() &&
368  filter.getFaceScope() != face.getScope()) {
369  return false;
370  }
371 
372  if (filter.hasFacePersistency() &&
373  filter.getFacePersistency() != face.getPersistency()) {
374  return false;
375  }
376 
377  if (filter.hasLinkType() &&
378  filter.getLinkType() != face.getLinkType()) {
379  return false;
380  }
381 
382  return true;
383 }
384 
385 ndn::nfd::FaceStatus
386 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
387 {
388  ndn::nfd::FaceStatus status;
389 
390  collectFaceProperties(face, status);
391 
392  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
393  if (expirationTime != time::steady_clock::TimePoint::max()) {
394  status.setExpirationPeriod(std::max(time::milliseconds(0),
395  time::duration_cast<time::milliseconds>(expirationTime - now)));
396  }
397 
398  const face::FaceCounters& counters = face.getCounters();
399  status.setNInInterests(counters.nInInterests)
400  .setNOutInterests(counters.nOutInterests)
401  .setNInData(counters.nInData)
402  .setNOutData(counters.nOutData)
403  .setNInNacks(counters.nInNacks)
404  .setNOutNacks(counters.nOutNacks)
405  .setNInBytes(counters.nInBytes)
406  .setNOutBytes(counters.nOutBytes);
407 
408  return status;
409 }
410 
411 template<typename FaceTraits>
412 void
413 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
414 {
415  traits.setFaceId(face.getId())
416  .setRemoteUri(face.getRemoteUri().toString())
417  .setLocalUri(face.getLocalUri().toString())
418  .setFaceScope(face.getScope())
419  .setFacePersistency(face.getPersistency())
420  .setLinkType(face.getLinkType());
421 
422  // Set Flag bits
423  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
424  if (linkService != nullptr) {
425  auto linkServiceOptions = linkService->getOptions();
426  traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
427  traits.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED,
428  linkServiceOptions.reliabilityOptions.isEnabled);
429  }
430 }
431 
432 void
433 FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
434 {
435  ndn::nfd::FaceEventNotification notification;
436  notification.setKind(kind);
437  collectFaceProperties(face, notification);
438 
439  m_postNotification(notification.wireEncode());
440 }
441 
442 void
443 FaceManager::connectFaceStateChangeSignal(const Face& face)
444 {
445  FaceId faceId = face.getId();
446  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
447  [this, faceId] (face::FaceState oldState, face::FaceState newState) {
448  const Face& face = *m_faceTable.get(faceId);
449 
450  if (newState == face::FaceState::UP) {
451  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
452  }
453  else if (newState == face::FaceState::DOWN) {
454  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
455  }
456  else if (newState == face::FaceState::CLOSED) {
457  m_faceStateChangeConn.erase(faceId);
458  }
459  });
460 }
461 
462 } // namespace nfd
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
const PacketCounter & nOutInterests
configuration file parsing utility
Definition: config-file.hpp:58
TransportState
indicates the state of a transport
Definition: transport.hpp:41
const PacketCounter & nOutData
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:44
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:164
FaceManager(FaceSystem &faceSystem, Dispatcher &dispatcher, CommandAuthenticator &authenticator)
provides ControlCommand authorization according to NFD configuration file
const ByteCounter & nInBytes
void add(shared_ptr< Face > face)
add a face
Definition: face-table.cpp:57
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:90
the transport is closed, and can be safely deallocated
ndn::mgmt::PostNotification registerNotificationStream(const std::string &verb)
a collection of common functions shared by all NFD managers, such as communicating with the dispatche...
signal::Signal< FaceTable, Face & > afterAdd
fires after a face is added
Definition: face-table.hpp:84
const PacketCounter & nOutNacks
gives access to counters provided by Face
const PacketCounter & nInInterests
void setConfigFile(ConfigFile &configFile)
Subscribe to face_system section for the config file.
const ByteCounter & nOutBytes
Provides support for an underlying protocol.
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
the transport is up and can transmit packets
uint64_t FaceId
identifies a face
Definition: face.hpp:39
virtual void createFace(const CreateFaceParams &params, const FaceCreatedCallback &onCreated, const FaceCreationFailedCallback &onFailure)=0
Try to create face using the supplied parameters.
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
const PacketCounter & nInData
const PacketCounter & nInNacks
the transport is temporarily down, and is being recovered