NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
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"
30 
32 
33 #ifdef HAVE_TCP
34 #include "face/tcp-factory.hpp"
35 #endif // HAVE_TCP
36 
37 #ifdef HAVE_UDP
38 #include "face/udp-factory.hpp"
39 #endif // HAVE_UDP
40 
41 #include "fw/face-table.hpp"
42 
43 #include <ndn-cxx/lp/tags.hpp>
44 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
45 
46 #ifdef HAVE_UNIX_SOCKETS
48 #endif // HAVE_UNIX_SOCKETS
49 
50 #ifdef HAVE_LIBPCAP
53 #endif // HAVE_LIBPCAP
54 
55 #ifdef HAVE_WEBSOCKET
57 #endif // HAVE_WEBSOCKET
58 
59 namespace nfd {
60 
61 NFD_LOG_INIT("FaceManager");
62 
63 FaceManager::FaceManager(FaceTable& faceTable, Dispatcher& dispatcher, CommandAuthenticator& authenticator)
64  : NfdManagerBase(dispatcher, authenticator, "faces")
65  , m_faceTable(faceTable)
66 {
67  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
68  bind(&FaceManager::createFace, this, _2, _3, _4, _5));
69 
70  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
71  bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
72 
73  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
74  bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
75 
76  registerCommandHandler<ndn::nfd::FaceEnableLocalControlCommand>("enable-local-control",
77  bind(&FaceManager::enableLocalControl, this, _2, _3, _4, _5));
78 
79  registerCommandHandler<ndn::nfd::FaceDisableLocalControlCommand>("disable-local-control",
80  bind(&FaceManager::disableLocalControl, this, _2, _3, _4, _5));
81 
82  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
83  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
84  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
85 
86  m_postNotification = registerNotificationStream("events");
87  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
88  connectFaceStateChangeSignal(face);
89  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
90  });
91  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
92  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
93  });
94 }
95 
96 void
98 {
99  configFile.addSectionHandler("face_system", bind(&FaceManager::processConfig, this, _1, _2, _3));
100 }
101 
102 void
103 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
104  const ControlParameters& parameters,
105  const ndn::mgmt::CommandContinuation& done)
106 {
107  FaceUri uri;
108  if (!uri.parse(parameters.getUri())) {
109  NFD_LOG_TRACE("failed to parse URI");
110  done(ControlResponse(400, "Malformed command"));
111  return;
112  }
113 
114  if (!uri.isCanonical()) {
115  NFD_LOG_TRACE("received non-canonical URI");
116  done(ControlResponse(400, "Non-canonical URI"));
117  return;
118  }
119 
120  auto factory = m_factories.find(uri.getScheme());
121  if (factory == m_factories.end()) {
122  NFD_LOG_TRACE("received create request for unsupported protocol");
123  done(ControlResponse(406, "Unsupported protocol"));
124  return;
125  }
126 
127  try {
128  factory->second->createFace(uri,
129  parameters.getFacePersistency(),
132  bind(&FaceManager::afterCreateFaceSuccess,
133  this, parameters, _1, done),
134  bind(&FaceManager::afterCreateFaceFailure,
135  this, _1, _2, done));
136  }
137  catch (const std::runtime_error& error) {
138  NFD_LOG_ERROR("Face creation failed: " << error.what());
139  done(ControlResponse(500, "Face creation failed due to internal error"));
140  return;
141  }
142  catch (const std::logic_error& error) {
143  NFD_LOG_ERROR("Face creation failed: " << error.what());
144  done(ControlResponse(500, "Face creation failed due to internal error"));
145  return;
146  }
147 }
148 
155 void
156 FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
157  const shared_ptr<Face>& face,
158  const ndn::mgmt::CommandContinuation& done)
159 {
160  // TODO: Re-enable check in #3232
161  //if (face->getId() != face::INVALID_FACEID) {
163  //ControlParameters response;
164  //response.setFaceId(face->getId());
165  //response.setUri(face->getRemoteUri().toString());
166  //response.setFacePersistency(face->getPersistency());
167  //
168  //auto linkService = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
169  //BOOST_ASSERT(linkService != nullptr);
170  //auto options = linkService->getOptions();
171  //response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
172  //
173  // NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
174  // done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
175  //}
176  //else {
177  // If scope non-local and flags set to enable local fields, request shouldn't
178  // have made it this far
179  BOOST_ASSERT(face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL ||
183 
184  m_faceTable.add(face);
185 
186  ControlParameters response;
187  response.setFaceId(face->getId());
188  response.setFacePersistency(face->getPersistency());
192  false);
193 
194  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
195  //}
196 }
197 
198 void
199 FaceManager::afterCreateFaceFailure(uint32_t status,
200  const std::string& reason,
201  const ndn::mgmt::CommandContinuation& done)
202 {
203  NFD_LOG_DEBUG("Face creation failed: " << reason);
204 
205  done(ControlResponse(status, reason));
206 }
207 
208 void
209 FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
210  const ControlParameters& parameters,
211  const ndn::mgmt::CommandContinuation& done)
212 {
213  FaceId faceId = parameters.getFaceId();
214  if (faceId == 0) {
215  // Self-updating
216  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
217  if (incomingFaceIdTag == nullptr) {
218  NFD_LOG_TRACE("unable to determine face for self-update");
219  done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
220  return;
221  }
222  faceId = *incomingFaceIdTag;
223  }
224 
225  Face* face = m_faceTable.get(faceId);
226 
227  if (face == nullptr) {
228  NFD_LOG_TRACE("invalid face specified");
229  done(ControlResponse(404, "Specified face does not exist"));
230  return;
231  }
232 
233  // Verify validity of requested changes
234  ControlParameters response;
235  bool areParamsValid = true;
236 
237  if (parameters.hasFacePersistency()) {
238  // TODO #3232: Add FacePersistency updating
239  NFD_LOG_TRACE("received unsupported face persistency change");
240  areParamsValid = false;
241  response.setFacePersistency(parameters.getFacePersistency());
242  }
243 
247  NFD_LOG_TRACE("received request to enable local fields on non-local face");
248  areParamsValid = false;
251  }
252 
253  if (!areParamsValid) {
254  done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
255  return;
256  }
257 
258  // All specified properties are valid, so make changes
259 
260  // TODO #3232: Add FacePersistency updating
261 
262  setLinkServiceOptions(*face, parameters, response);
263 
264  // Set ControlResponse fields
265  response.setFaceId(faceId);
266  response.setFacePersistency(face->getPersistency());
270  false);
271 
272  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
273 }
274 
275 void
276 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
277  const ControlParameters& parameters,
278  const ndn::mgmt::CommandContinuation& done)
279 {
280  Face* face = m_faceTable.get(parameters.getFaceId());
281  if (face != nullptr) {
282  face->close();
283  }
284 
285  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
286 }
287 
288 void
289 FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
290  const ControlParameters& parameters,
291  const ndn::mgmt::CommandContinuation& done)
292 {
293  Face* face = findFaceForLocalControl(interest, parameters, done);
294  if (!face) {
295  return;
296  }
297 
298  // enable-local-control will enable all local fields in GenericLinkService
299  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
300  if (service == nullptr) {
301  return done(ControlResponse(503, "LinkService type not supported"));
302  }
303 
304  face::GenericLinkService::Options options = service->getOptions();
305  options.allowLocalFields = true;
306  service->setOptions(options);
307 
308  return done(ControlResponse(200, "OK: enable all local fields on GenericLinkService")
309  .setBody(parameters.wireEncode()));
310 }
311 
312 void
313 FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
314  const ControlParameters& parameters,
315  const ndn::mgmt::CommandContinuation& done)
316 {
317  Face* face = findFaceForLocalControl(interest, parameters, done);
318  if (!face) {
319  return;
320  }
321 
322  // disable-local-control will disable all local fields in GenericLinkService
323  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
324  if (service == nullptr) {
325  return done(ControlResponse(503, "LinkService type not supported"));
326  }
327 
328  face::GenericLinkService::Options options = service->getOptions();
329  options.allowLocalFields = false;
330  service->setOptions(options);
331 
332  return done(ControlResponse(200, "OK: disable all local fields on GenericLinkService")
333  .setBody(parameters.wireEncode()));
334 }
335 
336 Face*
337 FaceManager::findFaceForLocalControl(const Interest& request,
338  const ControlParameters& parameters,
339  const ndn::mgmt::CommandContinuation& done)
340 {
341  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
342  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
343  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
344  // and is initialized synchronously with IncomingFaceId field enabled.
345  BOOST_ASSERT(incomingFaceIdTag != nullptr);
346 
347  Face* face = m_faceTable.get(*incomingFaceIdTag);
348  if (face == nullptr) {
349  NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
350  done(ControlResponse(410, "Face not found"));
351  return nullptr;
352  }
353 
354  if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
355  NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
356  done(ControlResponse(412, "Face is non-local"));
357  return nullptr;
358  }
359 
360  return face;
361 }
362 
363 void
364 FaceManager::setLinkServiceOptions(Face& face,
365  const ControlParameters& parameters,
366  ControlParameters& response)
367 {
368  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
369  BOOST_ASSERT(linkService != nullptr);
370 
371  auto options = linkService->getOptions();
374  options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
375  }
376  linkService->setOptions(options);
377 
378  // Set Flags for ControlResponse
379  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
380 }
381 
382 void
383 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
385 {
386  auto now = time::steady_clock::now();
387  for (const Face& face : m_faceTable) {
388  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
389  context.append(status.wireEncode());
390  }
391  context.end();
392 }
393 
394 void
395 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
397 {
398  std::set<const ProtocolFactory*> seenFactories;
399 
400  for (const auto& kv : m_factories) {
401  const ProtocolFactory* factory = kv.second.get();
402  bool inserted;
403  std::tie(std::ignore, inserted) = seenFactories.insert(factory);
404 
405  if (inserted) {
406  for (const auto& channel : factory->getChannels()) {
408  entry.setLocalUri(channel->getUri().toString());
409  context.append(entry.wireEncode());
410  }
411  }
412  }
413 
414  context.end();
415 }
416 
417 void
418 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
420 {
421  ndn::nfd::FaceQueryFilter faceFilter;
422  const Name& query = interest.getName();
423  try {
424  faceFilter.wireDecode(query[-1].blockFromValue());
425  }
426  catch (const tlv::Error& e) {
427  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
428  return context.reject(ControlResponse(400, "Malformed filter"));
429  }
430 
431  auto now = time::steady_clock::now();
432  for (const Face& face : m_faceTable) {
433  if (!matchFilter(faceFilter, face)) {
434  continue;
435  }
436  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
437  context.append(status.wireEncode());
438  }
439 
440  context.end();
441 }
442 
443 bool
444 FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
445 {
446  if (filter.hasFaceId() &&
447  filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
448  return false;
449  }
450 
451  if (filter.hasUriScheme() &&
452  filter.getUriScheme() != face.getRemoteUri().getScheme() &&
453  filter.getUriScheme() != face.getLocalUri().getScheme()) {
454  return false;
455  }
456 
457  if (filter.hasRemoteUri() &&
458  filter.getRemoteUri() != face.getRemoteUri().toString()) {
459  return false;
460  }
461 
462  if (filter.hasLocalUri() &&
463  filter.getLocalUri() != face.getLocalUri().toString()) {
464  return false;
465  }
466 
467  if (filter.hasFaceScope() &&
468  filter.getFaceScope() != face.getScope()) {
469  return false;
470  }
471 
472  if (filter.hasFacePersistency() &&
473  filter.getFacePersistency() != face.getPersistency()) {
474  return false;
475  }
476 
477  if (filter.hasLinkType() &&
478  filter.getLinkType() != face.getLinkType()) {
479  return false;
480  }
481 
482  return true;
483 }
484 
486 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
487 {
488  ndn::nfd::FaceStatus status;
489 
490  collectFaceProperties(face, status);
491 
492  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
493  if (expirationTime != time::steady_clock::TimePoint::max()) {
494  status.setExpirationPeriod(std::max(time::milliseconds(0),
495  time::duration_cast<time::milliseconds>(expirationTime - now)));
496  }
497 
498  const face::FaceCounters& counters = face.getCounters();
499  status.setNInInterests(counters.nInInterests)
501  .setNInDatas(counters.nInData)
502  .setNOutDatas(counters.nOutData)
503  .setNInNacks(counters.nInNacks)
504  .setNOutNacks(counters.nOutNacks)
505  .setNInBytes(counters.nInBytes)
506  .setNOutBytes(counters.nOutBytes);
507 
508  return status;
509 }
510 
511 template<typename FaceTraits>
512 void
513 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
514 {
515  traits.setFaceId(face.getId())
516  .setRemoteUri(face.getRemoteUri().toString())
517  .setLocalUri(face.getLocalUri().toString())
518  .setFaceScope(face.getScope())
519  .setFacePersistency(face.getPersistency())
520  .setLinkType(face.getLinkType());
521 
522  // Set Flag bits
523  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
524  if (linkService != nullptr) {
525  auto linkServiceOptions = linkService->getOptions();
526  traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
527  }
528 }
529 
530 void
531 FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
532 {
533  ndn::nfd::FaceEventNotification notification;
534  notification.setKind(kind);
535  collectFaceProperties(face, notification);
536 
537  m_postNotification(notification.wireEncode());
538 }
539 
540 void
541 FaceManager::connectFaceStateChangeSignal(const Face& face)
542 {
543  FaceId faceId = face.getId();
544  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
545  [this, faceId] (face::FaceState oldState, face::FaceState newState) {
546  const Face& face = *m_faceTable.get(faceId);
547 
548  if (newState == face::FaceState::UP) {
549  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
550  }
551  else if (newState == face::FaceState::DOWN) {
552  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
553  }
554  else if (newState == face::FaceState::CLOSED) {
555  m_faceStateChangeConn.erase(faceId);
556  }
557  });
558 }
559 
560 void
561 FaceManager::processConfig(const ConfigSection& configSection,
562  bool isDryRun,
563  const std::string& filename)
564 {
565  bool hasSeenUnix = false;
566  bool hasSeenTcp = false;
567  bool hasSeenUdp = false;
568  bool hasSeenEther = false;
569  bool hasSeenWebSocket = false;
570  auto nicList = listNetworkInterfaces();
571 
572  for (const auto& item : configSection) {
573  if (item.first == "unix") {
574  if (hasSeenUnix) {
575  BOOST_THROW_EXCEPTION(Error("Duplicate \"unix\" section"));
576  }
577  hasSeenUnix = true;
578 
579  processSectionUnix(item.second, isDryRun);
580  }
581  else if (item.first == "tcp") {
582  if (hasSeenTcp) {
583  BOOST_THROW_EXCEPTION(Error("Duplicate \"tcp\" section"));
584  }
585  hasSeenTcp = true;
586 
587  processSectionTcp(item.second, isDryRun);
588  }
589  else if (item.first == "udp") {
590  if (hasSeenUdp) {
591  BOOST_THROW_EXCEPTION(Error("Duplicate \"udp\" section"));
592  }
593  hasSeenUdp = true;
594 
595  processSectionUdp(item.second, isDryRun, nicList);
596  }
597  else if (item.first == "ether") {
598  if (hasSeenEther) {
599  BOOST_THROW_EXCEPTION(Error("Duplicate \"ether\" section"));
600  }
601  hasSeenEther = true;
602 
603  processSectionEther(item.second, isDryRun, nicList);
604  }
605  else if (item.first == "websocket") {
606  if (hasSeenWebSocket) {
607  BOOST_THROW_EXCEPTION(Error("Duplicate \"websocket\" section"));
608  }
609  hasSeenWebSocket = true;
610 
611  processSectionWebSocket(item.second, isDryRun);
612  }
613  else {
614  BOOST_THROW_EXCEPTION(Error("Unrecognized option \"" + item.first + "\""));
615  }
616  }
617 }
618 
619 void
620 FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
621 {
622  // ; the unix section contains settings of Unix stream faces and channels
623  // unix
624  // {
625  // path /var/run/nfd.sock ; Unix stream listener path
626  // }
627 
628 #if defined(HAVE_UNIX_SOCKETS)
629  std::string path = "/var/run/nfd.sock";
630 
631  for (const auto& i : configSection) {
632  if (i.first == "path") {
633  path = i.second.get_value<std::string>();
634  }
635  else {
636  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
637  i.first + "\" in \"unix\" section"));
638  }
639  }
640 
641  if (!isDryRun) {
642  if (m_factories.count("unix") > 0) {
643  return;
644  }
645 
646  auto factory = make_shared<UnixStreamFactory>();
647  m_factories.insert(std::make_pair("unix", factory));
648 
649  auto channel = factory->createChannel(path);
650  channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
651  }
652 #else
653  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without Unix sockets support, "
654  "cannot process \"unix\" section"));
655 #endif // HAVE_UNIX_SOCKETS
656 }
657 
658 void
659 FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
660 {
661  // ; the tcp section contains settings of TCP faces and channels
662  // tcp
663  // {
664  // listen yes ; set to 'no' to disable TCP listener, default 'yes'
665  // port 6363 ; TCP listener port number
666  // }
667 
668 #if defined(HAVE_TCP)
669  uint16_t port = 6363;
670  bool needToListen = true;
671  bool enableV4 = true;
672  bool enableV6 = true;
673 
674  for (const auto& i : configSection) {
675  if (i.first == "port") {
676  port = ConfigFile::parseNumber<uint16_t>(i, "tcp");
677  NFD_LOG_TRACE("TCP port set to " << port);
678  }
679  else if (i.first == "listen") {
680  needToListen = ConfigFile::parseYesNo(i, "tcp");
681  }
682  else if (i.first == "enable_v4") {
683  enableV4 = ConfigFile::parseYesNo(i, "tcp");
684  }
685  else if (i.first == "enable_v6") {
686  enableV6 = ConfigFile::parseYesNo(i, "tcp");
687  }
688  else {
689  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
690  i.first + "\" in \"tcp\" section"));
691  }
692  }
693 
694  if (!enableV4 && !enableV6) {
695  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 TCP channels have been disabled."
696  " Remove \"tcp\" section to disable TCP channels or"
697  " re-enable at least one channel type."));
698  }
699 
700  if (!isDryRun) {
701  if (m_factories.count("tcp") > 0) {
702  return;
703  }
704 
705  auto factory = make_shared<TcpFactory>();
706  m_factories.insert(std::make_pair("tcp", factory));
707 
708  if (enableV4) {
709  tcp::Endpoint endpoint(boost::asio::ip::tcp::v4(), port);
710  shared_ptr<TcpChannel> v4Channel = factory->createChannel(endpoint);
711  if (needToListen) {
712  v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
713  }
714 
715  m_factories.insert(std::make_pair("tcp4", factory));
716  }
717 
718  if (enableV6) {
719  tcp::Endpoint endpoint(boost::asio::ip::tcp::v6(), port);
720  shared_ptr<TcpChannel> v6Channel = factory->createChannel(endpoint);
721  if (needToListen) {
722  v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
723  }
724 
725  m_factories.insert(std::make_pair("tcp6", factory));
726  }
727  }
728 #else
729  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without TCP support, cannot process \"tcp\" section"));
730 #endif // HAVE_TCP
731 }
732 
733 void
734 FaceManager::processSectionUdp(const ConfigSection& configSection, bool isDryRun,
735  const std::vector<NetworkInterfaceInfo>& nicList)
736 {
737  // ; the udp section contains settings of UDP faces and channels
738  // udp
739  // {
740  // port 6363 ; UDP unicast port number
741  // idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
742  // keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
743 
744  // ; NFD creates one UDP multicast face per NIC
745  // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
746  // mcast_port 56363 ; UDP multicast port number
747  // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
748  // }
749 
750 #if defined(HAVE_UDP)
751  uint16_t port = 6363;
752  bool enableV4 = true;
753  bool enableV6 = true;
754  size_t timeout = 600;
755  size_t keepAliveInterval = 25;
756  bool useMcast = true;
757  auto mcastGroup = boost::asio::ip::address_v4::from_string("224.0.23.170");
758  uint16_t mcastPort = 56363;
759 
760  for (const auto& i : configSection) {
761  if (i.first == "port") {
762  port = ConfigFile::parseNumber<uint16_t>(i, "udp");
763  NFD_LOG_TRACE("UDP unicast port set to " << port);
764  }
765  else if (i.first == "enable_v4") {
766  enableV4 = ConfigFile::parseYesNo(i, "udp");
767  }
768  else if (i.first == "enable_v6") {
769  enableV6 = ConfigFile::parseYesNo(i, "udp");
770  }
771  else if (i.first == "idle_timeout") {
772  try {
773  timeout = i.second.get_value<size_t>();
774  }
775  catch (const boost::property_tree::ptree_bad_data&) {
776  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
777  i.first + "\" in \"udp\" section"));
778  }
779  }
780  else if (i.first == "keep_alive_interval") {
781  try {
782  keepAliveInterval = i.second.get_value<size_t>();
784  (void)(keepAliveInterval);
785  }
786  catch (const boost::property_tree::ptree_bad_data&) {
787  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
788  i.first + "\" in \"udp\" section"));
789  }
790  }
791  else if (i.first == "mcast") {
792  useMcast = ConfigFile::parseYesNo(i, "udp");
793  }
794  else if (i.first == "mcast_port") {
795  mcastPort = ConfigFile::parseNumber<uint16_t>(i, "udp");
796  NFD_LOG_TRACE("UDP multicast port set to " << mcastPort);
797  }
798  else if (i.first == "mcast_group") {
799  boost::system::error_code ec;
800  mcastGroup = boost::asio::ip::address_v4::from_string(i.second.get_value<std::string>(), ec);
801  if (ec) {
802  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
803  i.first + "\" in \"udp\" section"));
804  }
805  NFD_LOG_TRACE("UDP multicast group set to " << mcastGroup);
806  }
807  else {
808  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
809  i.first + "\" in \"udp\" section"));
810  }
811  }
812 
813  if (!enableV4 && !enableV6) {
814  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 UDP channels have been disabled."
815  " Remove \"udp\" section to disable UDP channels or"
816  " re-enable at least one channel type."));
817  }
818  else if (useMcast && !enableV4) {
819  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 multicast requested, but IPv4 channels"
820  " have been disabled (conflicting configuration options set)"));
821  }
822 
823  if (!isDryRun) {
824  shared_ptr<UdpFactory> factory;
825  bool isReload = false;
826  if (m_factories.count("udp") > 0) {
827  isReload = true;
828  factory = static_pointer_cast<UdpFactory>(m_factories["udp"]);
829  }
830  else {
831  factory = make_shared<UdpFactory>();
832  m_factories.insert(std::make_pair("udp", factory));
833  }
834 
835  if (!isReload && enableV4) {
836  udp::Endpoint endpoint(boost::asio::ip::udp::v4(), port);
837  shared_ptr<UdpChannel> v4Channel = factory->createChannel(endpoint, time::seconds(timeout));
838  v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
839 
840  m_factories.insert(std::make_pair("udp4", factory));
841  }
842 
843  if (!isReload && enableV6) {
844  udp::Endpoint endpoint(boost::asio::ip::udp::v6(), port);
845  shared_ptr<UdpChannel> v6Channel = factory->createChannel(endpoint, time::seconds(timeout));
846  v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
847 
848  m_factories.insert(std::make_pair("udp6", factory));
849  }
850 
851  std::set<shared_ptr<Face>> multicastFacesToRemove;
852  for (const auto& i : factory->getMulticastFaces()) {
853  multicastFacesToRemove.insert(i.second);
854  }
855 
856  if (useMcast && enableV4) {
857  std::vector<NetworkInterfaceInfo> ipv4MulticastInterfaces;
858  for (const auto& nic : nicList) {
859  if (nic.isUp() && nic.isMulticastCapable() && !nic.ipv4Addresses.empty()) {
860  ipv4MulticastInterfaces.push_back(nic);
861  }
862  }
863 
864  bool isNicNameNecessary = false;
865 #if defined(__linux__)
866  if (ipv4MulticastInterfaces.size() > 1) {
867  // On Linux if we have more than one MulticastUdpFace
868  // we need to specify the name of the interface
869  isNicNameNecessary = true;
870  }
871 #endif
872 
873  udp::Endpoint mcastEndpoint(mcastGroup, mcastPort);
874  for (const auto& nic : ipv4MulticastInterfaces) {
875  udp::Endpoint localEndpoint(nic.ipv4Addresses[0], mcastPort);
876  auto newFace = factory->createMulticastFace(localEndpoint, mcastEndpoint,
877  isNicNameNecessary ? nic.name : "");
878  m_faceTable.add(newFace);
879  multicastFacesToRemove.erase(newFace);
880  }
881  }
882 
883  for (const auto& face : multicastFacesToRemove) {
884  face->close();
885  }
886  }
887 #else
888  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without UDP support, cannot process \"udp\" section"));
889 #endif // HAVE_UDP
890 }
891 
892 void
893 FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryRun,
894  const std::vector<NetworkInterfaceInfo>& nicList)
895 {
896  // ; the ether section contains settings of Ethernet faces and channels
897  // ether
898  // {
899  // ; NFD creates one Ethernet multicast face per NIC
900  // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
901  // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
902  // }
903 
904 #if defined(HAVE_LIBPCAP)
905  NetworkInterfacePredicate nicPredicate;
906  bool useMcast = true;
908 
909  for (const auto& i : configSection) {
910  if (i.first == "mcast") {
911  useMcast = ConfigFile::parseYesNo(i, "ether");
912  }
913  else if (i.first == "mcast_group") {
914  mcastGroup = ethernet::Address::fromString(i.second.get_value<std::string>());
915  if (mcastGroup.isNull()) {
916  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
917  i.first + "\" in \"ether\" section"));
918  }
919  NFD_LOG_TRACE("Ethernet multicast group set to " << mcastGroup);
920  }
921  else if (i.first == "whitelist") {
922  nicPredicate.parseWhitelist(i.second);
923  }
924  else if (i.first == "blacklist") {
925  nicPredicate.parseBlacklist(i.second);
926  }
927  else {
928  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
929  i.first + "\" in \"ether\" section"));
930  }
931  }
932 
933  if (!isDryRun) {
934  shared_ptr<EthernetFactory> factory;
935  if (m_factories.count("ether") > 0) {
936  factory = static_pointer_cast<EthernetFactory>(m_factories["ether"]);
937  }
938  else {
939  factory = make_shared<EthernetFactory>();
940  m_factories.insert(std::make_pair("ether", factory));
941  }
942 
943  std::set<shared_ptr<Face>> multicastFacesToRemove;
944  for (const auto& i : factory->getMulticastFaces()) {
945  multicastFacesToRemove.insert(i.second);
946  }
947 
948  if (useMcast) {
949  for (const auto& nic : nicList) {
950  if (nic.isUp() && nic.isMulticastCapable() && nicPredicate(nic)) {
951  try {
952  auto newFace = factory->createMulticastFace(nic, mcastGroup);
953  m_faceTable.add(newFace);
954  multicastFacesToRemove.erase(newFace);
955  }
956  catch (const EthernetFactory::Error& factoryError) {
957  NFD_LOG_ERROR(factoryError.what() << ", continuing");
958  }
959  catch (const face::EthernetTransport::Error& faceError) {
960  NFD_LOG_ERROR(faceError.what() << ", continuing");
961  }
962  }
963  }
964  }
965 
966  for (const auto& face : multicastFacesToRemove) {
967  face->close();
968  }
969  }
970 #else
971  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section"));
972 #endif // HAVE_LIBPCAP
973 }
974 
975 void
976 FaceManager::processSectionWebSocket(const ConfigSection& configSection, bool isDryRun)
977 {
978  // ; the websocket section contains settings of WebSocket faces and channels
979  // websocket
980  // {
981  // listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
982  // port 9696 ; WebSocket listener port number
983  // enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
984  // enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
985  // }
986 
987 #if defined(HAVE_WEBSOCKET)
988  uint16_t port = 9696;
989  bool needToListen = true;
990  bool enableV4 = true;
991  bool enableV6 = true;
992 
993  for (const auto& i : configSection) {
994  if (i.first == "port") {
995  port = ConfigFile::parseNumber<uint16_t>(i, "websocket");
996  NFD_LOG_TRACE("WebSocket port set to " << port);
997  }
998  else if (i.first == "listen") {
999  needToListen = ConfigFile::parseYesNo(i, "websocket");
1000  }
1001  else if (i.first == "enable_v4") {
1002  enableV4 = ConfigFile::parseYesNo(i, "websocket");
1003  }
1004  else if (i.first == "enable_v6") {
1005  enableV6 = ConfigFile::parseYesNo(i, "websocket");
1006  }
1007  else {
1008  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
1009  i.first + "\" in \"websocket\" section"));
1010  }
1011  }
1012 
1013  if (!enableV4 && !enableV6) {
1014  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 WebSocket channels have been disabled."
1015  " Remove \"websocket\" section to disable WebSocket channels or"
1016  " re-enable at least one channel type."));
1017  }
1018 
1019  if (!enableV4 && enableV6) {
1020  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel."));
1021  }
1022 
1023  if (!isDryRun) {
1024  if (m_factories.count("websocket") > 0) {
1025  return;
1026  }
1027 
1028  auto factory = make_shared<WebSocketFactory>();
1029  m_factories.insert(std::make_pair("websocket", factory));
1030 
1031  shared_ptr<WebSocketChannel> channel;
1032 
1033  if (enableV6 && enableV4) {
1034  websocket::Endpoint endpoint(boost::asio::ip::address_v6::any(), port);
1035  channel = factory->createChannel(endpoint);
1036 
1037  m_factories.insert(std::make_pair("websocket46", factory));
1038  }
1039  else if (enableV4) {
1040  websocket::Endpoint endpoint(boost::asio::ip::address_v4::any(), port);
1041  channel = factory->createChannel(endpoint);
1042 
1043  m_factories.insert(std::make_pair("websocket4", factory));
1044  }
1045 
1046  if (channel && needToListen) {
1047  channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
1048  }
1049  }
1050 #else
1051  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without WebSocket, "
1052  "cannot process \"websocket\" section"));
1053 #endif // HAVE_WEBSOCKET
1054 }
1055 
1056 } // namespace nfd
signal::Signal< FaceTable, Face & > afterAdd
fires after a face is added
Definition: face-table.hpp:85
void reject(const ControlResponse &resp=ControlResponse().setCode(400))
declare the non-existence of a response
void setConfigFile(ConfigFile &configFile)
Subscribe to face_system section for the config file.
time_point TimePoint
Definition: time.hpp:120
ControlParameters & setFaceId(uint64_t faceId)
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
GenericLinkService is a LinkService that implements the NDNLPv2 protocol.
face went UP (from DOWN state)
static bool parseYesNo(const ConfigSection &node, const std::string &key, const std::string &sectionName)
parse a config option that can be either "yes" or "no"
Definition: config-file.cpp:62
bool parse(const std::string &uri)
exception-safe parsing
Definition: face-uri.cpp:63
const std::string & getLocalUri() const
represents parameters in a ControlCommand request or response
generalization of a network interface
Definition: face.hpp:67
bool allowLocalFields
enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy ...
represents a dispatcher on server side of NFD Management protocol
Definition: dispatcher.hpp:129
represents an Ethernet hardware address
Definition: ethernet.hpp:53
static Address fromString(const std::string &str)
Creates an Address from a string containing an Ethernet address in hexadecimal notation, with colons or hyphens as separators.
Definition: ethernet.cpp:86
TransportState
indicates the state of a transport
Definition: transport.hpp:41
static time_point now() noexcept
Definition: time.cpp:79
FaceStatus & setNInDatas(uint64_t nInDatas)
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
configuration file parsing utility
Definition: config-file.hpp:50
const PacketCounter & nOutNacks
size_t wireEncode(EncodingImpl< TAG > &encoder) const
void add(shared_ptr< Face > face)
add a face
Definition: face-table.cpp:58
bool isCanonical() const
determine whether this FaceUri is in canonical form
Definition: face-uri.cpp:552
virtual std::vector< shared_ptr< const Channel > > getChannels() const =0
std::string toString() const
write as a string
Definition: face-uri.cpp:195
Address getDefaultMulticastAddress()
Returns the default Ethernet multicast address for NDN.
Definition: ethernet.cpp:124
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:91
FaceStatus & setNOutDatas(uint64_t nOutDatas)
represents a Face status change notification
const std::string & getRemoteUri() const
represents an Interest packet
Definition: interest.hpp:42
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
FaceEventNotification & setKind(FaceEventKind kind)
FaceUri getLocalUri() const
Definition: face.hpp:253
FaceUri getRemoteUri() const
Definition: face.hpp:259
LinkService * getLinkService() const
Definition: face.hpp:199
FaceStatus & setNOutBytes(uint64_t nOutBytes)
void parseWhitelist(const boost::property_tree::ptree &list)
FaceStatus & setNOutInterests(uint64_t nOutInterests)
C & setFaceId(uint64_t faceId)
Definition: face-traits.hpp:65
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:113
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:42
time::steady_clock::TimePoint getExpirationTime() const
Definition: face.hpp:295
provides a tag type for simple types
Definition: tag.hpp:58
std::vector< NetworkInterfaceInfo > listNetworkInterfaces()
List configured network interfaces on the system and their info.
FaceStatus & setNInInterests(uint64_t nInInterests)
FacePersistency getFacePersistency() const
FaceStatus & setNInBytes(uint64_t nInBytes)
Represents a predicate to accept or reject a NetworkInterfaceInfo.
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:57
size_t wireEncode(EncodingImpl< TAG > &encoder) const
prepend FaceEventNotification to the encoder
ndn::mgmt::ControlResponse ControlResponse
container of all faces
Definition: face-table.hpp:37
FaceStatus & setNInNacks(uint64_t nInNacks)
ndn::nfd::LinkType getLinkType() const
Definition: face.hpp:283
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
void addSectionHandler(const std::string &sectionName, ConfigSectionHandler subscriber)
setup notification of configuration file sections
Definition: config-file.cpp:79
Abstract base class for all protocol factories.
void end()
end the response successfully after appending zero or more blocks
boost::asio::ip::tcp::endpoint Endpoint
Definition: tcp-channel.hpp:35
the transport is closed, and can be safely deallocated
const PacketCounter & nOutData
FaceId getId() const
Definition: face.hpp:229
const PacketCounter & nInInterests
FaceStatus & setExpirationPeriod(const time::milliseconds &expirationPeriod)
size_t wireEncode(EncodingImpl< TAG > &encoder) const
prepend FaceStatus to the encoder
Definition: face-status.cpp:56
represents Face status
Definition: face-status.hpp:37
ndn::nfd::FaceScope getScope() const
Definition: face.hpp:265
signal::Signal< Transport, FaceState, FaceState > & afterStateChange
signals after face state changed
Definition: face.hpp:166
boost::property_tree::ptree ConfigSection
Name abstraction to represent an absolute name.
Definition: name.hpp:46
const ByteCounter & nOutBytes
bool hasFlagBit(size_t bit) const
FaceManager(FaceTable &faceTable, Dispatcher &dispatcher, CommandAuthenticator &authenticator)
std::function< void(const ControlResponse &resp)> CommandContinuation
a function to be called after ControlCommandHandler completes
Definition: dispatcher.hpp:95
represents Face Query Filter
boost::asio::ip::udp::endpoint Endpoint
Definition: udp-channel.hpp:34
const std::string & getUri() const
Options that control the behavior of GenericLinkService.
Exception of EthernetFactory.
provides ControlCommand authorization according to NFD configuration file
const ByteCounter & nInBytes
void parseBlacklist(const boost::property_tree::ptree &list)
ndn::nfd::FacePersistency getPersistency() const
Definition: face.hpp:271
ControlParameters & setFacePersistency(FacePersistency persistency)
FaceStatus & setNOutNacks(uint64_t nOutNacks)
void append(const Block &block)
append a Block to the response
represents NFD Channel Status dataset
bool getFlagBit(size_t bit) const
boost::asio::ip::tcp::endpoint Endpoint
face went DOWN (from UP state)
void close()
request the face to be closed
Definition: face.hpp:301
bool isNull() const
True if this is a null address (00:00:00:00:00:00)
Definition: ethernet.cpp:66
ndn::mgmt::PostNotification registerNotificationStream(const std::string &verb)
the transport is up
const Options & getOptions() const
get Options used by GenericLinkService
const std::string & getUriScheme() const
provides a context for generating response to a StatusDataset request
FacePersistency getFacePersistency() const
uint64_t FaceId
identifies a face
Definition: face.hpp:39
a collection of common functions shared by all NFD managers, such as communicating with the dispatche...
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
bit that controls whether local fields are enabled on a face
void wireDecode(const Block &wire)
decode FaceQueryFilter
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
ControlParameters & setFlagBit(size_t bit, bool value, bool wantMask=true)
set a bit in Flags
const FaceCounters & getCounters() const
Definition: face.hpp:307
const PacketCounter & nOutInterests
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
gives access to counters provided by Face
the transport is down temporarily, and is being recovered
size_t wireEncode(EncodingImpl< TAG > &encoder) const
const PacketCounter & nInNacks
ChannelStatus & setLocalUri(const std::string localUri)
const Name & getName() const
Definition: interest.hpp:215
const PacketCounter & nInData