face-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
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(FaceTable& faceTable, Dispatcher& dispatcher, CommandAuthenticator& authenticator)
39  : NfdManagerBase(dispatcher, authenticator, "faces")
40  , m_faceSystem(faceTable)
41  , m_faceTable(faceTable)
42 {
43  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
44  bind(&FaceManager::createFace, this, _2, _3, _4, _5));
45 
46  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
47  bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
48 
49  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
50  bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
51 
52  registerCommandHandler<ndn::nfd::FaceEnableLocalControlCommand>("enable-local-control",
53  bind(&FaceManager::enableLocalControl, this, _2, _3, _4, _5));
54 
55  registerCommandHandler<ndn::nfd::FaceDisableLocalControlCommand>("disable-local-control",
56  bind(&FaceManager::disableLocalControl, this, _2, _3, _4, _5));
57 
58  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
59  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
60  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
61 
62  m_postNotification = registerNotificationStream("events");
63  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
64  connectFaceStateChangeSignal(face);
65  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
66  });
67  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
68  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
69  });
70 }
71 
72 void
74 {
75  m_faceSystem.setConfigFile(configFile);
76 }
77 
78 void
79 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
80  const ControlParameters& parameters,
81  const ndn::mgmt::CommandContinuation& done)
82 {
83  FaceUri uri;
84  if (!uri.parse(parameters.getUri())) {
85  NFD_LOG_TRACE("failed to parse URI");
86  done(ControlResponse(400, "Malformed command"));
87  return;
88  }
89 
90  if (!uri.isCanonical()) {
91  NFD_LOG_TRACE("received non-canonical URI");
92  done(ControlResponse(400, "Non-canonical URI"));
93  return;
94  }
95 
96  ProtocolFactory* factory = m_faceSystem.getFactoryByScheme(uri.getScheme());
97  if (factory == nullptr) {
98  NFD_LOG_TRACE("received create request for unsupported protocol");
99  done(ControlResponse(406, "Unsupported protocol"));
100  return;
101  }
102 
103  try {
104  factory->createFace(uri,
105  parameters.getFacePersistency(),
106  parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
107  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED),
108  bind(&FaceManager::afterCreateFaceSuccess, this, parameters, _1, done),
109  bind(&FaceManager::afterCreateFaceFailure, this, _1, _2, done));
110  }
111  catch (const std::runtime_error& error) {
112  NFD_LOG_ERROR("Face creation failed: " << error.what());
113  done(ControlResponse(500, "Face creation failed due to internal error"));
114  return;
115  }
116  catch (const std::logic_error& error) {
117  NFD_LOG_ERROR("Face creation failed: " << error.what());
118  done(ControlResponse(500, "Face creation failed due to internal error"));
119  return;
120  }
121 }
122 
129 void
130 FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
131  const shared_ptr<Face>& face,
132  const ndn::mgmt::CommandContinuation& done)
133 {
134  // TODO: Re-enable check in #3232
135  //if (face->getId() != face::INVALID_FACEID) {
137  //ControlParameters response;
138  //response.setFaceId(face->getId());
139  //response.setUri(face->getRemoteUri().toString());
140  //response.setFacePersistency(face->getPersistency());
141  //
142  //auto linkService = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
143  //BOOST_ASSERT(linkService != nullptr);
144  //auto options = linkService->getOptions();
145  //response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
146  //
147  // NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
148  // done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
149  //}
150  //else {
151  // If scope non-local and flags set to enable local fields, request shouldn't
152  // have made it this far
153  BOOST_ASSERT(face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL ||
154  !parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ||
155  (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
156  !parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)));
157 
158  m_faceTable.add(face);
159 
160  ControlParameters response;
161  response.setFaceId(face->getId());
162  response.setFacePersistency(face->getPersistency());
163  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
164  parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ?
165  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) : false,
166  false);
167 
168  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
169  //}
170 }
171 
172 void
173 FaceManager::afterCreateFaceFailure(uint32_t status,
174  const std::string& reason,
175  const ndn::mgmt::CommandContinuation& done)
176 {
177  NFD_LOG_DEBUG("Face creation failed: " << reason);
178 
179  done(ControlResponse(status, reason));
180 }
181 
182 void
183 FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
184  const ControlParameters& parameters,
185  const ndn::mgmt::CommandContinuation& done)
186 {
187  FaceId faceId = parameters.getFaceId();
188  if (faceId == 0) {
189  // Self-updating
190  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
191  if (incomingFaceIdTag == nullptr) {
192  NFD_LOG_TRACE("unable to determine face for self-update");
193  done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
194  return;
195  }
196  faceId = *incomingFaceIdTag;
197  }
198 
199  Face* face = m_faceTable.get(faceId);
200 
201  if (face == nullptr) {
202  NFD_LOG_TRACE("invalid face specified");
203  done(ControlResponse(404, "Specified face does not exist"));
204  return;
205  }
206 
207  // Verify validity of requested changes
208  ControlParameters response;
209  bool areParamsValid = true;
210 
211  if (parameters.hasFacePersistency()) {
212  // TODO #3232: Add FacePersistency updating
213  NFD_LOG_TRACE("received unsupported face persistency change");
214  areParamsValid = false;
215  response.setFacePersistency(parameters.getFacePersistency());
216  }
217 
218  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
219  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
220  face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
221  NFD_LOG_TRACE("received request to enable local fields on non-local face");
222  areParamsValid = false;
223  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
224  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
225  }
226 
227  if (!areParamsValid) {
228  done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
229  return;
230  }
231 
232  // All specified properties are valid, so make changes
233 
234  // TODO #3232: Add FacePersistency updating
235 
236  setLinkServiceOptions(*face, parameters, response);
237 
238  // Set ControlResponse fields
239  response.setFaceId(faceId);
240  response.setFacePersistency(face->getPersistency());
241  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
242  parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ?
243  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) : false,
244  false);
245 
246  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
247 }
248 
249 void
250 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
251  const ControlParameters& parameters,
252  const ndn::mgmt::CommandContinuation& done)
253 {
254  Face* face = m_faceTable.get(parameters.getFaceId());
255  if (face != nullptr) {
256  face->close();
257  }
258 
259  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
260 }
261 
262 void
263 FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
264  const ControlParameters& parameters,
265  const ndn::mgmt::CommandContinuation& done)
266 {
267  Face* face = findFaceForLocalControl(interest, parameters, done);
268  if (!face) {
269  return;
270  }
271 
272  // enable-local-control will enable all local fields in GenericLinkService
273  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
274  if (service == nullptr) {
275  return done(ControlResponse(503, "LinkService type not supported"));
276  }
277 
278  face::GenericLinkService::Options options = service->getOptions();
279  options.allowLocalFields = true;
280  service->setOptions(options);
281 
282  return done(ControlResponse(200, "OK: enable all local fields on GenericLinkService")
283  .setBody(parameters.wireEncode()));
284 }
285 
286 void
287 FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
288  const ControlParameters& parameters,
289  const ndn::mgmt::CommandContinuation& done)
290 {
291  Face* face = findFaceForLocalControl(interest, parameters, done);
292  if (!face) {
293  return;
294  }
295 
296  // disable-local-control will disable all local fields in GenericLinkService
297  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
298  if (service == nullptr) {
299  return done(ControlResponse(503, "LinkService type not supported"));
300  }
301 
302  face::GenericLinkService::Options options = service->getOptions();
303  options.allowLocalFields = false;
304  service->setOptions(options);
305 
306  return done(ControlResponse(200, "OK: disable all local fields on GenericLinkService")
307  .setBody(parameters.wireEncode()));
308 }
309 
310 Face*
311 FaceManager::findFaceForLocalControl(const Interest& request,
312  const ControlParameters& parameters,
313  const ndn::mgmt::CommandContinuation& done)
314 {
315  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
316  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
317  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
318  // and is initialized synchronously with IncomingFaceId field enabled.
319  BOOST_ASSERT(incomingFaceIdTag != nullptr);
320 
321  Face* face = m_faceTable.get(*incomingFaceIdTag);
322  if (face == nullptr) {
323  NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
324  done(ControlResponse(410, "Face not found"));
325  return nullptr;
326  }
327 
328  if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
329  NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
330  done(ControlResponse(412, "Face is non-local"));
331  return nullptr;
332  }
333 
334  return face;
335 }
336 
337 void
338 FaceManager::setLinkServiceOptions(Face& face,
339  const ControlParameters& parameters,
340  ControlParameters& response)
341 {
342  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
343  BOOST_ASSERT(linkService != nullptr);
344 
345  auto options = linkService->getOptions();
346  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
347  face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
348  options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
349  }
350  linkService->setOptions(options);
351 
352  // Set Flags for ControlResponse
353  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
354 }
355 
356 void
357 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
358  ndn::mgmt::StatusDatasetContext& context)
359 {
360  auto now = time::steady_clock::now();
361  for (const Face& face : m_faceTable) {
362  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
363  context.append(status.wireEncode());
364  }
365  context.end();
366 }
367 
368 void
369 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
370  ndn::mgmt::StatusDatasetContext& context)
371 {
372  std::set<const ProtocolFactory*> factories = m_faceSystem.listProtocolFactories();
373  for (const ProtocolFactory* factory : factories) {
374  for (const auto& channel : factory->getChannels()) {
375  ndn::nfd::ChannelStatus entry;
376  entry.setLocalUri(channel->getUri().toString());
377  context.append(entry.wireEncode());
378  }
379  }
380  context.end();
381 }
382 
383 void
384 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
385  ndn::mgmt::StatusDatasetContext& context)
386 {
387  ndn::nfd::FaceQueryFilter faceFilter;
388  const Name& query = interest.getName();
389  try {
390  faceFilter.wireDecode(query[-1].blockFromValue());
391  }
392  catch (const tlv::Error& e) {
393  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
394  return context.reject(ControlResponse(400, "Malformed filter"));
395  }
396 
397  auto now = time::steady_clock::now();
398  for (const Face& face : m_faceTable) {
399  if (!matchFilter(faceFilter, face)) {
400  continue;
401  }
402  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
403  context.append(status.wireEncode());
404  }
405 
406  context.end();
407 }
408 
409 bool
410 FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
411 {
412  if (filter.hasFaceId() &&
413  filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
414  return false;
415  }
416 
417  if (filter.hasUriScheme() &&
418  filter.getUriScheme() != face.getRemoteUri().getScheme() &&
419  filter.getUriScheme() != face.getLocalUri().getScheme()) {
420  return false;
421  }
422 
423  if (filter.hasRemoteUri() &&
424  filter.getRemoteUri() != face.getRemoteUri().toString()) {
425  return false;
426  }
427 
428  if (filter.hasLocalUri() &&
429  filter.getLocalUri() != face.getLocalUri().toString()) {
430  return false;
431  }
432 
433  if (filter.hasFaceScope() &&
434  filter.getFaceScope() != face.getScope()) {
435  return false;
436  }
437 
438  if (filter.hasFacePersistency() &&
439  filter.getFacePersistency() != face.getPersistency()) {
440  return false;
441  }
442 
443  if (filter.hasLinkType() &&
444  filter.getLinkType() != face.getLinkType()) {
445  return false;
446  }
447 
448  return true;
449 }
450 
451 ndn::nfd::FaceStatus
452 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
453 {
454  ndn::nfd::FaceStatus status;
455 
456  collectFaceProperties(face, status);
457 
458  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
459  if (expirationTime != time::steady_clock::TimePoint::max()) {
460  status.setExpirationPeriod(std::max(time::milliseconds(0),
461  time::duration_cast<time::milliseconds>(expirationTime - now)));
462  }
463 
464  const face::FaceCounters& counters = face.getCounters();
465  status.setNInInterests(counters.nInInterests)
466  .setNOutInterests(counters.nOutInterests)
467  .setNInDatas(counters.nInData)
468  .setNOutDatas(counters.nOutData)
469  .setNInNacks(counters.nInNacks)
470  .setNOutNacks(counters.nOutNacks)
471  .setNInBytes(counters.nInBytes)
472  .setNOutBytes(counters.nOutBytes);
473 
474  return status;
475 }
476 
477 template<typename FaceTraits>
478 void
479 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
480 {
481  traits.setFaceId(face.getId())
482  .setRemoteUri(face.getRemoteUri().toString())
483  .setLocalUri(face.getLocalUri().toString())
484  .setFaceScope(face.getScope())
485  .setFacePersistency(face.getPersistency())
486  .setLinkType(face.getLinkType());
487 
488  // Set Flag bits
489  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
490  if (linkService != nullptr) {
491  auto linkServiceOptions = linkService->getOptions();
492  traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
493  }
494 }
495 
496 void
497 FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
498 {
499  ndn::nfd::FaceEventNotification notification;
500  notification.setKind(kind);
501  collectFaceProperties(face, notification);
502 
503  m_postNotification(notification.wireEncode());
504 }
505 
506 void
507 FaceManager::connectFaceStateChangeSignal(const Face& face)
508 {
509  FaceId faceId = face.getId();
510  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
511  [this, faceId] (face::FaceState oldState, face::FaceState newState) {
512  const Face& face = *m_faceTable.get(faceId);
513 
514  if (newState == face::FaceState::UP) {
515  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
516  }
517  else if (newState == face::FaceState::DOWN) {
518  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
519  }
520  else if (newState == face::FaceState::CLOSED) {
521  m_faceStateChangeConn.erase(faceId);
522  }
523  });
524 }
525 
526 } // namespace nfd
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
configuration file parsing utility
Definition: config-file.hpp:58
container of all faces
Definition: face-table.hpp:37
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:45
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:164
provides ControlCommand authorization according to NFD configuration file
void add(shared_ptr< Face > face)
add a face
Definition: face-table.cpp:61
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
TransportState FaceState
indicates the state of a face
Definition: face.hpp:54
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:91
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:85
void setConfigFile(ConfigFile &configFile)
Subscribe to face_system section for the config file.
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
the transport is up
uint64_t FaceId
identifies a face
Definition: face.hpp:39
FaceManager(FaceTable &faceTable, Dispatcher &dispatcher, CommandAuthenticator &authenticator)
the transport is down temporarily, and is being recovered