blob: b49b752928a2e3c1a4a9984ab2636e04623514c7 [file] [log] [blame]
Yanbiao Li73860e32015-08-19 16:30:16 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "face-manager.hpp"
27
28#include "core/network-interface.hpp"
Yukai Tu0a49d342015-09-13 12:54:22 +080029#include "face/lp-face-wrapper.hpp"
Yanbiao Li73860e32015-08-19 16:30:16 -070030#include "face/tcp-factory.hpp"
31#include "face/udp-factory.hpp"
Yukai Tu0a49d342015-09-13 12:54:22 +080032#include "fw/face-table.hpp"
Yanbiao Li73860e32015-08-19 16:30:16 -070033
34#include <ndn-cxx/management/nfd-face-status.hpp>
35#include <ndn-cxx/management/nfd-channel-status.hpp>
36#include <ndn-cxx/management/nfd-face-event-notification.hpp>
37
38#ifdef HAVE_UNIX_SOCKETS
39#include "face/unix-stream-factory.hpp"
40#endif // HAVE_UNIX_SOCKETS
41
42#ifdef HAVE_LIBPCAP
43#include "face/ethernet-factory.hpp"
44#include "face/ethernet-face.hpp"
45#endif // HAVE_LIBPCAP
46
47#ifdef HAVE_WEBSOCKET
48#include "face/websocket-factory.hpp"
49#endif // HAVE_WEBSOCKET
50
51namespace nfd {
52
53NFD_LOG_INIT("FaceManager");
54
55FaceManager::FaceManager(FaceTable& faceTable,
56 Dispatcher& dispatcher,
57 CommandValidator& validator)
58 : ManagerBase(dispatcher, validator, "faces")
59 , m_faceTable(faceTable)
60{
61 registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
62 bind(&FaceManager::createFace, this, _2, _3, _4, _5));
63
64 registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
65 bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
66
67 registerCommandHandler<ndn::nfd::FaceEnableLocalControlCommand>("enable-local-control",
68 bind(&FaceManager::enableLocalControl, this, _2, _3, _4, _5));
69
70 registerCommandHandler<ndn::nfd::FaceDisableLocalControlCommand>("disable-local-control",
71 bind(&FaceManager::disableLocalControl, this, _2, _3, _4, _5));
72
73 registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
74 registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
75 registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
76
77 auto postNotification = registerNotificationStream("events");
78 m_faceAddConn =
79 m_faceTable.onAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
80 m_faceRemoveConn =
81 m_faceTable.onRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
82}
83
84void
85FaceManager::setConfigFile(ConfigFile& configFile)
86{
87 configFile.addSectionHandler("face_system", bind(&FaceManager::processConfig, this, _1, _2, _3));
88}
89
90void
91FaceManager::createFace(const Name& topPrefix, const Interest& interest,
92 const ControlParameters& parameters,
93 const ndn::mgmt::CommandContinuation& done)
94{
95 FaceUri uri;
96 if (!uri.parse(parameters.getUri())) {
97 NFD_LOG_TRACE("failed to parse URI");
98 return done(ControlResponse(400, "Malformed command"));
99 }
100
101 if (!uri.isCanonical()) {
102 NFD_LOG_TRACE("received non-canonical URI");
103 return done(ControlResponse(400, "Non-canonical URI"));
104 }
105
106 FactoryMap::iterator factory = m_factories.find(uri.getScheme());
107 if (factory == m_factories.end()) {
108 return done(ControlResponse(501, "Unsupported protocol"));
109 }
110
111 try {
112 factory->second->createFace(uri,
113 parameters.getFacePersistency(),
114 bind(&FaceManager::afterCreateFaceSuccess,
115 this, parameters, _1, done),
116 bind(&FaceManager::afterCreateFaceFailure,
117 this, _1, done));
118 }
119 catch (const std::runtime_error& error) {
120 std::string errorMessage = "Face creation failed: ";
121 errorMessage += error.what();
122
123 NFD_LOG_ERROR(errorMessage);
124 return done(ControlResponse(500, errorMessage));
125 }
126 catch (const std::logic_error& error) {
127 std::string errorMessage = "Face creation failed: ";
128 errorMessage += error.what();
129
130 NFD_LOG_ERROR(errorMessage);
131 return done(ControlResponse(500, errorMessage));
132 }
133}
134
135void
136FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
137 const ControlParameters& parameters,
138 const ndn::mgmt::CommandContinuation& done)
139{
140 shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
141 if (target) {
142 target->close();
143 }
144
145 done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
146}
147
148void
149FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
150 const ControlParameters& parameters,
151 const ndn::mgmt::CommandContinuation& done)
152{
153 auto result = extractLocalControlParameters(interest, parameters, done);
154 if (result.isValid) {
155 result.face->setLocalControlHeaderFeature(result.feature, true);
156 return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
157 }
158}
159
160void
161FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
162 const ControlParameters& parameters,
163 const ndn::mgmt::CommandContinuation& done)
164{
165 auto result = extractLocalControlParameters(interest, parameters, done);
166 if (result.isValid) {
167 result.face->setLocalControlHeaderFeature(result.feature, false);
168 return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
169 }
170}
171
172void
173FaceManager::afterCreateFaceSuccess(ControlParameters& parameters,
174 const shared_ptr<Face>& newFace,
175 const ndn::mgmt::CommandContinuation& done)
176{
177 addCreatedFaceToForwarder(newFace);
178 parameters.setFaceId(newFace->getId());
179 parameters.setUri(newFace->getRemoteUri().toString());
180 parameters.setFacePersistency(newFace->getPersistency());
181
182 done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
183}
184
185void
186FaceManager::afterCreateFaceFailure(const std::string& reason,
187 const ndn::mgmt::CommandContinuation& done)
188{
189 NFD_LOG_DEBUG("Failed to create face: " << reason);
190
191 done(ControlResponse(408, "Failed to create face: " + reason));
192}
193
194FaceManager::ExtractLocalControlParametersResult
195FaceManager::extractLocalControlParameters(const Interest& request,
196 const ControlParameters& parameters,
197 const ndn::mgmt::CommandContinuation& done)
198{
199 ExtractLocalControlParametersResult result;
200 result.isValid = false;
201
202 auto face = m_faceTable.get(request.getIncomingFaceId());
203 if (!static_cast<bool>(face)) {
204 NFD_LOG_DEBUG("command result: faceid " << request.getIncomingFaceId() << " not found");
205 done(ControlResponse(410, "Face not found"));
206 return result;
207 }
208
209 if (!face->isLocal()) {
210 NFD_LOG_DEBUG("command result: cannot enable local control on non-local faceid " <<
211 face->getId());
212 done(ControlResponse(412, "Face is non-local"));
213 return result;
214 }
215
216 result.isValid = true;
217 result.face = dynamic_pointer_cast<LocalFace>(face);
218 result.feature = static_cast<LocalControlFeature>(parameters.getLocalControlFeature());
219
220 return result;
221}
222
223void
224FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
225 ndn::mgmt::StatusDatasetContext& context)
226{
227 for (const auto& face : m_faceTable) {
228 context.append(face->getFaceStatus().wireEncode());
229 }
230 context.end();
231}
232
233void
234FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
235 ndn::mgmt::StatusDatasetContext& context)
236{
237 std::set<shared_ptr<ProtocolFactory>> seenFactories;
238
239 for (auto i = m_factories.begin(); i != m_factories.end(); ++i) {
240 const shared_ptr<ProtocolFactory>& factory = i->second;
241
242 if (seenFactories.find(factory) != seenFactories.end()) {
243 continue;
244 }
245 seenFactories.insert(factory);
246
247 std::list<shared_ptr<const Channel>> channels = factory->getChannels();
248
249 for (auto j = channels.begin(); j != channels.end(); ++j) {
250 ndn::nfd::ChannelStatus entry;
251 entry.setLocalUri((*j)->getUri().toString());
252 context.append(entry.wireEncode());
253 }
254 }
255
256 context.end();
257}
258
259void
260FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
261 ndn::mgmt::StatusDatasetContext& context)
262{
263 ndn::nfd::FaceQueryFilter faceFilter;
264 const Name& query = interest.getName();
265 try {
266 faceFilter.wireDecode(query[-1].blockFromValue());
267 }
268 catch (const tlv::Error&) {
269 NFD_LOG_DEBUG("query result: malformed filter");
270 return context.reject(ControlResponse(400, "malformed filter"));
271 }
272
273 for (const auto& face : m_faceTable) {
274 if (doesMatchFilter(faceFilter, face)) {
275 context.append(face->getFaceStatus().wireEncode());
276 }
277 }
278 context.end();
279}
280
281bool
282FaceManager::doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr<Face> face)
283{
284 if (filter.hasFaceId() &&
285 filter.getFaceId() != static_cast<uint64_t>(face->getId())) {
286 return false;
287 }
288
289 if (filter.hasUriScheme() &&
290 filter.getUriScheme() != face->getRemoteUri().getScheme() &&
291 filter.getUriScheme() != face->getLocalUri().getScheme()) {
292 return false;
293 }
294
295 if (filter.hasRemoteUri() &&
296 filter.getRemoteUri() != face->getRemoteUri().toString()) {
297 return false;
298 }
299
300 if (filter.hasLocalUri() &&
301 filter.getLocalUri() != face->getLocalUri().toString()) {
302 return false;
303 }
304
305 if (filter.hasFaceScope() &&
306 (filter.getFaceScope() == ndn::nfd::FACE_SCOPE_LOCAL) != face->isLocal()) {
307 return false;
308 }
309
310 if (filter.hasFacePersistency() &&
311 filter.getFacePersistency() != face->getPersistency()) {
312 return false;
313 }
314
315 if (filter.hasLinkType() &&
316 (filter.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) != face->isMultiAccess()) {
317 return false;
318 }
319
320 return true;
321}
322
323void
324FaceManager::afterFaceAdded(shared_ptr<Face> face,
325 const ndn::mgmt::PostNotification& post)
326{
327 ndn::nfd::FaceEventNotification notification;
328 notification.setKind(ndn::nfd::FACE_EVENT_CREATED);
329 face->copyStatusTo(notification);
330
331 post(notification.wireEncode());
332}
333
334void
335FaceManager::afterFaceRemoved(shared_ptr<Face> face,
336 const ndn::mgmt::PostNotification& post)
337{
338 ndn::nfd::FaceEventNotification notification;
339 notification.setKind(ndn::nfd::FACE_EVENT_DESTROYED);
340 face->copyStatusTo(notification);
341
342 post(notification.wireEncode());
343}
344
345void
346FaceManager::processConfig(const ConfigSection& configSection,
347 bool isDryRun,
348 const std::string& filename)
349{
350 bool hasSeenUnix = false;
351 bool hasSeenTcp = false;
352 bool hasSeenUdp = false;
353 bool hasSeenEther = false;
354 bool hasSeenWebSocket = false;
355
356 const std::vector<NetworkInterfaceInfo> nicList(listNetworkInterfaces());
357
358 for (const auto& item : configSection) {
359 if (item.first == "unix") {
360 if (hasSeenUnix) {
361 BOOST_THROW_EXCEPTION(Error("Duplicate \"unix\" section"));
362 }
363 hasSeenUnix = true;
364
365 processSectionUnix(item.second, isDryRun);
366 }
367 else if (item.first == "tcp") {
368 if (hasSeenTcp) {
369 BOOST_THROW_EXCEPTION(Error("Duplicate \"tcp\" section"));
370 }
371 hasSeenTcp = true;
372
373 processSectionTcp(item.second, isDryRun);
374 }
375 else if (item.first == "udp") {
376 if (hasSeenUdp) {
377 BOOST_THROW_EXCEPTION(Error("Duplicate \"udp\" section"));
378 }
379 hasSeenUdp = true;
380
381 processSectionUdp(item.second, isDryRun, nicList);
382 }
383 else if (item.first == "ether") {
384 if (hasSeenEther) {
385 BOOST_THROW_EXCEPTION(Error("Duplicate \"ether\" section"));
386 }
387 hasSeenEther = true;
388
389 processSectionEther(item.second, isDryRun, nicList);
390 }
391 else if (item.first == "websocket") {
392 if (hasSeenWebSocket) {
393 BOOST_THROW_EXCEPTION(Error("Duplicate \"websocket\" section"));
394 }
395 hasSeenWebSocket = true;
396
397 processSectionWebSocket(item.second, isDryRun);
398 }
399 else {
400 BOOST_THROW_EXCEPTION(Error("Unrecognized option \"" + item.first + "\""));
401 }
402 }
403}
404
405void
406FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
407{
408 // ; the unix section contains settings of Unix stream faces and channels
409 // unix
410 // {
411 // path /var/run/nfd.sock ; Unix stream listener path
412 // }
413
414#if defined(HAVE_UNIX_SOCKETS)
415
416 std::string path = "/var/run/nfd.sock";
417
418 for (auto i = configSection.begin(); i != configSection.end(); ++i) {
419 if (i->first == "path") {
420 path = i->second.get_value<std::string>();
421 }
422 else {
423 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
424 i->first + "\" in \"unix\" section"));
425 }
426 }
427
428 if (!isDryRun) {
429 if (m_factories.count("unix") > 0) {
430 return;
431 }
432
433 shared_ptr<UnixStreamFactory> factory = make_shared<UnixStreamFactory>();
434 shared_ptr<UnixStreamChannel> unixChannel = factory->createChannel(path);
435
436 // Should acceptFailed callback be used somehow?
437 unixChannel->listen(bind(&FaceTable::add, &m_faceTable, _1),
438 UnixStreamChannel::ConnectFailedCallback());
439
440 m_factories.insert(std::make_pair("unix", factory));
441 }
442#else
443 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without Unix sockets support, "
444 "cannot process \"unix\" section"));
445#endif // HAVE_UNIX_SOCKETS
446}
447
448void
449FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
450{
451 // ; the tcp section contains settings of TCP faces and channels
452 // tcp
453 // {
454 // listen yes ; set to 'no' to disable TCP listener, default 'yes'
455 // port 6363 ; TCP listener port number
456 // }
457
458 std::string port = "6363";
459 bool needToListen = true;
460 bool enableV4 = true;
461 bool enableV6 = true;
462
463 for (auto i = configSection.begin(); i != configSection.end(); ++i) {
464 if (i->first == "port") {
465 port = i->second.get_value<std::string>();
466 try {
467 uint16_t portNo = boost::lexical_cast<uint16_t>(port);
468 NFD_LOG_TRACE("TCP port set to " << portNo);
469 }
470 catch (const std::bad_cast& error) {
471 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option " +
472 i->first + "\" in \"tcp\" section"));
473 }
474 }
475 else if (i->first == "listen") {
476 needToListen = ConfigFile::parseYesNo(i, i->first, "tcp");
477 }
478 else if (i->first == "enable_v4") {
479 enableV4 = ConfigFile::parseYesNo(i, i->first, "tcp");
480 }
481 else if (i->first == "enable_v6") {
482 enableV6 = ConfigFile::parseYesNo(i, i->first, "tcp");
483 }
484 else {
485 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
486 i->first + "\" in \"tcp\" section"));
487 }
488 }
489
490 if (!enableV4 && !enableV6) {
491 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 channels have been disabled."
492 " Remove \"tcp\" section to disable TCP channels or"
493 " re-enable at least one channel type."));
494 }
495
496 if (!isDryRun) {
497 if (m_factories.count("tcp") > 0) {
498 return;
499 }
500
501 shared_ptr<TcpFactory> factory = make_shared<TcpFactory>(port);
502 m_factories.insert(std::make_pair("tcp", factory));
503
504 if (enableV4) {
505 shared_ptr<TcpChannel> ipv4Channel = factory->createChannel("0.0.0.0", port);
506 if (needToListen) {
507 // Should acceptFailed callback be used somehow?
508 ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
509 TcpChannel::ConnectFailedCallback());
510 }
511
512 m_factories.insert(std::make_pair("tcp4", factory));
513 }
514
515 if (enableV6) {
516 shared_ptr<TcpChannel> ipv6Channel = factory->createChannel("::", port);
517 if (needToListen) {
518 // Should acceptFailed callback be used somehow?
519 ipv6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
520 TcpChannel::ConnectFailedCallback());
521 }
522
523 m_factories.insert(std::make_pair("tcp6", factory));
524 }
525 }
526}
527
528void
529FaceManager::processSectionUdp(const ConfigSection& configSection,
530 bool isDryRun,
531 const std::vector<NetworkInterfaceInfo>& nicList)
532{
533 // ; the udp section contains settings of UDP faces and channels
534 // udp
535 // {
536 // port 6363 ; UDP unicast port number
537 // idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
538 // keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
539
540 // ; NFD creates one UDP multicast face per NIC
541 // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
542 // mcast_port 56363 ; UDP multicast port number
543 // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
544 // }
545
546 std::string port = "6363";
547 bool enableV4 = true;
548 bool enableV6 = true;
549 size_t timeout = 600;
550 size_t keepAliveInterval = 25;
551 bool useMcast = true;
552 std::string mcastGroup = "224.0.23.170";
553 std::string mcastPort = "56363";
554
555
556 for (auto i = configSection.begin(); i != configSection.end(); ++i) {
557 if (i->first == "port") {
558 port = i->second.get_value<std::string>();
559 try {
560 uint16_t portNo = boost::lexical_cast<uint16_t>(port);
561 NFD_LOG_TRACE("UDP port set to " << portNo);
562 }
563 catch (const std::bad_cast& error) {
564 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option " +
565 i->first + "\" in \"udp\" section"));
566 }
567 }
568 else if (i->first == "enable_v4") {
569 enableV4 = ConfigFile::parseYesNo(i, i->first, "udp");
570 }
571 else if (i->first == "enable_v6") {
572 enableV6 = ConfigFile::parseYesNo(i, i->first, "udp");
573 }
574 else if (i->first == "idle_timeout") {
575 try {
576 timeout = i->second.get_value<size_t>();
577 }
578 catch (const std::exception& e) {
579 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
580 i->first + "\" in \"udp\" section"));
581 }
582 }
583 else if (i->first == "keep_alive_interval") {
584 try {
585 keepAliveInterval = i->second.get_value<size_t>();
586
587 /// \todo Make use of keepAliveInterval
588 /// \todo what is keep alive interval used for?
589 (void)(keepAliveInterval);
590 }
591 catch (const std::exception& e) {
592 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
593 i->first + "\" in \"udp\" section"));
594 }
595 }
596 else if (i->first == "mcast") {
597 useMcast = ConfigFile::parseYesNo(i, i->first, "udp");
598 }
599 else if (i->first == "mcast_port") {
600 mcastPort = i->second.get_value<std::string>();
601 try {
602 uint16_t portNo = boost::lexical_cast<uint16_t>(mcastPort);
603 NFD_LOG_TRACE("UDP multicast port set to " << portNo);
604 }
605 catch (const std::bad_cast& error) {
606 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option " +
607 i->first + "\" in \"udp\" section"));
608 }
609 }
610 else if (i->first == "mcast_group") {
611 using namespace boost::asio::ip;
612 mcastGroup = i->second.get_value<std::string>();
613 try {
614 address mcastGroupTest = address::from_string(mcastGroup);
615 if (!mcastGroupTest.is_v4()) {
616 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
617 i->first + "\" in \"udp\" section"));
618 }
619 }
620 catch(const std::runtime_error& e) {
621 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
622 i->first + "\" in \"udp\" section"));
623 }
624 }
625 else {
626 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
627 i->first + "\" in \"udp\" section"));
628 }
629 }
630
631 if (!enableV4 && !enableV6) {
632 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 channels have been disabled."
633 " Remove \"udp\" section to disable UDP channels or"
634 " re-enable at least one channel type."));
635 }
636 else if (useMcast && !enableV4) {
637 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 multicast requested, but IPv4 channels"
638 " have been disabled (conflicting configuration options set)"));
639 }
640
641 if (!isDryRun) {
642 shared_ptr<UdpFactory> factory;
643 bool isReload = false;
644 if (m_factories.count("udp") > 0) {
645 isReload = true;
646 factory = static_pointer_cast<UdpFactory>(m_factories["udp"]);
647 }
648 else {
649 factory = make_shared<UdpFactory>(port);
650 m_factories.insert(std::make_pair("udp", factory));
651 }
652
653 if (!isReload && enableV4) {
654 shared_ptr<UdpChannel> v4Channel =
655 factory->createChannel("0.0.0.0", port, time::seconds(timeout));
656
657 v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
658 UdpChannel::ConnectFailedCallback());
659
660 m_factories.insert(std::make_pair("udp4", factory));
661 }
662
663 if (!isReload && enableV6) {
664 shared_ptr<UdpChannel> v6Channel =
665 factory->createChannel("::", port, time::seconds(timeout));
666
667 v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
668 UdpChannel::ConnectFailedCallback());
669 m_factories.insert(std::make_pair("udp6", factory));
670 }
671
672 if (useMcast && enableV4) {
673 std::vector<NetworkInterfaceInfo> ipv4MulticastInterfaces;
674 for (const auto& nic : nicList) {
675 if (nic.isUp() && nic.isMulticastCapable() && !nic.ipv4Addresses.empty()) {
676 ipv4MulticastInterfaces.push_back(nic);
677 }
678 }
679
680 bool isNicNameNecessary = false;
681#if defined(__linux__)
682 if (ipv4MulticastInterfaces.size() > 1) {
683 // On Linux if we have more than one MulticastUdpFace
684 // we need to specify the name of the interface
685 isNicNameNecessary = true;
686 }
687#endif
688
Yukai Tu0a49d342015-09-13 12:54:22 +0800689 std::list<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
Yanbiao Li73860e32015-08-19 16:30:16 -0700690 for (auto i = factory->getMulticastFaces().begin();
691 i != factory->getMulticastFaces().end();
692 ++i) {
693 multicastFacesToRemove.push_back(i->second);
694 }
695
696 for (const auto& nic : ipv4MulticastInterfaces) {
Yukai Tu0a49d342015-09-13 12:54:22 +0800697 auto newFace = factory->createMulticastFace(nic.ipv4Addresses[0].to_string(),
698 mcastGroup, mcastPort,
699 isNicNameNecessary ? nic.name : "");
Yanbiao Li73860e32015-08-19 16:30:16 -0700700 addCreatedFaceToForwarder(newFace);
701 multicastFacesToRemove.remove(newFace);
702 }
703
Yukai Tu0a49d342015-09-13 12:54:22 +0800704 for (const auto& face : multicastFacesToRemove) {
705 face->close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700706 }
707 }
708 else {
Yukai Tu0a49d342015-09-13 12:54:22 +0800709 std::list<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
Yanbiao Li73860e32015-08-19 16:30:16 -0700710 for (auto i = factory->getMulticastFaces().begin();
711 i != factory->getMulticastFaces().end();
712 ++i) {
713 multicastFacesToRemove.push_back(i->second);
714 }
715
Yukai Tu0a49d342015-09-13 12:54:22 +0800716 for (const auto& face : multicastFacesToRemove) {
717 face->close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700718 }
719 }
720 }
721}
722
723void
724FaceManager::processSectionEther(const ConfigSection& configSection,
725 bool isDryRun,
726 const std::vector<NetworkInterfaceInfo>& nicList)
727{
728 // ; the ether section contains settings of Ethernet faces and channels
729 // ether
730 // {
731 // ; NFD creates one Ethernet multicast face per NIC
732 // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
733 // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
734 // }
735
736#if defined(HAVE_LIBPCAP)
737 bool useMcast = true;
738 ethernet::Address mcastGroup(ethernet::getDefaultMulticastAddress());
739
740 for (auto i = configSection.begin(); i != configSection.end(); ++i) {
741 if (i->first == "mcast") {
742 useMcast = ConfigFile::parseYesNo(i, i->first, "ether");
743 }
744 else if (i->first == "mcast_group") {
745 mcastGroup = ethernet::Address::fromString(i->second.get_value<std::string>());
746 if (mcastGroup.isNull()) {
747 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
748 i->first + "\" in \"ether\" section"));
749 }
750 }
751 else {
752 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
753 i->first + "\" in \"ether\" section"));
754 }
755 }
756
757 if (!isDryRun) {
758 shared_ptr<EthernetFactory> factory;
759 if (m_factories.count("ether") > 0) {
760 factory = static_pointer_cast<EthernetFactory>(m_factories["ether"]);
761 }
762 else {
763 factory = make_shared<EthernetFactory>();
764 m_factories.insert(std::make_pair("ether", factory));
765 }
766
767 if (useMcast) {
768 std::list<shared_ptr<EthernetFace> > multicastFacesToRemove;
769 for (auto i = factory->getMulticastFaces().begin();
770 i != factory->getMulticastFaces().end();
771 ++i) {
772 multicastFacesToRemove.push_back(i->second);
773 }
774
775 for (const auto& nic : nicList) {
776 if (nic.isUp() && nic.isMulticastCapable()) {
777 try {
778 shared_ptr<EthernetFace> newFace =
779 factory->createMulticastFace(nic, mcastGroup);
780
781 addCreatedFaceToForwarder(newFace);
782 multicastFacesToRemove.remove(newFace);
783 }
784 catch (const EthernetFactory::Error& factoryError) {
785 NFD_LOG_ERROR(factoryError.what() << ", continuing");
786 }
787 catch (const EthernetFace::Error& faceError) {
788 NFD_LOG_ERROR(faceError.what() << ", continuing");
789 }
790 }
791 }
792
793 for (auto i = multicastFacesToRemove.begin();
794 i != multicastFacesToRemove.end();
795 ++i) {
796 (*i)->close();
797 }
798 }
799 else {
800 std::list<shared_ptr<EthernetFace> > multicastFacesToRemove;
801 for (auto i = factory->getMulticastFaces().begin();
802 i != factory->getMulticastFaces().end();
803 ++i) {
804 multicastFacesToRemove.push_back(i->second);
805 }
806
807 for (auto i = multicastFacesToRemove.begin();
808 i != multicastFacesToRemove.end();
809 ++i) {
810 (*i)->close();
811 }
812 }
813 }
814#else
815 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section"));
816#endif // HAVE_LIBPCAP
817}
818
819void
820FaceManager::processSectionWebSocket(const ConfigSection& configSection, bool isDryRun)
821{
822 // ; the websocket section contains settings of WebSocket faces and channels
823 // websocket
824 // {
825 // listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
826 // port 9696 ; WebSocket listener port number
827 // enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
828 // enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
829 // }
830
831#if defined(HAVE_WEBSOCKET)
832
833 std::string port = "9696";
834 bool needToListen = true;
835 bool enableV4 = true;
836 bool enableV6 = true;
837
838 for (auto i = configSection.begin(); i != configSection.end(); ++i) {
839 if (i->first == "port") {
840 port = i->second.get_value<std::string>();
841 try {
842 uint16_t portNo = boost::lexical_cast<uint16_t>(port);
843 NFD_LOG_TRACE("WebSocket port set to " << portNo);
844 }
845 catch (const std::bad_cast& error) {
846 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option " +
847 i->first + "\" in \"websocket\" section"));
848 }
849 }
850 else if (i->first == "listen") {
851 needToListen = ConfigFile::parseYesNo(i, i->first, "websocket");
852 }
853 else if (i->first == "enable_v4") {
854 enableV4 = ConfigFile::parseYesNo(i, i->first, "websocket");
855 }
856 else if (i->first == "enable_v6") {
857 enableV6 = ConfigFile::parseYesNo(i, i->first, "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 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 shared_ptr<WebSocketFactory> factory = make_shared<WebSocketFactory>(port);
881 m_factories.insert(std::make_pair("websocket", factory));
882
883 if (enableV6 && enableV4) {
884 shared_ptr<WebSocketChannel> ip46Channel = factory->createChannel("::", port);
885 if (needToListen) {
886 ip46Channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
887 }
888
889 m_factories.insert(std::make_pair("websocket46", factory));
890 }
891 else if (enableV4) {
892 shared_ptr<WebSocketChannel> ipv4Channel = factory->createChannel("0.0.0.0", port);
893 if (needToListen) {
894 ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
895 }
896
897 m_factories.insert(std::make_pair("websocket4", factory));
898 }
899 }
900#else
901 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without WebSocket, "
902 "cannot process \"websocket\" section"));
903#endif // HAVE_WEBSOCKET
904}
905
906void
907FaceManager::addCreatedFaceToForwarder(shared_ptr<Face> newFace)
908{
909 m_faceTable.add(newFace);
910}
911
912} // namespace