blob: 701bddd73ae4544941514d5bfa9091ee51f69555 [file] [log] [blame]
Steve DiBenedettoabe9e972014-02-20 15:37:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "face-manager.hpp"
8
9#include "core/face-uri.hpp"
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060010#include "core/network-interface.hpp"
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070011#include "fw/face-table.hpp"
12
13#include "face/tcp-factory.hpp"
14#include "face/udp-factory.hpp"
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060015
16#ifdef HAVE_UNIX_SOCKETS
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070017#include "face/unix-stream-factory.hpp"
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060018#endif // HAVE_UNIX_SOCKETS
19
20#ifdef HAVE_PCAP
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070021#include "face/ethernet-factory.hpp"
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060022#endif // HAVE_PCAP
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070023
24namespace nfd {
25
26NFD_LOG_INIT("FaceManager");
27
28const Name FaceManager::COMMAND_PREFIX = "/localhost/nfd/faces";
29
30const size_t FaceManager::COMMAND_UNSIGNED_NCOMPS =
31 FaceManager::COMMAND_PREFIX.size() +
32 1 + // verb
33 1; // verb options
34
35const size_t FaceManager::COMMAND_SIGNED_NCOMPS =
36 FaceManager::COMMAND_UNSIGNED_NCOMPS +
Steve DiBenedetto2c2b8892014-02-27 11:46:48 -070037 4; // (timestamp, nonce, signed info tlv, signature tlv)
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070038
39const FaceManager::VerbAndProcessor FaceManager::COMMAND_VERBS[] =
40 {
41 VerbAndProcessor(
42 Name::Component("create"),
43 &FaceManager::createFace
44 ),
45
46 VerbAndProcessor(
47 Name::Component("destroy"),
48 &FaceManager::destroyFace
49 ),
50 };
51
52
53
54FaceManager::FaceManager(FaceTable& faceTable,
Steve DiBenedetto2c2b8892014-02-27 11:46:48 -070055 shared_ptr<InternalFace> face)
56 : ManagerBase(face, FACE_MANAGER_PRIVILEGE)
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070057 , m_faceTable(faceTable)
58 , m_verbDispatch(COMMAND_VERBS,
59 COMMAND_VERBS +
60 (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
61{
62 face->setInterestFilter("/localhost/nfd/faces",
63 bind(&FaceManager::onFaceRequest, this, _2));
64}
65
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060066FaceManager::~FaceManager()
67{
68
69}
70
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070071void
72FaceManager::setConfigFile(ConfigFile& configFile)
73{
74 configFile.addSectionHandler("face_system",
75 bind(&FaceManager::onConfig, this, _1, _2));
76}
77
78
79void
80FaceManager::onConfig(const ConfigSection& configSection, bool isDryRun)
81{
82 bool hasSeenUnix = false;
83 bool hasSeenTcp = false;
84 bool hasSeenUdp = false;
85 bool hasSeenEther = false;
86
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -060087 const std::list<shared_ptr<NetworkInterfaceInfo> > nicList(listNetworkInterfaces());
88
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070089 for (ConfigSection::const_iterator item = configSection.begin();
90 item != configSection.end();
91 ++item)
92 {
93 if (item->first == "unix")
94 {
95 if (hasSeenUnix)
96 throw Error("Duplicate \"unix\" section");
97 hasSeenUnix = true;
98
99 processSectionUnix(item->second, isDryRun);
100 }
101 else if (item->first == "tcp")
102 {
103 if (hasSeenTcp)
104 throw Error("Duplicate \"tcp\" section");
105 hasSeenTcp = true;
106
107 processSectionTcp(item->second, isDryRun);
108 }
109 else if (item->first == "udp")
110 {
111 if (hasSeenUdp)
112 throw Error("Duplicate \"udp\" section");
113 hasSeenUdp = true;
114
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600115 processSectionUdp(item->second, isDryRun, nicList);
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700116 }
117 else if (item->first == "ether")
118 {
119 if (hasSeenEther)
120 throw Error("Duplicate \"ether\" section");
121 hasSeenEther = true;
122
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600123 processSectionEther(item->second, isDryRun, nicList);
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700124 }
125 else
126 {
127 throw Error("Unrecognized option \"" + item->first + "\"");
128 }
129 }
130}
131
132void
133FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
134{
135 // ; the unix section contains settings of UNIX stream faces and channels
136 // unix
137 // {
138 // listen yes ; set to 'no' to disable UNIX stream listener, default 'yes'
139 // path /var/run/nfd.sock ; UNIX stream listener path
140 // }
141
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600142#if defined(HAVE_UNIX_SOCKETS)
143
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700144 bool needToListen = true;
145 std::string path = "/var/run/nfd.sock";
146
147 for (ConfigSection::const_iterator i = configSection.begin();
148 i != configSection.end();
149 ++i)
150 {
151 if (i->first == "path")
152 {
153 path = i->second.get_value<std::string>();
154 }
155 else if (i->first == "listen")
156 {
157 needToListen = parseYesNo(i, i->first, "unix");
158 }
159 else
160 {
161 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"unix\" section");
162 }
163 }
164
165 if (!isDryRun)
166 {
167 shared_ptr<UnixStreamFactory> factory = make_shared<UnixStreamFactory>();
168 shared_ptr<UnixStreamChannel> unixChannel = factory->createChannel(path);
169
170 if (needToListen)
171 {
172 // Should acceptFailed callback be used somehow?
173 unixChannel->listen(bind(&FaceTable::add, &m_faceTable, _1),
174 UnixStreamChannel::ConnectFailedCallback());
175 }
176
177 m_factories.insert(std::make_pair("unix", factory));
178 }
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600179#else
180 throw ConfigFile::Error("NFD was compiled without UNIX sockets support, cannot process \"unix\" section");
181#endif // HAVE_UNIX_SOCKETS
182
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700183}
184
185void
186FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
187{
188 // ; the tcp section contains settings of TCP faces and channels
189 // tcp
190 // {
191 // listen yes ; set to 'no' to disable TCP listener, default 'yes'
192 // port 6363 ; TCP listener port number
193 // }
194
195 std::string port = "6363";
196 bool needToListen = true;
197
198 for (ConfigSection::const_iterator i = configSection.begin();
199 i != configSection.end();
200 ++i)
201 {
202 if (i->first == "port")
203 {
204 port = i->second.get_value<std::string>();
205 }
206 else if (i->first == "listen")
207 {
208 needToListen = parseYesNo(i, i->first, "tcp");
209 }
210 else
211 {
212 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"tcp\" section");
213 }
214 }
215
216 if (!isDryRun)
217 {
218 shared_ptr<TcpFactory> factory = make_shared<TcpFactory>(boost::cref(port));
219
220 using namespace boost::asio::ip;
221
222 shared_ptr<TcpChannel> ipv4Channel = factory->createChannel("0.0.0.0", port);
223 shared_ptr<TcpChannel> ipv6Channel = factory->createChannel("::", port);
224
225 if (needToListen)
226 {
227 // Should acceptFailed callback be used somehow?
228
229 ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
230 TcpChannel::ConnectFailedCallback());
231 ipv6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
232 TcpChannel::ConnectFailedCallback());
233 }
234
235 m_factories.insert(std::make_pair("tcp", factory));
236 m_factories.insert(std::make_pair("tcp4", factory));
237 m_factories.insert(std::make_pair("tcp6", factory));
238 }
239}
240
241void
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600242FaceManager::processSectionUdp(const ConfigSection& configSection,
243 bool isDryRun,
244 const std::list<shared_ptr<NetworkInterfaceInfo> >& nicList)
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700245{
246 // ; the udp section contains settings of UDP faces and channels
247 // udp
248 // {
249 // port 6363 ; UDP unicast port number
250 // idle_timeout 30 ; idle time (seconds) before closing a UDP unicast face
251 // keep_alive_interval 25; interval (seconds) between keep-alive refreshes
252
253 // ; NFD creates one UDP multicast face per NIC
254 // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
255 // mcast_port 56363 ; UDP multicast port number
256 // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
257 // }
258
259 std::string port = "6363";
260 size_t timeout = 30;
261 size_t keepAliveInterval = 25;
262 bool useMcast = true;
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600263 std::string mcastGroup = "224.0.23.170";
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700264 std::string mcastPort = "56363";
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600265
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700266
267 for (ConfigSection::const_iterator i = configSection.begin();
268 i != configSection.end();
269 ++i)
270 {
271 if (i->first == "port")
272 {
273 port = i->second.get_value<std::string>();
274 }
275 else if (i->first == "idle_timeout")
276 {
277 try
278 {
279 timeout = i->second.get_value<size_t>();
280 }
281 catch (const std::exception& e)
282 {
283 throw ConfigFile::Error("Invalid value for option \"" +
284 i->first + "\" in \"udp\" section");
285 }
286 }
287 else if (i->first == "keep_alive_interval")
288 {
289 try
290 {
291 keepAliveInterval = i->second.get_value<size_t>();
292 }
293 catch (const std::exception& e)
294 {
295 throw ConfigFile::Error("Invalid value for option \"" +
296 i->first + "\" in \"udp\" section");
297 }
298 }
299 else if (i->first == "mcast")
300 {
301 useMcast = parseYesNo(i, i->first, "udp");
302 }
303 else if (i->first == "mcast_port")
304 {
305 mcastPort = i->second.get_value<std::string>();
306 }
307 else if (i->first == "mcast_group")
308 {
309 using namespace boost::asio::ip;
310 mcastGroup = i->second.get_value<std::string>();
311 try
312 {
313 address mcastGroupTest = address::from_string(mcastGroup);
314 if (!mcastGroupTest.is_v4())
315 {
316 throw ConfigFile::Error("Invalid value for option \"" +
317 i->first + "\" in \"udp\" section");
318 }
319 }
320 catch(const std::runtime_error& e)
321 {
322 throw ConfigFile::Error("Invalid value for option \"" +
323 i->first + "\" in \"udp\" section");
324 }
325 }
326 else
327 {
328 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"udp\" section");
329 }
330 }
331
332 /// \todo what is keep alive interval used for?
333
334 if (!isDryRun)
335 {
336 shared_ptr<UdpFactory> factory = make_shared<UdpFactory>(boost::cref(port));
337
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600338 factory->createChannel("::", port, time::seconds(timeout));
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700339
340 m_factories.insert(std::make_pair("udp", factory));
341 m_factories.insert(std::make_pair("udp4", factory));
342 m_factories.insert(std::make_pair("udp6", factory));
343
344 if (useMcast)
345 {
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600346 bool useEndpoint = false;
347 udp::Endpoint localEndpoint;
348
349 try
350 {
351 localEndpoint.port(boost::lexical_cast<uint16_t>(port));
352 useEndpoint = true;
353 }
354 catch (const boost::bad_lexical_cast& error)
355 {
356 NFD_LOG_DEBUG("Treating UDP port \"" << port << "\" as a service name");
357 }
358
359 for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i = nicList.begin();
360 i != nicList.end();
361 ++i)
362 {
363 const shared_ptr<NetworkInterfaceInfo>& nic = *i;
364 if (nic->isUp() && nic->isMulticastCapable() && !nic->ipv4Addresses.empty())
365 {
366 shared_ptr<MulticastUdpFace> newFace =
367 factory->createMulticastFace(nic->ipv4Addresses[0].to_string(),
368 mcastGroup, mcastPort);
369
370 NFD_LOG_INFO("Created multicast Face ID " << newFace->getId());
371
372 if (useEndpoint)
373 {
374 for (std::vector<boost::asio::ip::address_v4>::const_iterator j =
375 nic->ipv4Addresses.begin();
376 j != nic->ipv4Addresses.end();
377 ++j)
378 {
379 localEndpoint.address(*j);
380 factory->createChannel(localEndpoint, time::seconds(timeout));
381 }
382 }
383 else
384 {
385 for (std::vector<boost::asio::ip::address_v4>::const_iterator j =
386 nic->ipv4Addresses.begin();
387 j != nic->ipv4Addresses.end();
388 ++j)
389 {
390 factory->createChannel(j->to_string(), port, time::seconds(timeout));
391 }
392 }
393 }
394 }
395 }
396 else
397 {
398 factory->createChannel("0.0.0.0", port, time::seconds(timeout));
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700399 }
400 }
401}
402
403void
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600404FaceManager::processSectionEther(const ConfigSection& configSection,
405 bool isDryRun,
406 const std::list<shared_ptr<NetworkInterfaceInfo> >& nicList)
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700407{
408 // ; the ether section contains settings of Ethernet faces and channels
409 // ether
410 // {
411 // ; NFD creates one Ethernet multicast face per NIC
412 // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
413 // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
414 // }
415
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600416#if defined(HAVE_PCAP)
417
418 using ethernet::Address;
419
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700420 bool useMcast = true;
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600421 Address mcastGroup(ethernet::getDefaultMulticastAddress());
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700422
423 for (ConfigSection::const_iterator i = configSection.begin();
424 i != configSection.end();
425 ++i)
426 {
427 if (i->first == "mcast")
428 {
429 useMcast = parseYesNo(i, i->first, "ether");
430 }
431
432 else if (i->first == "mcast_group")
433 {
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600434 mcastGroup = Address::fromString(i->second.get_value<std::string>());
435 if (mcastGroup.isNull())
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700436 {
437 throw ConfigFile::Error("Invalid value for option \"" +
438 i->first + "\" in \"ether\" section");
439 }
440 }
441 else
442 {
443 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"ether\" section");
444 }
445 }
446
447 if (!isDryRun)
448 {
449 shared_ptr<EthernetFactory> factory = make_shared<EthernetFactory>();
450 m_factories.insert(std::make_pair("ether", factory));
451
452 if (useMcast)
453 {
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600454 for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i = nicList.begin();
455 i != nicList.end();
456 ++i)
457 {
458 const shared_ptr<NetworkInterfaceInfo>& nic = *i;
459 if (nic->isUp() && nic->isMulticastCapable())
460 {
461 try
462 {
463 shared_ptr<EthernetFace> newFace =
464 factory->createMulticastFace(nic->name, mcastGroup);
465 NFD_LOG_INFO("Created multicast Face ID " << newFace->getId());
466 }
467 catch (const EthernetFactory::Error& factoryError)
468 {
469 NFD_LOG_ERROR(factoryError.what() << ", continuing");
470 }
471 catch (const EthernetFace::Error& faceError)
472 {
473 NFD_LOG_ERROR(faceError.what() << ", continuing");
474 }
475 }
476 }
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700477 }
478 }
Steve DiBenedetto4aca99c2014-03-11 11:27:54 -0600479#else
480 throw ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section");
481#endif // HAVE_PCAP
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700482}
483
484
485void
486FaceManager::onFaceRequest(const Interest& request)
487{
488 const Name& command = request.getName();
489 const size_t commandNComps = command.size();
490
491 if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
492 commandNComps < COMMAND_SIGNED_NCOMPS)
493 {
494 NFD_LOG_INFO("command result: unsigned verb: " << command);
495 sendResponse(command, 401, "Signature required");
496
497 return;
498 }
499 else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
500 !COMMAND_PREFIX.isPrefixOf(command))
501 {
502 NFD_LOG_INFO("command result: malformed");
503 sendResponse(command, 400, "Malformed command");
504 return;
505 }
506
Steve DiBenedetto2c2b8892014-02-27 11:46:48 -0700507 validate(request,
508 bind(&FaceManager::onValidatedFaceRequest, this, _1),
509 bind(&ManagerBase::onCommandValidationFailed, this, _1, _2));
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700510}
511
512void
513FaceManager::onValidatedFaceRequest(const shared_ptr<const Interest>& request)
514{
515 const Name& command = request->getName();
516 const Name::Component& verb = command.get(COMMAND_PREFIX.size());
517
518 VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find (verb);
519 if (verbProcessor != m_verbDispatch.end())
520 {
521 ndn::nfd::FaceManagementOptions options;
522 if (!extractOptions(*request, options))
523 {
524 sendResponse(command, 400, "Malformed command");
525 return;
526 }
527
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700528 NFD_LOG_INFO("command result: processing verb: " << verb);
529 (verbProcessor->second)(this, command, options);
530 }
531 else
532 {
533 NFD_LOG_INFO("command result: unsupported verb: " << verb);
534 sendResponse(command, 501, "Unsupported command");
535 }
536
537}
538
539bool
540FaceManager::extractOptions(const Interest& request,
541 ndn::nfd::FaceManagementOptions& extractedOptions)
542{
543 const Name& command = request.getName();
544 const size_t optionCompIndex =
545 COMMAND_PREFIX.size() + 1;
546
547 try
548 {
549 Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
550 extractedOptions.wireDecode(rawOptions);
551 }
552 catch (const ndn::Tlv::Error& e)
553 {
554 NFD_LOG_INFO("Bad command option parse: " << command);
555 return false;
556 }
557 NFD_LOG_DEBUG("Options parsed OK");
558 return true;
559}
560
561void
562FaceManager::onCreated(const Name& requestName,
563 ndn::nfd::FaceManagementOptions& options,
564 const shared_ptr<Face>& newFace)
565{
566 m_faceTable.add(newFace);
567 options.setFaceId(newFace->getId());
568
569 NFD_LOG_INFO("Created Face ID " << newFace->getId());
570
571 ndn::nfd::ControlResponse response;
572 setResponse(response, 200, "Success", options.wireEncode());
573 sendResponse(requestName, response);
574}
575
576void
577FaceManager::onConnectFailed(const Name& requestName, const std::string& reason)
578{
579 NFD_LOG_INFO("Failed to create face: " << reason);
580 sendResponse(requestName, 400, "Failed to create face");
581}
582
583void
584FaceManager::createFace(const Name& requestName,
585 ndn::nfd::FaceManagementOptions& options)
586{
587 FaceUri uri;
588 if (!uri.parse(options.getUri()))
589 {
590 sendResponse(requestName, 400, "Malformed command");
591 return;
592 }
593
594 FactoryMap::iterator factory = m_factories.find(uri.getScheme());
595 if (factory == m_factories.end())
596 {
597 sendResponse(requestName, 501, "Unsupported protocol");
598 return;
599 }
600
601 factory->second->createFace(uri,
602 bind(&FaceManager::onCreated, this, requestName, options, _1),
603 bind(&FaceManager::onConnectFailed, this, requestName, _1));
604}
605
606
607void
608FaceManager::destroyFace(const Name& requestName,
609 ndn::nfd::FaceManagementOptions& options)
610{
611 shared_ptr<Face> target = m_faceTable.get(options.getFaceId());
612 if (target)
613 {
614 m_faceTable.remove(target);
615 target->close();
616 }
617 sendResponse(requestName, 200, "Success");
618}
619
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700620
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700621
622} // namespace nfd