NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: 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"
27 
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/management/nfd-channel-status.hpp>
44 #include <ndn-cxx/management/nfd-face-status.hpp>
45 #include <ndn-cxx/management/nfd-face-event-notification.hpp>
46 
47 #ifdef HAVE_UNIX_SOCKETS
49 #endif // HAVE_UNIX_SOCKETS
50 
51 #ifdef HAVE_LIBPCAP
54 #endif // HAVE_LIBPCAP
55 
56 #ifdef HAVE_WEBSOCKET
58 #endif // HAVE_WEBSOCKET
59 
60 namespace nfd {
61 
62 NFD_LOG_INIT("FaceManager");
63 
65  Dispatcher& dispatcher,
66  CommandValidator& validator)
67  : ManagerBase(dispatcher, validator, "faces")
68  , m_faceTable(faceTable)
69 {
70  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
71  bind(&FaceManager::createFace, 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  auto postNotification = registerNotificationStream("events");
87  m_faceAddConn =
88  m_faceTable.afterAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
89  m_faceRemoveConn =
90  m_faceTable.beforeRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
91 }
92 
93 void
95 {
96  configFile.addSectionHandler("face_system", bind(&FaceManager::processConfig, this, _1, _2, _3));
97 }
98 
99 void
100 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
101  const ControlParameters& parameters,
102  const ndn::mgmt::CommandContinuation& done)
103 {
104  FaceUri uri;
105  if (!uri.parse(parameters.getUri())) {
106  NFD_LOG_TRACE("failed to parse URI");
107  return done(ControlResponse(400, "Malformed command"));
108  }
109 
110  if (!uri.isCanonical()) {
111  NFD_LOG_TRACE("received non-canonical URI");
112  return done(ControlResponse(400, "Non-canonical URI"));
113  }
114 
115  auto factory = m_factories.find(uri.getScheme());
116  if (factory == m_factories.end()) {
117  return done(ControlResponse(501, "Unsupported protocol"));
118  }
119 
120  try {
121  factory->second->createFace(uri,
122  parameters.getFacePersistency(),
123  bind(&FaceManager::afterCreateFaceSuccess,
124  this, parameters, _1, done),
125  bind(&FaceManager::afterCreateFaceFailure,
126  this, _1, done));
127  }
128  catch (const std::runtime_error& error) {
129  std::string errorMessage = "Face creation failed: ";
130  errorMessage += error.what();
131 
132  NFD_LOG_ERROR(errorMessage);
133  return done(ControlResponse(500, errorMessage));
134  }
135  catch (const std::logic_error& error) {
136  std::string errorMessage = "Face creation failed: ";
137  errorMessage += error.what();
138 
139  NFD_LOG_ERROR(errorMessage);
140  return done(ControlResponse(500, errorMessage));
141  }
142 }
143 
144 void
145 FaceManager::afterCreateFaceSuccess(ControlParameters& parameters,
146  const shared_ptr<Face>& newFace,
147  const ndn::mgmt::CommandContinuation& done)
148 {
149  m_faceTable.add(newFace);
150  parameters.setFaceId(newFace->getId());
151  parameters.setUri(newFace->getRemoteUri().toString());
152  parameters.setFacePersistency(newFace->getPersistency());
153 
154  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
155 }
156 
157 void
158 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
159  const ControlParameters& parameters,
160  const ndn::mgmt::CommandContinuation& done)
161 {
162  shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
163  if (target) {
164  target->close();
165  }
166 
167  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
168 }
169 
170 void
171 FaceManager::afterCreateFaceFailure(const std::string& reason,
172  const ndn::mgmt::CommandContinuation& done)
173 {
174  NFD_LOG_DEBUG("Failed to create face: " << reason);
175 
176  done(ControlResponse(408, "Failed to create face: " + reason));
177 }
178 
179 void
180 FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
181  const ControlParameters& parameters,
182  const ndn::mgmt::CommandContinuation& done)
183 {
184  Face* face = findFaceForLocalControl(interest, parameters, done);
185  if (!face) {
186  return;
187  }
188 
189  // TODO#3226 redesign enable-local-control
190  // For now, enable-local-control will enable all local fields in GenericLinkService.
191  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
192  if (service == nullptr) {
193  return done(ControlResponse(503, "LinkService type not supported"));
194  }
195 
196  face::GenericLinkService::Options options = service->getOptions();
197  options.allowLocalFields = true;
198  service->setOptions(options);
199 
200  return done(ControlResponse(200, "OK: enable all local fields on GenericLinkService")
201  .setBody(parameters.wireEncode()));
202 }
203 
204 void
205 FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
206  const ControlParameters& parameters,
207  const ndn::mgmt::CommandContinuation& done)
208 {
209  Face* face = findFaceForLocalControl(interest, parameters, done);
210  if (!face) {
211  return;
212  }
213 
214  // TODO#3226 redesign disable-local-control
215  // For now, disable-local-control will disable all local fields in GenericLinkService.
216  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
217  if (service == nullptr) {
218  return done(ControlResponse(503, "LinkService type not supported"));
219  }
220 
221  face::GenericLinkService::Options options = service->getOptions();
222  options.allowLocalFields = false;
223  service->setOptions(options);
224 
225  return done(ControlResponse(200, "OK: disable all local fields on GenericLinkService")
226  .setBody(parameters.wireEncode()));
227 }
228 
229 Face*
230 FaceManager::findFaceForLocalControl(const Interest& request,
231  const ControlParameters& parameters,
232  const ndn::mgmt::CommandContinuation& done)
233 {
234  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
235  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
236  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
237  // and is initialized synchronously with IncomingFaceId field enabled.
238  BOOST_ASSERT(incomingFaceIdTag != nullptr);
239 
240  auto face = m_faceTable.get(*incomingFaceIdTag);
241  if (face == nullptr) {
242  NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
243  done(ControlResponse(410, "Face not found"));
244  return nullptr;
245  }
246 
247  if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
248  NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
249  done(ControlResponse(412, "Face is non-local"));
250  return nullptr;
251  }
252 
253  return face.get();
254 }
255 
256 void
257 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
259 {
260  auto now = time::steady_clock::now();
261  for (const auto& face : m_faceTable) {
262  ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
263  context.append(status.wireEncode());
264  }
265  context.end();
266 }
267 
268 void
269 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
271 {
272  std::set<const ProtocolFactory*> seenFactories;
273 
274  for (const auto& kv : m_factories) {
275  const ProtocolFactory* factory = kv.second.get();
276  bool inserted;
277  std::tie(std::ignore, inserted) = seenFactories.insert(factory);
278 
279  if (inserted) {
280  for (const auto& channel : factory->getChannels()) {
282  entry.setLocalUri(channel->getUri().toString());
283  context.append(entry.wireEncode());
284  }
285  }
286  }
287 
288  context.end();
289 }
290 
291 void
292 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
294 {
295  ndn::nfd::FaceQueryFilter faceFilter;
296  const Name& query = interest.getName();
297  try {
298  faceFilter.wireDecode(query[-1].blockFromValue());
299  }
300  catch (const tlv::Error& e) {
301  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
302  return context.reject(ControlResponse(400, "Malformed filter"));
303  }
304 
305  auto now = time::steady_clock::now();
306  for (const auto& face : m_faceTable) {
307  if (!doesMatchFilter(faceFilter, face)) {
308  continue;
309  }
310  ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
311  context.append(status.wireEncode());
312  }
313 
314  context.end();
315 }
316 
317 bool
318 FaceManager::doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr<Face> face)
319 {
320  if (filter.hasFaceId() &&
321  filter.getFaceId() != static_cast<uint64_t>(face->getId())) {
322  return false;
323  }
324 
325  if (filter.hasUriScheme() &&
326  filter.getUriScheme() != face->getRemoteUri().getScheme() &&
327  filter.getUriScheme() != face->getLocalUri().getScheme()) {
328  return false;
329  }
330 
331  if (filter.hasRemoteUri() &&
332  filter.getRemoteUri() != face->getRemoteUri().toString()) {
333  return false;
334  }
335 
336  if (filter.hasLocalUri() &&
337  filter.getLocalUri() != face->getLocalUri().toString()) {
338  return false;
339  }
340 
341  if (filter.hasFaceScope() &&
342  filter.getFaceScope() != face->getScope()) {
343  return false;
344  }
345 
346  if (filter.hasFacePersistency() &&
347  filter.getFacePersistency() != face->getPersistency()) {
348  return false;
349  }
350 
351  if (filter.hasLinkType() &&
352  filter.getLinkType() != face->getLinkType()) {
353  return false;
354  }
355 
356  return true;
357 }
358 
360 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
361 {
362  ndn::nfd::FaceStatus status;
363 
364  collectFaceProperties(face, status);
365 
366  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
367  if (expirationTime != time::steady_clock::TimePoint::max()) {
368  status.setExpirationPeriod(std::max(time::milliseconds(0),
369  time::duration_cast<time::milliseconds>(expirationTime - now)));
370  }
371 
372  const face::FaceCounters& counters = face.getCounters();
373  status.setNInInterests(counters.nInInterests)
375  .setNInDatas(counters.nInData)
376  .setNOutDatas(counters.nOutData)
377  .setNInNacks(counters.nInNacks)
378  .setNOutNacks(counters.nOutNacks)
379  .setNInBytes(counters.nInBytes)
380  .setNOutBytes(counters.nOutBytes);
381 
382  return status;
383 }
384 
385 template<typename FaceTraits>
386 void
387 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
388 {
389  traits.setFaceId(face.getId())
390  .setRemoteUri(face.getRemoteUri().toString())
391  .setLocalUri(face.getLocalUri().toString())
392  .setFaceScope(face.getScope())
393  .setFacePersistency(face.getPersistency())
394  .setLinkType(face.getLinkType());
395 }
396 
397 void
398 FaceManager::afterFaceAdded(shared_ptr<Face> face,
399  const ndn::mgmt::PostNotification& post)
400 {
401  ndn::nfd::FaceEventNotification notification;
403  collectFaceProperties(*face, notification);
404 
405  post(notification.wireEncode());
406 }
407 
408 void
409 FaceManager::afterFaceRemoved(shared_ptr<Face> face,
410  const ndn::mgmt::PostNotification& post)
411 {
412  ndn::nfd::FaceEventNotification notification;
414  collectFaceProperties(*face, notification);
415 
416  post(notification.wireEncode());
417 }
418 
419 void
420 FaceManager::processConfig(const ConfigSection& configSection,
421  bool isDryRun,
422  const std::string& filename)
423 {
424  bool hasSeenUnix = false;
425  bool hasSeenTcp = false;
426  bool hasSeenUdp = false;
427  bool hasSeenEther = false;
428  bool hasSeenWebSocket = false;
429  auto nicList = listNetworkInterfaces();
430 
431  for (const auto& item : configSection) {
432  if (item.first == "unix") {
433  if (hasSeenUnix) {
434  BOOST_THROW_EXCEPTION(Error("Duplicate \"unix\" section"));
435  }
436  hasSeenUnix = true;
437 
438  processSectionUnix(item.second, isDryRun);
439  }
440  else if (item.first == "tcp") {
441  if (hasSeenTcp) {
442  BOOST_THROW_EXCEPTION(Error("Duplicate \"tcp\" section"));
443  }
444  hasSeenTcp = true;
445 
446  processSectionTcp(item.second, isDryRun);
447  }
448  else if (item.first == "udp") {
449  if (hasSeenUdp) {
450  BOOST_THROW_EXCEPTION(Error("Duplicate \"udp\" section"));
451  }
452  hasSeenUdp = true;
453 
454  processSectionUdp(item.second, isDryRun, nicList);
455  }
456  else if (item.first == "ether") {
457  if (hasSeenEther) {
458  BOOST_THROW_EXCEPTION(Error("Duplicate \"ether\" section"));
459  }
460  hasSeenEther = true;
461 
462  processSectionEther(item.second, isDryRun, nicList);
463  }
464  else if (item.first == "websocket") {
465  if (hasSeenWebSocket) {
466  BOOST_THROW_EXCEPTION(Error("Duplicate \"websocket\" section"));
467  }
468  hasSeenWebSocket = true;
469 
470  processSectionWebSocket(item.second, isDryRun);
471  }
472  else {
473  BOOST_THROW_EXCEPTION(Error("Unrecognized option \"" + item.first + "\""));
474  }
475  }
476 }
477 
478 void
479 FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
480 {
481  // ; the unix section contains settings of Unix stream faces and channels
482  // unix
483  // {
484  // path /var/run/nfd.sock ; Unix stream listener path
485  // }
486 
487 #if defined(HAVE_UNIX_SOCKETS)
488  std::string path = "/var/run/nfd.sock";
489 
490  for (const auto& i : configSection) {
491  if (i.first == "path") {
492  path = i.second.get_value<std::string>();
493  }
494  else {
495  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
496  i.first + "\" in \"unix\" section"));
497  }
498  }
499 
500  if (!isDryRun) {
501  if (m_factories.count("unix") > 0) {
502  return;
503  }
504 
505  auto factory = make_shared<UnixStreamFactory>();
506  m_factories.insert(std::make_pair("unix", factory));
507 
508  auto channel = factory->createChannel(path);
509  channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
510  }
511 #else
512  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without Unix sockets support, "
513  "cannot process \"unix\" section"));
514 #endif // HAVE_UNIX_SOCKETS
515 }
516 
517 void
518 FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
519 {
520  // ; the tcp section contains settings of TCP faces and channels
521  // tcp
522  // {
523  // listen yes ; set to 'no' to disable TCP listener, default 'yes'
524  // port 6363 ; TCP listener port number
525  // }
526 
527 #if defined(HAVE_TCP)
528  uint16_t port = 6363;
529  bool needToListen = true;
530  bool enableV4 = true;
531  bool enableV6 = true;
532 
533  for (const auto& i : configSection) {
534  if (i.first == "port") {
535  port = ConfigFile::parseNumber<uint16_t>(i, "tcp");
536  NFD_LOG_TRACE("TCP port set to " << port);
537  }
538  else if (i.first == "listen") {
539  needToListen = ConfigFile::parseYesNo(i, "tcp");
540  }
541  else if (i.first == "enable_v4") {
542  enableV4 = ConfigFile::parseYesNo(i, "tcp");
543  }
544  else if (i.first == "enable_v6") {
545  enableV6 = ConfigFile::parseYesNo(i, "tcp");
546  }
547  else {
548  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
549  i.first + "\" in \"tcp\" section"));
550  }
551  }
552 
553  if (!enableV4 && !enableV6) {
554  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 TCP channels have been disabled."
555  " Remove \"tcp\" section to disable TCP channels or"
556  " re-enable at least one channel type."));
557  }
558 
559  if (!isDryRun) {
560  if (m_factories.count("tcp") > 0) {
561  return;
562  }
563 
564  auto factory = make_shared<TcpFactory>();
565  m_factories.insert(std::make_pair("tcp", factory));
566 
567  if (enableV4) {
568  tcp::Endpoint endpoint(boost::asio::ip::tcp::v4(), port);
569  shared_ptr<TcpChannel> v4Channel = factory->createChannel(endpoint);
570  if (needToListen) {
571  v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
572  }
573 
574  m_factories.insert(std::make_pair("tcp4", factory));
575  }
576 
577  if (enableV6) {
578  tcp::Endpoint endpoint(boost::asio::ip::tcp::v6(), port);
579  shared_ptr<TcpChannel> v6Channel = factory->createChannel(endpoint);
580  if (needToListen) {
581  v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
582  }
583 
584  m_factories.insert(std::make_pair("tcp6", factory));
585  }
586  }
587 #else
588  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without TCP support, cannot process \"tcp\" section"));
589 #endif // HAVE_TCP
590 }
591 
592 void
593 FaceManager::processSectionUdp(const ConfigSection& configSection, bool isDryRun,
594  const std::vector<NetworkInterfaceInfo>& nicList)
595 {
596  // ; the udp section contains settings of UDP faces and channels
597  // udp
598  // {
599  // port 6363 ; UDP unicast port number
600  // idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
601  // keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
602 
603  // ; NFD creates one UDP multicast face per NIC
604  // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
605  // mcast_port 56363 ; UDP multicast port number
606  // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
607  // }
608 
609 #if defined(HAVE_UDP)
610  uint16_t port = 6363;
611  bool enableV4 = true;
612  bool enableV6 = true;
613  size_t timeout = 600;
614  size_t keepAliveInterval = 25;
615  bool useMcast = true;
616  auto mcastGroup = boost::asio::ip::address_v4::from_string("224.0.23.170");
617  uint16_t mcastPort = 56363;
618 
619  for (const auto& i : configSection) {
620  if (i.first == "port") {
621  port = ConfigFile::parseNumber<uint16_t>(i, "udp");
622  NFD_LOG_TRACE("UDP unicast port set to " << port);
623  }
624  else if (i.first == "enable_v4") {
625  enableV4 = ConfigFile::parseYesNo(i, "udp");
626  }
627  else if (i.first == "enable_v6") {
628  enableV6 = ConfigFile::parseYesNo(i, "udp");
629  }
630  else if (i.first == "idle_timeout") {
631  try {
632  timeout = i.second.get_value<size_t>();
633  }
634  catch (const boost::property_tree::ptree_bad_data&) {
635  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
636  i.first + "\" in \"udp\" section"));
637  }
638  }
639  else if (i.first == "keep_alive_interval") {
640  try {
641  keepAliveInterval = i.second.get_value<size_t>();
643  (void)(keepAliveInterval);
644  }
645  catch (const boost::property_tree::ptree_bad_data&) {
646  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
647  i.first + "\" in \"udp\" section"));
648  }
649  }
650  else if (i.first == "mcast") {
651  useMcast = ConfigFile::parseYesNo(i, "udp");
652  }
653  else if (i.first == "mcast_port") {
654  mcastPort = ConfigFile::parseNumber<uint16_t>(i, "udp");
655  NFD_LOG_TRACE("UDP multicast port set to " << mcastPort);
656  }
657  else if (i.first == "mcast_group") {
658  boost::system::error_code ec;
659  mcastGroup = boost::asio::ip::address_v4::from_string(i.second.get_value<std::string>(), ec);
660  if (ec) {
661  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
662  i.first + "\" in \"udp\" section"));
663  }
664  NFD_LOG_TRACE("UDP multicast group set to " << mcastGroup);
665  }
666  else {
667  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
668  i.first + "\" in \"udp\" section"));
669  }
670  }
671 
672  if (!enableV4 && !enableV6) {
673  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 UDP channels have been disabled."
674  " Remove \"udp\" section to disable UDP channels or"
675  " re-enable at least one channel type."));
676  }
677  else if (useMcast && !enableV4) {
678  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 multicast requested, but IPv4 channels"
679  " have been disabled (conflicting configuration options set)"));
680  }
681 
682  if (!isDryRun) {
683  shared_ptr<UdpFactory> factory;
684  bool isReload = false;
685  if (m_factories.count("udp") > 0) {
686  isReload = true;
687  factory = static_pointer_cast<UdpFactory>(m_factories["udp"]);
688  }
689  else {
690  factory = make_shared<UdpFactory>();
691  m_factories.insert(std::make_pair("udp", factory));
692  }
693 
694  if (!isReload && enableV4) {
695  udp::Endpoint endpoint(boost::asio::ip::udp::v4(), port);
696  shared_ptr<UdpChannel> v4Channel = factory->createChannel(endpoint, time::seconds(timeout));
697  v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
698 
699  m_factories.insert(std::make_pair("udp4", factory));
700  }
701 
702  if (!isReload && enableV6) {
703  udp::Endpoint endpoint(boost::asio::ip::udp::v6(), port);
704  shared_ptr<UdpChannel> v6Channel = factory->createChannel(endpoint, time::seconds(timeout));
705  v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
706 
707  m_factories.insert(std::make_pair("udp6", factory));
708  }
709 
710  std::set<shared_ptr<Face>> multicastFacesToRemove;
711  for (const auto& i : factory->getMulticastFaces()) {
712  multicastFacesToRemove.insert(i.second);
713  }
714 
715  if (useMcast && enableV4) {
716  std::vector<NetworkInterfaceInfo> ipv4MulticastInterfaces;
717  for (const auto& nic : nicList) {
718  if (nic.isUp() && nic.isMulticastCapable() && !nic.ipv4Addresses.empty()) {
719  ipv4MulticastInterfaces.push_back(nic);
720  }
721  }
722 
723  bool isNicNameNecessary = false;
724 #if defined(__linux__)
725  if (ipv4MulticastInterfaces.size() > 1) {
726  // On Linux if we have more than one MulticastUdpFace
727  // we need to specify the name of the interface
728  isNicNameNecessary = true;
729  }
730 #endif
731 
732  udp::Endpoint mcastEndpoint(mcastGroup, mcastPort);
733  for (const auto& nic : ipv4MulticastInterfaces) {
734  udp::Endpoint localEndpoint(nic.ipv4Addresses[0], mcastPort);
735  auto newFace = factory->createMulticastFace(localEndpoint, mcastEndpoint,
736  isNicNameNecessary ? nic.name : "");
737  m_faceTable.add(newFace);
738  multicastFacesToRemove.erase(newFace);
739  }
740  }
741 
742  for (const auto& face : multicastFacesToRemove) {
743  face->close();
744  }
745  }
746 #else
747  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without UDP support, cannot process \"udp\" section"));
748 #endif // HAVE_UDP
749 }
750 
751 void
752 FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryRun,
753  const std::vector<NetworkInterfaceInfo>& nicList)
754 {
755  // ; the ether section contains settings of Ethernet faces and channels
756  // ether
757  // {
758  // ; NFD creates one Ethernet multicast face per NIC
759  // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
760  // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
761  // }
762 
763 #if defined(HAVE_LIBPCAP)
764  bool useMcast = true;
766 
767  for (const auto& i : configSection) {
768  if (i.first == "mcast") {
769  useMcast = ConfigFile::parseYesNo(i, "ether");
770  }
771  else if (i.first == "mcast_group") {
772  mcastGroup = ethernet::Address::fromString(i.second.get_value<std::string>());
773  if (mcastGroup.isNull()) {
774  BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
775  i.first + "\" in \"ether\" section"));
776  }
777  NFD_LOG_TRACE("Ethernet multicast group set to " << mcastGroup);
778  }
779  else {
780  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
781  i.first + "\" in \"ether\" section"));
782  }
783  }
784 
785  if (!isDryRun) {
786  shared_ptr<EthernetFactory> factory;
787  if (m_factories.count("ether") > 0) {
788  factory = static_pointer_cast<EthernetFactory>(m_factories["ether"]);
789  }
790  else {
791  factory = make_shared<EthernetFactory>();
792  m_factories.insert(std::make_pair("ether", factory));
793  }
794 
795  std::set<shared_ptr<Face>> multicastFacesToRemove;
796  for (const auto& i : factory->getMulticastFaces()) {
797  multicastFacesToRemove.insert(i.second);
798  }
799 
800  if (useMcast) {
801  for (const auto& nic : nicList) {
802  if (nic.isUp() && nic.isMulticastCapable()) {
803  try {
804  auto newFace = factory->createMulticastFace(nic, mcastGroup);
805  m_faceTable.add(newFace);
806  multicastFacesToRemove.erase(newFace);
807  }
808  catch (const EthernetFactory::Error& factoryError) {
809  NFD_LOG_ERROR(factoryError.what() << ", continuing");
810  }
811  catch (const face::EthernetTransport::Error& faceError) {
812  NFD_LOG_ERROR(faceError.what() << ", continuing");
813  }
814  }
815  }
816  }
817 
818  for (const auto& face : multicastFacesToRemove) {
819  face->close();
820  }
821  }
822 #else
823  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section"));
824 #endif // HAVE_LIBPCAP
825 }
826 
827 void
828 FaceManager::processSectionWebSocket(const ConfigSection& configSection, bool isDryRun)
829 {
830  // ; the websocket section contains settings of WebSocket faces and channels
831  // websocket
832  // {
833  // listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
834  // port 9696 ; WebSocket listener port number
835  // enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
836  // enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
837  // }
838 
839 #if defined(HAVE_WEBSOCKET)
840  uint16_t port = 9696;
841  bool needToListen = true;
842  bool enableV4 = true;
843  bool enableV6 = true;
844 
845  for (const auto& i : configSection) {
846  if (i.first == "port") {
847  port = ConfigFile::parseNumber<uint16_t>(i, "websocket");
848  NFD_LOG_TRACE("WebSocket port set to " << port);
849  }
850  else if (i.first == "listen") {
851  needToListen = ConfigFile::parseYesNo(i, "websocket");
852  }
853  else if (i.first == "enable_v4") {
854  enableV4 = ConfigFile::parseYesNo(i, "websocket");
855  }
856  else if (i.first == "enable_v6") {
857  enableV6 = ConfigFile::parseYesNo(i, "websocket");
858  }
859  else {
860  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
861  i.first + "\" in \"websocket\" section"));
862  }
863  }
864 
865  if (!enableV4 && !enableV6) {
866  BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 WebSocket channels have been disabled."
867  " Remove \"websocket\" section to disable WebSocket channels or"
868  " re-enable at least one channel type."));
869  }
870 
871  if (!enableV4 && enableV6) {
872  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel."));
873  }
874 
875  if (!isDryRun) {
876  if (m_factories.count("websocket") > 0) {
877  return;
878  }
879 
880  auto factory = make_shared<WebSocketFactory>();
881  m_factories.insert(std::make_pair("websocket", factory));
882 
883  shared_ptr<WebSocketChannel> channel;
884 
885  if (enableV6 && enableV4) {
886  websocket::Endpoint endpoint(boost::asio::ip::address_v6::any(), port);
887  channel = factory->createChannel(endpoint);
888 
889  m_factories.insert(std::make_pair("websocket46", factory));
890  }
891  else if (enableV4) {
892  websocket::Endpoint endpoint(boost::asio::ip::address_v4::any(), port);
893  channel = factory->createChannel(endpoint);
894 
895  m_factories.insert(std::make_pair("websocket4", factory));
896  }
897 
898  if (channel && needToListen) {
899  channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
900  }
901  }
902 #else
903  BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without WebSocket, "
904  "cannot process \"websocket\" section"));
905 #endif // HAVE_WEBSOCKET
906 }
907 
908 } // namespace nfd
signal::Signal< FaceTable, shared_ptr< Face > > afterAdd
fires after a Face is added
Definition: face-table.hpp:78
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:108
ControlParameters & setFaceId(uint64_t faceId)
a collection of common functions shared by all NFD managers, such as communicating with the dispatche...
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
GenericLinkService is a LinkService that implements the NDNLPv2 protocol.
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
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
std::function< void(const Block &notification)> PostNotification
a function to post a notification
Definition: dispatcher.hpp:123
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
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
const PacketCounter & nOutNacks
size_t wireEncode(EncodingImpl< TAG > &encoder) const
void add(shared_ptr< Face > face)
Definition: face-table.cpp:61
bool isCanonical() const
determine whether this FaceUri is in canonical form
Definition: face-uri.cpp:507
virtual std::vector< shared_ptr< const Channel > > getChannels() const =0
Address getDefaultMulticastAddress()
Returns the default Ethernet multicast address for NDN.
Definition: ethernet.cpp:124
FaceStatus & setNOutDatas(uint64_t nOutDatas)
represents a Face status change notification
const std::string & getRemoteUri() const
represents an Interest packet
Definition: interest.hpp:45
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:57
FaceEventNotification & setKind(FaceEventKind kind)
FaceStatus & setNOutBytes(uint64_t nOutBytes)
FaceStatus & setNOutInterests(uint64_t nOutInterests)
C & setFaceId(uint64_t faceId)
ControlParameters & setUri(const std::string &uri)
const std::string & getScheme() const
get scheme (protocol)
Definition: face-uri.hpp:109
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)
signal::Signal< FaceTable, shared_ptr< Face > > beforeRemove
fires before a Face is removed
Definition: face-table.hpp:84
FacePersistency getFacePersistency() const
FaceStatus & setNInBytes(uint64_t nInBytes)
size_t wireEncode(EncodingImpl< TAG > &encoder) const
prepend FaceEventNotification to the encoder
ndn::mgmt::ControlResponse ControlResponse
container of all Faces
Definition: face-table.hpp:38
FaceStatus & setNInNacks(uint64_t nInNacks)
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
const PacketCounter & nOutData
const PacketCounter & nInInterests
FaceStatus & setExpirationPeriod(const time::milliseconds &expirationPeriod)
size_t wireEncode(EncodingImpl< TAG > &encoder) const
prepend FaceStatus to the encoder
represents Face status
boost::property_tree::ptree ConfigSection
Name abstraction to represent an absolute name.
Definition: name.hpp:46
const ByteCounter & nOutBytes
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.
const ByteCounter & nInBytes
static bool parseYesNo(const ConfigSection::value_type &option, const std::string &sectionName)
parse a config option that can be either "yes" or "no"
Definition: config-file.cpp:62
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
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
boost::asio::ip::tcp::endpoint Endpoint
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)
const std::string & getUriScheme() const
provides a context for generating response to a StatusDataset request
FacePersistency getFacePersistency() const
shared_ptr< Face > get(FaceId id) const
Definition: face-table.cpp:48
FaceManager(FaceTable &faceTable, Dispatcher &dispatcher, CommandValidator &validator)
void wireDecode(const Block &wire)
decode FaceQueryFilter
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
const PacketCounter & nOutInterests
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
gives access to counters provided by Face
size_t wireEncode(EncodingImpl< TAG > &encoder) const
const PacketCounter & nInNacks
ChannelStatus & setLocalUri(const std::string localUri)
const Name & getName() const
Definition: interest.hpp:218
const PacketCounter & nInData