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