blob: 9874176ecc519a3d3e2e1ab8607bc0e7fb15a91d [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"
10#include "fw/face-table.hpp"
11
12#include "face/tcp-factory.hpp"
13#include "face/udp-factory.hpp"
14#include "face/unix-stream-factory.hpp"
15#include "face/ethernet-factory.hpp"
16
17#ifdef __linux__
18#include <netinet/ether.h>
19#else
20#include <net/ethernet.h>
21#endif
22
23
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
66void
67FaceManager::setConfigFile(ConfigFile& configFile)
68{
69 configFile.addSectionHandler("face_system",
70 bind(&FaceManager::onConfig, this, _1, _2));
71}
72
73
74void
75FaceManager::onConfig(const ConfigSection& configSection, bool isDryRun)
76{
77 bool hasSeenUnix = false;
78 bool hasSeenTcp = false;
79 bool hasSeenUdp = false;
80 bool hasSeenEther = false;
81
82 for (ConfigSection::const_iterator item = configSection.begin();
83 item != configSection.end();
84 ++item)
85 {
86 if (item->first == "unix")
87 {
88 if (hasSeenUnix)
89 throw Error("Duplicate \"unix\" section");
90 hasSeenUnix = true;
91
92 processSectionUnix(item->second, isDryRun);
93 }
94 else if (item->first == "tcp")
95 {
96 if (hasSeenTcp)
97 throw Error("Duplicate \"tcp\" section");
98 hasSeenTcp = true;
99
100 processSectionTcp(item->second, isDryRun);
101 }
102 else if (item->first == "udp")
103 {
104 if (hasSeenUdp)
105 throw Error("Duplicate \"udp\" section");
106 hasSeenUdp = true;
107
108 processSectionUdp(item->second, isDryRun);
109 }
110 else if (item->first == "ether")
111 {
112 if (hasSeenEther)
113 throw Error("Duplicate \"ether\" section");
114 hasSeenEther = true;
115
116 processSectionEther(item->second, isDryRun);
117 }
118 else
119 {
120 throw Error("Unrecognized option \"" + item->first + "\"");
121 }
122 }
123}
124
125void
126FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
127{
128 // ; the unix section contains settings of UNIX stream faces and channels
129 // unix
130 // {
131 // listen yes ; set to 'no' to disable UNIX stream listener, default 'yes'
132 // path /var/run/nfd.sock ; UNIX stream listener path
133 // }
134
135 bool needToListen = true;
136 std::string path = "/var/run/nfd.sock";
137
138 for (ConfigSection::const_iterator i = configSection.begin();
139 i != configSection.end();
140 ++i)
141 {
142 if (i->first == "path")
143 {
144 path = i->second.get_value<std::string>();
145 }
146 else if (i->first == "listen")
147 {
148 needToListen = parseYesNo(i, i->first, "unix");
149 }
150 else
151 {
152 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"unix\" section");
153 }
154 }
155
156 if (!isDryRun)
157 {
158 shared_ptr<UnixStreamFactory> factory = make_shared<UnixStreamFactory>();
159 shared_ptr<UnixStreamChannel> unixChannel = factory->createChannel(path);
160
161 if (needToListen)
162 {
163 // Should acceptFailed callback be used somehow?
164 unixChannel->listen(bind(&FaceTable::add, &m_faceTable, _1),
165 UnixStreamChannel::ConnectFailedCallback());
166 }
167
168 m_factories.insert(std::make_pair("unix", factory));
169 }
170}
171
172void
173FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
174{
175 // ; the tcp section contains settings of TCP faces and channels
176 // tcp
177 // {
178 // listen yes ; set to 'no' to disable TCP listener, default 'yes'
179 // port 6363 ; TCP listener port number
180 // }
181
182 std::string port = "6363";
183 bool needToListen = true;
184
185 for (ConfigSection::const_iterator i = configSection.begin();
186 i != configSection.end();
187 ++i)
188 {
189 if (i->first == "port")
190 {
191 port = i->second.get_value<std::string>();
192 }
193 else if (i->first == "listen")
194 {
195 needToListen = parseYesNo(i, i->first, "tcp");
196 }
197 else
198 {
199 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"tcp\" section");
200 }
201 }
202
203 if (!isDryRun)
204 {
205 shared_ptr<TcpFactory> factory = make_shared<TcpFactory>(boost::cref(port));
206
207 using namespace boost::asio::ip;
208
209 shared_ptr<TcpChannel> ipv4Channel = factory->createChannel("0.0.0.0", port);
210 shared_ptr<TcpChannel> ipv6Channel = factory->createChannel("::", port);
211
212 if (needToListen)
213 {
214 // Should acceptFailed callback be used somehow?
215
216 ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
217 TcpChannel::ConnectFailedCallback());
218 ipv6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
219 TcpChannel::ConnectFailedCallback());
220 }
221
222 m_factories.insert(std::make_pair("tcp", factory));
223 m_factories.insert(std::make_pair("tcp4", factory));
224 m_factories.insert(std::make_pair("tcp6", factory));
225 }
226}
227
228void
229FaceManager::processSectionUdp(const ConfigSection& configSection, bool isDryRun)
230{
231 // ; the udp section contains settings of UDP faces and channels
232 // udp
233 // {
234 // port 6363 ; UDP unicast port number
235 // idle_timeout 30 ; idle time (seconds) before closing a UDP unicast face
236 // keep_alive_interval 25; interval (seconds) between keep-alive refreshes
237
238 // ; NFD creates one UDP multicast face per NIC
239 // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
240 // mcast_port 56363 ; UDP multicast port number
241 // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
242 // }
243
244 std::string port = "6363";
245 size_t timeout = 30;
246 size_t keepAliveInterval = 25;
247 bool useMcast = true;
248 std::string mcastPort = "56363";
249 std::string mcastGroup;
250
251 for (ConfigSection::const_iterator i = configSection.begin();
252 i != configSection.end();
253 ++i)
254 {
255 if (i->first == "port")
256 {
257 port = i->second.get_value<std::string>();
258 }
259 else if (i->first == "idle_timeout")
260 {
261 try
262 {
263 timeout = i->second.get_value<size_t>();
264 }
265 catch (const std::exception& e)
266 {
267 throw ConfigFile::Error("Invalid value for option \"" +
268 i->first + "\" in \"udp\" section");
269 }
270 }
271 else if (i->first == "keep_alive_interval")
272 {
273 try
274 {
275 keepAliveInterval = i->second.get_value<size_t>();
276 }
277 catch (const std::exception& e)
278 {
279 throw ConfigFile::Error("Invalid value for option \"" +
280 i->first + "\" in \"udp\" section");
281 }
282 }
283 else if (i->first == "mcast")
284 {
285 useMcast = parseYesNo(i, i->first, "udp");
286 }
287 else if (i->first == "mcast_port")
288 {
289 mcastPort = i->second.get_value<std::string>();
290 }
291 else if (i->first == "mcast_group")
292 {
293 using namespace boost::asio::ip;
294 mcastGroup = i->second.get_value<std::string>();
295 try
296 {
297 address mcastGroupTest = address::from_string(mcastGroup);
298 if (!mcastGroupTest.is_v4())
299 {
300 throw ConfigFile::Error("Invalid value for option \"" +
301 i->first + "\" in \"udp\" section");
302 }
303 }
304 catch(const std::runtime_error& e)
305 {
306 throw ConfigFile::Error("Invalid value for option \"" +
307 i->first + "\" in \"udp\" section");
308 }
309 }
310 else
311 {
312 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"udp\" section");
313 }
314 }
315
316 /// \todo what is keep alive interval used for?
317
318 if (!isDryRun)
319 {
320 shared_ptr<UdpFactory> factory = make_shared<UdpFactory>(boost::cref(port));
321
322 shared_ptr<UdpChannel> ipv4Channel =
323 factory->createChannel("0.0.0.0", port, time::seconds(timeout));
324 shared_ptr<UdpChannel> ipv6Channel =
325 factory->createChannel("::", port, time::seconds(timeout));
326
327 m_factories.insert(std::make_pair("udp", factory));
328 m_factories.insert(std::make_pair("udp4", factory));
329 m_factories.insert(std::make_pair("udp6", factory));
330
331 if (useMcast)
332 {
333 /// \todo create one multicast face per NIC
334 NFD_LOG_WARN("multicast faces are not implemented");
335 }
336 }
337}
338
339void
340FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryRun)
341{
342 // ; the ether section contains settings of Ethernet faces and channels
343 // ether
344 // {
345 // ; NFD creates one Ethernet multicast face per NIC
346 // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
347 // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
348 // }
349
350 bool useMcast = true;
351 std::string mcastGroup;
352
353 for (ConfigSection::const_iterator i = configSection.begin();
354 i != configSection.end();
355 ++i)
356 {
357 if (i->first == "mcast")
358 {
359 useMcast = parseYesNo(i, i->first, "ether");
360 }
361
362 else if (i->first == "mcast_group")
363 {
364 const std::string mcastGroup = i->second.get_value<std::string>();
365 /// \todo change to use ethernet::Address::fromString
366 if (!ether_aton(mcastGroup.c_str()))
367 {
368 throw ConfigFile::Error("Invalid value for option \"" +
369 i->first + "\" in \"ether\" section");
370 }
371 }
372 else
373 {
374 throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"ether\" section");
375 }
376 }
377
378 if (!isDryRun)
379 {
380 shared_ptr<EthernetFactory> factory = make_shared<EthernetFactory>();
381 m_factories.insert(std::make_pair("ether", factory));
382
383 if (useMcast)
384 {
385 /// \todo create one multicast face per NIC
386 NFD_LOG_WARN("multicast faces are not implemented");
387 }
388 }
389}
390
391
392void
393FaceManager::onFaceRequest(const Interest& request)
394{
395 const Name& command = request.getName();
396 const size_t commandNComps = command.size();
397
398 if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
399 commandNComps < COMMAND_SIGNED_NCOMPS)
400 {
401 NFD_LOG_INFO("command result: unsigned verb: " << command);
402 sendResponse(command, 401, "Signature required");
403
404 return;
405 }
406 else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
407 !COMMAND_PREFIX.isPrefixOf(command))
408 {
409 NFD_LOG_INFO("command result: malformed");
410 sendResponse(command, 400, "Malformed command");
411 return;
412 }
413
Steve DiBenedetto2c2b8892014-02-27 11:46:48 -0700414 validate(request,
415 bind(&FaceManager::onValidatedFaceRequest, this, _1),
416 bind(&ManagerBase::onCommandValidationFailed, this, _1, _2));
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700417}
418
419void
420FaceManager::onValidatedFaceRequest(const shared_ptr<const Interest>& request)
421{
422 const Name& command = request->getName();
423 const Name::Component& verb = command.get(COMMAND_PREFIX.size());
424
425 VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find (verb);
426 if (verbProcessor != m_verbDispatch.end())
427 {
428 ndn::nfd::FaceManagementOptions options;
429 if (!extractOptions(*request, options))
430 {
431 sendResponse(command, 400, "Malformed command");
432 return;
433 }
434
Steve DiBenedettoabe9e972014-02-20 15:37:04 -0700435 NFD_LOG_INFO("command result: processing verb: " << verb);
436 (verbProcessor->second)(this, command, options);
437 }
438 else
439 {
440 NFD_LOG_INFO("command result: unsupported verb: " << verb);
441 sendResponse(command, 501, "Unsupported command");
442 }
443
444}
445
446bool
447FaceManager::extractOptions(const Interest& request,
448 ndn::nfd::FaceManagementOptions& extractedOptions)
449{
450 const Name& command = request.getName();
451 const size_t optionCompIndex =
452 COMMAND_PREFIX.size() + 1;
453
454 try
455 {
456 Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
457 extractedOptions.wireDecode(rawOptions);
458 }
459 catch (const ndn::Tlv::Error& e)
460 {
461 NFD_LOG_INFO("Bad command option parse: " << command);
462 return false;
463 }
464 NFD_LOG_DEBUG("Options parsed OK");
465 return true;
466}
467
468void
469FaceManager::onCreated(const Name& requestName,
470 ndn::nfd::FaceManagementOptions& options,
471 const shared_ptr<Face>& newFace)
472{
473 m_faceTable.add(newFace);
474 options.setFaceId(newFace->getId());
475
476 NFD_LOG_INFO("Created Face ID " << newFace->getId());
477
478 ndn::nfd::ControlResponse response;
479 setResponse(response, 200, "Success", options.wireEncode());
480 sendResponse(requestName, response);
481}
482
483void
484FaceManager::onConnectFailed(const Name& requestName, const std::string& reason)
485{
486 NFD_LOG_INFO("Failed to create face: " << reason);
487 sendResponse(requestName, 400, "Failed to create face");
488}
489
490void
491FaceManager::createFace(const Name& requestName,
492 ndn::nfd::FaceManagementOptions& options)
493{
494 FaceUri uri;
495 if (!uri.parse(options.getUri()))
496 {
497 sendResponse(requestName, 400, "Malformed command");
498 return;
499 }
500
501 FactoryMap::iterator factory = m_factories.find(uri.getScheme());
502 if (factory == m_factories.end())
503 {
504 sendResponse(requestName, 501, "Unsupported protocol");
505 return;
506 }
507
508 factory->second->createFace(uri,
509 bind(&FaceManager::onCreated, this, requestName, options, _1),
510 bind(&FaceManager::onConnectFailed, this, requestName, _1));
511}
512
513
514void
515FaceManager::destroyFace(const Name& requestName,
516 ndn::nfd::FaceManagementOptions& options)
517{
518 shared_ptr<Face> target = m_faceTable.get(options.getFaceId());
519 if (target)
520 {
521 m_faceTable.remove(target);
522 target->close();
523 }
524 sendResponse(requestName, 200, "Success");
525}
526
527FaceManager::~FaceManager()
528{
529
530}
531
532} // namespace nfd