blob: 2caa74c22a5fba405056e37c03441ddddaa83226 [file] [log] [blame]
Yanbiao Li73860e32015-08-19 16:30:16 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Yanbiao Lidf846e52016-01-30 21:53:47 -08003 * Copyright (c) 2014-2016, Regents of the University of California,
Yanbiao Li73860e32015-08-19 16:30:16 -07004 * 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"
Junxiao Shi40cb61c2015-09-23 18:36:45 -070029#include "face/generic-link-service.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
Junxiao Shicbc8e942016-09-06 03:17:45 +000034#include <ndn-cxx/lp/tags.hpp>
Yanbiao Li73860e32015-08-19 16:30:16 -070035#include <ndn-cxx/management/nfd-channel-status.hpp>
Davide Pesavento1d7e7af2015-10-10 23:54:08 +020036#include <ndn-cxx/management/nfd-face-status.hpp>
Yanbiao Li73860e32015-08-19 16:30:16 -070037#include <ndn-cxx/management/nfd-face-event-notification.hpp>
38
39#ifdef HAVE_UNIX_SOCKETS
40#include "face/unix-stream-factory.hpp"
41#endif // HAVE_UNIX_SOCKETS
42
43#ifdef HAVE_LIBPCAP
44#include "face/ethernet-factory.hpp"
Davide Pesavento35120ea2015-11-17 21:13:18 +010045#include "face/ethernet-transport.hpp"
Yanbiao Li73860e32015-08-19 16:30:16 -070046#endif // HAVE_LIBPCAP
47
48#ifdef HAVE_WEBSOCKET
49#include "face/websocket-factory.hpp"
50#endif // HAVE_WEBSOCKET
51
52namespace nfd {
53
54NFD_LOG_INIT("FaceManager");
55
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000056FaceManager::FaceManager(FaceTable& faceTable, Dispatcher& dispatcher, CommandAuthenticator& authenticator)
57 : NfdManagerBase(dispatcher, authenticator, "faces")
Yanbiao Li73860e32015-08-19 16:30:16 -070058 , m_faceTable(faceTable)
59{
60 registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
61 bind(&FaceManager::createFace, this, _2, _3, _4, _5));
62
Eric Newberryb5aa7f52016-09-03 20:36:12 -070063 registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
64 bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
65
Yanbiao Li73860e32015-08-19 16:30:16 -070066 registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
67 bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
68
69 registerCommandHandler<ndn::nfd::FaceEnableLocalControlCommand>("enable-local-control",
70 bind(&FaceManager::enableLocalControl, this, _2, _3, _4, _5));
71
72 registerCommandHandler<ndn::nfd::FaceDisableLocalControlCommand>("disable-local-control",
73 bind(&FaceManager::disableLocalControl, this, _2, _3, _4, _5));
74
75 registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
76 registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
77 registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
78
Junxiao Shiae04d342016-07-19 13:20:22 +000079 m_postNotification = registerNotificationStream("events");
80 m_faceAddConn = m_faceTable.afterAdd.connect(bind(&FaceManager::notifyAddFace, this, _1));
81 m_faceRemoveConn = m_faceTable.beforeRemove.connect(bind(&FaceManager::notifyRemoveFace, this, _1));
Yanbiao Li73860e32015-08-19 16:30:16 -070082}
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");
Eric Newberry42602412016-08-27 09:33:18 -070098 done(ControlResponse(400, "Malformed command"));
99 return;
Yanbiao Li73860e32015-08-19 16:30:16 -0700100 }
101
102 if (!uri.isCanonical()) {
103 NFD_LOG_TRACE("received non-canonical URI");
Eric Newberry42602412016-08-27 09:33:18 -0700104 done(ControlResponse(400, "Non-canonical URI"));
105 return;
Yanbiao Li73860e32015-08-19 16:30:16 -0700106 }
107
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200108 auto factory = m_factories.find(uri.getScheme());
Yanbiao Li73860e32015-08-19 16:30:16 -0700109 if (factory == m_factories.end()) {
Eric Newberry42602412016-08-27 09:33:18 -0700110 NFD_LOG_TRACE("received create request for unsupported protocol");
111 done(ControlResponse(406, "Unsupported protocol"));
112 return;
Yanbiao Li73860e32015-08-19 16:30:16 -0700113 }
114
115 try {
116 factory->second->createFace(uri,
117 parameters.getFacePersistency(),
118 bind(&FaceManager::afterCreateFaceSuccess,
119 this, parameters, _1, done),
120 bind(&FaceManager::afterCreateFaceFailure,
Eric Newberry42602412016-08-27 09:33:18 -0700121 this, _1, _2, done));
Yanbiao Li73860e32015-08-19 16:30:16 -0700122 }
123 catch (const std::runtime_error& error) {
Eric Newberry42602412016-08-27 09:33:18 -0700124 NFD_LOG_ERROR("Face creation failed: " << error.what());
125 done(ControlResponse(500, "Face creation failed due to internal error"));
126 return;
Yanbiao Li73860e32015-08-19 16:30:16 -0700127 }
128 catch (const std::logic_error& error) {
Eric Newberry42602412016-08-27 09:33:18 -0700129 NFD_LOG_ERROR("Face creation failed: " << error.what());
130 done(ControlResponse(500, "Face creation failed due to internal error"));
131 return;
Yanbiao Li73860e32015-08-19 16:30:16 -0700132 }
133}
134
Eric Newberry42602412016-08-27 09:33:18 -0700135/**
136 * \todo #3232
137 * If the creation of this face would conflict with an existing face (e.g. same underlying
138 * protocol and remote address, or a NIC-associated permanent face), the command will fail
139 * with StatusCode 409.
140 */
Yanbiao Li73860e32015-08-19 16:30:16 -0700141void
Eric Newberry42602412016-08-27 09:33:18 -0700142FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
Yanbiao Li73860e32015-08-19 16:30:16 -0700143 const shared_ptr<Face>& newFace,
144 const ndn::mgmt::CommandContinuation& done)
145{
Eric Newberry42602412016-08-27 09:33:18 -0700146 ControlParameters response;
Yanbiao Li73860e32015-08-19 16:30:16 -0700147
Eric Newberry42602412016-08-27 09:33:18 -0700148 m_faceTable.add(newFace);
149
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700150 // TODO: #3731: Verify and add Flags
151
Eric Newberry42602412016-08-27 09:33:18 -0700152 // Set ControlResponse parameters
153 response.setFaceId(newFace->getId());
154 response.setFacePersistency(newFace->getPersistency());
155
156 done(ControlResponse(200, "OK").setBody(response.wireEncode()));
157}
158
159void
160FaceManager::afterCreateFaceFailure(uint32_t status,
161 const std::string& reason,
162 const ndn::mgmt::CommandContinuation& done)
163{
164 NFD_LOG_DEBUG("Face creation failed: " << reason);
165
166 done(ControlResponse(status, reason));
Yanbiao Li73860e32015-08-19 16:30:16 -0700167}
168
169void
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700170FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
171 const ControlParameters& parameters,
172 const ndn::mgmt::CommandContinuation& done)
173{
174 FaceId faceId = parameters.getFaceId();
175 if (faceId == 0) {
176 // Self-updating
177 shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
178 if (incomingFaceIdTag == nullptr) {
179 NFD_LOG_TRACE("unable to determine face for self-update");
180 done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
181 return;
182 }
183 faceId = *incomingFaceIdTag;
184 }
185
186 Face* face = m_faceTable.get(faceId);
187
188 if (face == nullptr) {
189 NFD_LOG_TRACE("invalid face specified");
190 done(ControlResponse(404, "Specified face does not exist"));
191 return;
192 }
193
194 // Verify validity of requested changes
195 ControlParameters response;
196 bool areParamsValid = true;
197
198 if (parameters.hasFacePersistency()) {
199 // TODO #3232: Add FacePersistency updating
200 NFD_LOG_TRACE("received unsupported face persistency change");
201 areParamsValid = false;
202 response.setFacePersistency(parameters.getFacePersistency());
203 }
204
205 if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
206 parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
207 face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
208 NFD_LOG_TRACE("received request to enable local fields on non-local face");
209 areParamsValid = false;
210 response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
211 parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
212 }
213
214 if (!areParamsValid) {
215 done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
216 return;
217 }
218
219 // All specified properties are valid, so make changes
220
221 // TODO #3232: Add FacePersistency updating
222
223 setLinkServiceOptions(*face, parameters, response);
224
225 // Set remaining ControlResponse fields
226 response.setFaceId(faceId);
227 response.setFacePersistency(face->getPersistency());
228
229 done(ControlResponse(200, "OK").setBody(response.wireEncode()));
230}
231
232void
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700233FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
234 const ControlParameters& parameters,
235 const ndn::mgmt::CommandContinuation& done)
236{
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000237 Face* face = m_faceTable.get(parameters.getFaceId());
238 if (face != nullptr) {
239 face->close();
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700240 }
241
242 done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
243}
244
245void
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700246FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
247 const ControlParameters& parameters,
248 const ndn::mgmt::CommandContinuation& done)
249{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700250 Face* face = findFaceForLocalControl(interest, parameters, done);
251 if (!face) {
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700252 return;
253 }
254
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700255 // enable-local-control will enable all local fields in GenericLinkService
Junxiao Shicde37ad2015-12-24 01:02:05 -0700256 auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700257 if (service == nullptr) {
258 return done(ControlResponse(503, "LinkService type not supported"));
259 }
260
261 face::GenericLinkService::Options options = service->getOptions();
262 options.allowLocalFields = true;
263 service->setOptions(options);
264
265 return done(ControlResponse(200, "OK: enable all local fields on GenericLinkService")
266 .setBody(parameters.wireEncode()));
267}
268
269void
270FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest,
271 const ControlParameters& parameters,
272 const ndn::mgmt::CommandContinuation& done)
273{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700274 Face* face = findFaceForLocalControl(interest, parameters, done);
275 if (!face) {
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700276 return;
277 }
278
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700279 // disable-local-control will disable all local fields in GenericLinkService
Junxiao Shicde37ad2015-12-24 01:02:05 -0700280 auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
Junxiao Shi40cb61c2015-09-23 18:36:45 -0700281 if (service == nullptr) {
282 return done(ControlResponse(503, "LinkService type not supported"));
283 }
284
285 face::GenericLinkService::Options options = service->getOptions();
286 options.allowLocalFields = false;
287 service->setOptions(options);
288
289 return done(ControlResponse(200, "OK: disable all local fields on GenericLinkService")
290 .setBody(parameters.wireEncode()));
291}
292
Junxiao Shicde37ad2015-12-24 01:02:05 -0700293Face*
294FaceManager::findFaceForLocalControl(const Interest& request,
295 const ControlParameters& parameters,
296 const ndn::mgmt::CommandContinuation& done)
Yanbiao Li73860e32015-08-19 16:30:16 -0700297{
Junxiao Shi0de23a22015-12-03 20:07:02 +0000298 shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
299 // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
300 // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
301 // and is initialized synchronously with IncomingFaceId field enabled.
302 BOOST_ASSERT(incomingFaceIdTag != nullptr);
303
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000304 Face* face = m_faceTable.get(*incomingFaceIdTag);
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200305 if (face == nullptr) {
Junxiao Shi0de23a22015-12-03 20:07:02 +0000306 NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
Yanbiao Li73860e32015-08-19 16:30:16 -0700307 done(ControlResponse(410, "Face not found"));
Junxiao Shicde37ad2015-12-24 01:02:05 -0700308 return nullptr;
Yanbiao Li73860e32015-08-19 16:30:16 -0700309 }
310
Junxiao Shicde37ad2015-12-24 01:02:05 -0700311 if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200312 NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
Yanbiao Li73860e32015-08-19 16:30:16 -0700313 done(ControlResponse(412, "Face is non-local"));
Junxiao Shicde37ad2015-12-24 01:02:05 -0700314 return nullptr;
Yanbiao Li73860e32015-08-19 16:30:16 -0700315 }
316
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000317 return face;
Yanbiao Li73860e32015-08-19 16:30:16 -0700318}
319
320void
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700321FaceManager::setLinkServiceOptions(Face& face,
322 const ControlParameters& parameters,
323 ControlParameters& response)
324{
325 auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
326 BOOST_ASSERT(linkService != nullptr);
327
328 auto options = linkService->getOptions();
329 if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
330 face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
331 options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
332 }
333 linkService->setOptions(options);
334
335 // Set Flags for ControlResponse
336 response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
337}
338
339void
Yanbiao Li73860e32015-08-19 16:30:16 -0700340FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
341 ndn::mgmt::StatusDatasetContext& context)
342{
Eric Newberryc64d30a2015-12-26 11:07:27 -0700343 auto now = time::steady_clock::now();
Junxiao Shib84e6742016-07-19 13:16:22 +0000344 for (const Face& face : m_faceTable) {
345 ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
Junxiao Shida93f1f2015-11-11 06:13:16 -0700346 context.append(status.wireEncode());
Yanbiao Li73860e32015-08-19 16:30:16 -0700347 }
348 context.end();
349}
350
351void
352FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
353 ndn::mgmt::StatusDatasetContext& context)
354{
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200355 std::set<const ProtocolFactory*> seenFactories;
Yanbiao Li73860e32015-08-19 16:30:16 -0700356
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200357 for (const auto& kv : m_factories) {
358 const ProtocolFactory* factory = kv.second.get();
359 bool inserted;
360 std::tie(std::ignore, inserted) = seenFactories.insert(factory);
Yanbiao Li73860e32015-08-19 16:30:16 -0700361
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200362 if (inserted) {
363 for (const auto& channel : factory->getChannels()) {
364 ndn::nfd::ChannelStatus entry;
365 entry.setLocalUri(channel->getUri().toString());
366 context.append(entry.wireEncode());
367 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700368 }
369 }
370
371 context.end();
372}
373
374void
375FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
376 ndn::mgmt::StatusDatasetContext& context)
377{
378 ndn::nfd::FaceQueryFilter faceFilter;
379 const Name& query = interest.getName();
380 try {
381 faceFilter.wireDecode(query[-1].blockFromValue());
382 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200383 catch (const tlv::Error& e) {
384 NFD_LOG_DEBUG("Malformed query filter: " << e.what());
385 return context.reject(ControlResponse(400, "Malformed filter"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700386 }
387
Eric Newberryc64d30a2015-12-26 11:07:27 -0700388 auto now = time::steady_clock::now();
Junxiao Shib84e6742016-07-19 13:16:22 +0000389 for (const Face& face : m_faceTable) {
390 if (!matchFilter(faceFilter, face)) {
Junxiao Shida93f1f2015-11-11 06:13:16 -0700391 continue;
Yanbiao Li73860e32015-08-19 16:30:16 -0700392 }
Junxiao Shib84e6742016-07-19 13:16:22 +0000393 ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
Junxiao Shida93f1f2015-11-11 06:13:16 -0700394 context.append(status.wireEncode());
Yanbiao Li73860e32015-08-19 16:30:16 -0700395 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200396
Yanbiao Li73860e32015-08-19 16:30:16 -0700397 context.end();
398}
399
400bool
Junxiao Shib84e6742016-07-19 13:16:22 +0000401FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
Yanbiao Li73860e32015-08-19 16:30:16 -0700402{
403 if (filter.hasFaceId() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000404 filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700405 return false;
406 }
407
408 if (filter.hasUriScheme() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000409 filter.getUriScheme() != face.getRemoteUri().getScheme() &&
410 filter.getUriScheme() != face.getLocalUri().getScheme()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700411 return false;
412 }
413
414 if (filter.hasRemoteUri() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000415 filter.getRemoteUri() != face.getRemoteUri().toString()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700416 return false;
417 }
418
419 if (filter.hasLocalUri() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000420 filter.getLocalUri() != face.getLocalUri().toString()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700421 return false;
422 }
423
424 if (filter.hasFaceScope() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000425 filter.getFaceScope() != face.getScope()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700426 return false;
427 }
428
429 if (filter.hasFacePersistency() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000430 filter.getFacePersistency() != face.getPersistency()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700431 return false;
432 }
433
434 if (filter.hasLinkType() &&
Junxiao Shib84e6742016-07-19 13:16:22 +0000435 filter.getLinkType() != face.getLinkType()) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700436 return false;
437 }
438
439 return true;
440}
441
Eric Newberryc64d30a2015-12-26 11:07:27 -0700442ndn::nfd::FaceStatus
443FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
444{
445 ndn::nfd::FaceStatus status;
446
447 collectFaceProperties(face, status);
448
449 time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
450 if (expirationTime != time::steady_clock::TimePoint::max()) {
451 status.setExpirationPeriod(std::max(time::milliseconds(0),
452 time::duration_cast<time::milliseconds>(expirationTime - now)));
453 }
454
455 const face::FaceCounters& counters = face.getCounters();
456 status.setNInInterests(counters.nInInterests)
457 .setNOutInterests(counters.nOutInterests)
458 .setNInDatas(counters.nInData)
459 .setNOutDatas(counters.nOutData)
460 .setNInNacks(counters.nInNacks)
461 .setNOutNacks(counters.nOutNacks)
462 .setNInBytes(counters.nInBytes)
463 .setNOutBytes(counters.nOutBytes);
464
465 return status;
466}
467
Junxiao Shida93f1f2015-11-11 06:13:16 -0700468template<typename FaceTraits>
Junxiao Shicde37ad2015-12-24 01:02:05 -0700469void
470FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
Junxiao Shida93f1f2015-11-11 06:13:16 -0700471{
472 traits.setFaceId(face.getId())
473 .setRemoteUri(face.getRemoteUri().toString())
474 .setLocalUri(face.getLocalUri().toString())
475 .setFaceScope(face.getScope())
476 .setFacePersistency(face.getPersistency())
477 .setLinkType(face.getLinkType());
Junxiao Shida93f1f2015-11-11 06:13:16 -0700478}
479
480void
Junxiao Shiae04d342016-07-19 13:20:22 +0000481FaceManager::notifyAddFace(const Face& face)
Yanbiao Li73860e32015-08-19 16:30:16 -0700482{
483 ndn::nfd::FaceEventNotification notification;
484 notification.setKind(ndn::nfd::FACE_EVENT_CREATED);
Junxiao Shiae04d342016-07-19 13:20:22 +0000485 collectFaceProperties(face, notification);
Yanbiao Li73860e32015-08-19 16:30:16 -0700486
Junxiao Shiae04d342016-07-19 13:20:22 +0000487 m_postNotification(notification.wireEncode());
Yanbiao Li73860e32015-08-19 16:30:16 -0700488}
489
490void
Junxiao Shiae04d342016-07-19 13:20:22 +0000491FaceManager::notifyRemoveFace(const Face& face)
Yanbiao Li73860e32015-08-19 16:30:16 -0700492{
493 ndn::nfd::FaceEventNotification notification;
494 notification.setKind(ndn::nfd::FACE_EVENT_DESTROYED);
Junxiao Shiae04d342016-07-19 13:20:22 +0000495 collectFaceProperties(face, notification);
Yanbiao Li73860e32015-08-19 16:30:16 -0700496
Junxiao Shiae04d342016-07-19 13:20:22 +0000497 m_postNotification(notification.wireEncode());
Yanbiao Li73860e32015-08-19 16:30:16 -0700498}
499
500void
501FaceManager::processConfig(const ConfigSection& configSection,
502 bool isDryRun,
503 const std::string& filename)
504{
505 bool hasSeenUnix = false;
506 bool hasSeenTcp = false;
507 bool hasSeenUdp = false;
508 bool hasSeenEther = false;
509 bool hasSeenWebSocket = false;
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200510 auto nicList = listNetworkInterfaces();
Yanbiao Li73860e32015-08-19 16:30:16 -0700511
512 for (const auto& item : configSection) {
513 if (item.first == "unix") {
514 if (hasSeenUnix) {
515 BOOST_THROW_EXCEPTION(Error("Duplicate \"unix\" section"));
516 }
517 hasSeenUnix = true;
518
519 processSectionUnix(item.second, isDryRun);
520 }
521 else if (item.first == "tcp") {
522 if (hasSeenTcp) {
523 BOOST_THROW_EXCEPTION(Error("Duplicate \"tcp\" section"));
524 }
525 hasSeenTcp = true;
526
527 processSectionTcp(item.second, isDryRun);
528 }
529 else if (item.first == "udp") {
530 if (hasSeenUdp) {
531 BOOST_THROW_EXCEPTION(Error("Duplicate \"udp\" section"));
532 }
533 hasSeenUdp = true;
534
535 processSectionUdp(item.second, isDryRun, nicList);
536 }
537 else if (item.first == "ether") {
538 if (hasSeenEther) {
539 BOOST_THROW_EXCEPTION(Error("Duplicate \"ether\" section"));
540 }
541 hasSeenEther = true;
542
543 processSectionEther(item.second, isDryRun, nicList);
544 }
545 else if (item.first == "websocket") {
546 if (hasSeenWebSocket) {
547 BOOST_THROW_EXCEPTION(Error("Duplicate \"websocket\" section"));
548 }
549 hasSeenWebSocket = true;
550
551 processSectionWebSocket(item.second, isDryRun);
552 }
553 else {
554 BOOST_THROW_EXCEPTION(Error("Unrecognized option \"" + item.first + "\""));
555 }
556 }
557}
558
559void
560FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
561{
562 // ; the unix section contains settings of Unix stream faces and channels
563 // unix
564 // {
565 // path /var/run/nfd.sock ; Unix stream listener path
566 // }
567
568#if defined(HAVE_UNIX_SOCKETS)
Yanbiao Li73860e32015-08-19 16:30:16 -0700569 std::string path = "/var/run/nfd.sock";
570
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200571 for (const auto& i : configSection) {
572 if (i.first == "path") {
573 path = i.second.get_value<std::string>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700574 }
575 else {
576 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200577 i.first + "\" in \"unix\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700578 }
579 }
580
581 if (!isDryRun) {
582 if (m_factories.count("unix") > 0) {
583 return;
584 }
585
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200586 auto factory = make_shared<UnixStreamFactory>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700587 m_factories.insert(std::make_pair("unix", factory));
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200588
589 auto channel = factory->createChannel(path);
590 channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700591 }
592#else
593 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without Unix sockets support, "
594 "cannot process \"unix\" section"));
595#endif // HAVE_UNIX_SOCKETS
596}
597
598void
599FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
600{
601 // ; the tcp section contains settings of TCP faces and channels
602 // tcp
603 // {
604 // listen yes ; set to 'no' to disable TCP listener, default 'yes'
605 // port 6363 ; TCP listener port number
606 // }
607
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200608 uint16_t port = 6363;
Yanbiao Li73860e32015-08-19 16:30:16 -0700609 bool needToListen = true;
610 bool enableV4 = true;
611 bool enableV6 = true;
612
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200613 for (const auto& i : configSection) {
614 if (i.first == "port") {
615 port = ConfigFile::parseNumber<uint16_t>(i, "tcp");
616 NFD_LOG_TRACE("TCP port set to " << port);
Yanbiao Li73860e32015-08-19 16:30:16 -0700617 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200618 else if (i.first == "listen") {
619 needToListen = ConfigFile::parseYesNo(i, "tcp");
Yanbiao Li73860e32015-08-19 16:30:16 -0700620 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200621 else if (i.first == "enable_v4") {
622 enableV4 = ConfigFile::parseYesNo(i, "tcp");
Yanbiao Li73860e32015-08-19 16:30:16 -0700623 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200624 else if (i.first == "enable_v6") {
625 enableV6 = ConfigFile::parseYesNo(i, "tcp");
Yanbiao Li73860e32015-08-19 16:30:16 -0700626 }
627 else {
628 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200629 i.first + "\" in \"tcp\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700630 }
631 }
632
633 if (!enableV4 && !enableV6) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200634 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 TCP channels have been disabled."
Yanbiao Li73860e32015-08-19 16:30:16 -0700635 " Remove \"tcp\" section to disable TCP channels or"
636 " re-enable at least one channel type."));
637 }
638
639 if (!isDryRun) {
640 if (m_factories.count("tcp") > 0) {
641 return;
642 }
643
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200644 auto factory = make_shared<TcpFactory>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700645 m_factories.insert(std::make_pair("tcp", factory));
646
647 if (enableV4) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200648 tcp::Endpoint endpoint(boost::asio::ip::tcp::v4(), port);
649 shared_ptr<TcpChannel> v4Channel = factory->createChannel(endpoint);
Yanbiao Li73860e32015-08-19 16:30:16 -0700650 if (needToListen) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200651 v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700652 }
653
654 m_factories.insert(std::make_pair("tcp4", factory));
655 }
656
657 if (enableV6) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200658 tcp::Endpoint endpoint(boost::asio::ip::tcp::v6(), port);
659 shared_ptr<TcpChannel> v6Channel = factory->createChannel(endpoint);
Yanbiao Li73860e32015-08-19 16:30:16 -0700660 if (needToListen) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200661 v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700662 }
663
664 m_factories.insert(std::make_pair("tcp6", factory));
665 }
666 }
667}
668
669void
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200670FaceManager::processSectionUdp(const ConfigSection& configSection, bool isDryRun,
Yanbiao Li73860e32015-08-19 16:30:16 -0700671 const std::vector<NetworkInterfaceInfo>& nicList)
672{
673 // ; the udp section contains settings of UDP faces and channels
674 // udp
675 // {
676 // port 6363 ; UDP unicast port number
677 // idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
678 // keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
679
680 // ; NFD creates one UDP multicast face per NIC
681 // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
682 // mcast_port 56363 ; UDP multicast port number
683 // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
684 // }
685
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200686 uint16_t port = 6363;
Yanbiao Li73860e32015-08-19 16:30:16 -0700687 bool enableV4 = true;
688 bool enableV6 = true;
689 size_t timeout = 600;
690 size_t keepAliveInterval = 25;
691 bool useMcast = true;
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200692 auto mcastGroup = boost::asio::ip::address_v4::from_string("224.0.23.170");
693 uint16_t mcastPort = 56363;
Yanbiao Li73860e32015-08-19 16:30:16 -0700694
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200695 for (const auto& i : configSection) {
696 if (i.first == "port") {
697 port = ConfigFile::parseNumber<uint16_t>(i, "udp");
698 NFD_LOG_TRACE("UDP unicast port set to " << port);
699 }
700 else if (i.first == "enable_v4") {
701 enableV4 = ConfigFile::parseYesNo(i, "udp");
702 }
703 else if (i.first == "enable_v6") {
704 enableV6 = ConfigFile::parseYesNo(i, "udp");
705 }
706 else if (i.first == "idle_timeout") {
Yanbiao Li73860e32015-08-19 16:30:16 -0700707 try {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200708 timeout = i.second.get_value<size_t>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700709 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200710 catch (const boost::property_tree::ptree_bad_data&) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700711 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200712 i.first + "\" in \"udp\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700713 }
714 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200715 else if (i.first == "keep_alive_interval") {
Yanbiao Li73860e32015-08-19 16:30:16 -0700716 try {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200717 keepAliveInterval = i.second.get_value<size_t>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700718 /// \todo Make use of keepAliveInterval
Yanbiao Li73860e32015-08-19 16:30:16 -0700719 (void)(keepAliveInterval);
720 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200721 catch (const boost::property_tree::ptree_bad_data&) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700722 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200723 i.first + "\" in \"udp\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700724 }
725 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200726 else if (i.first == "mcast") {
727 useMcast = ConfigFile::parseYesNo(i, "udp");
Yanbiao Li73860e32015-08-19 16:30:16 -0700728 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200729 else if (i.first == "mcast_port") {
730 mcastPort = ConfigFile::parseNumber<uint16_t>(i, "udp");
731 NFD_LOG_TRACE("UDP multicast port set to " << mcastPort);
Yanbiao Li73860e32015-08-19 16:30:16 -0700732 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200733 else if (i.first == "mcast_group") {
734 boost::system::error_code ec;
735 mcastGroup = boost::asio::ip::address_v4::from_string(i.second.get_value<std::string>(), ec);
736 if (ec) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700737 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200738 i.first + "\" in \"udp\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700739 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200740 NFD_LOG_TRACE("UDP multicast group set to " << mcastGroup);
Yanbiao Li73860e32015-08-19 16:30:16 -0700741 }
742 else {
743 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200744 i.first + "\" in \"udp\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700745 }
746 }
747
748 if (!enableV4 && !enableV6) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200749 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 UDP channels have been disabled."
Yanbiao Li73860e32015-08-19 16:30:16 -0700750 " Remove \"udp\" section to disable UDP channels or"
751 " re-enable at least one channel type."));
752 }
753 else if (useMcast && !enableV4) {
754 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 multicast requested, but IPv4 channels"
755 " have been disabled (conflicting configuration options set)"));
756 }
757
758 if (!isDryRun) {
759 shared_ptr<UdpFactory> factory;
760 bool isReload = false;
761 if (m_factories.count("udp") > 0) {
762 isReload = true;
763 factory = static_pointer_cast<UdpFactory>(m_factories["udp"]);
764 }
765 else {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200766 factory = make_shared<UdpFactory>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700767 m_factories.insert(std::make_pair("udp", factory));
768 }
769
770 if (!isReload && enableV4) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200771 udp::Endpoint endpoint(boost::asio::ip::udp::v4(), port);
772 shared_ptr<UdpChannel> v4Channel = factory->createChannel(endpoint, time::seconds(timeout));
773 v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700774
775 m_factories.insert(std::make_pair("udp4", factory));
776 }
777
778 if (!isReload && enableV6) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200779 udp::Endpoint endpoint(boost::asio::ip::udp::v6(), port);
780 shared_ptr<UdpChannel> v6Channel = factory->createChannel(endpoint, time::seconds(timeout));
781 v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700782
Yanbiao Li73860e32015-08-19 16:30:16 -0700783 m_factories.insert(std::make_pair("udp6", factory));
784 }
785
Junxiao Shicde37ad2015-12-24 01:02:05 -0700786 std::set<shared_ptr<Face>> multicastFacesToRemove;
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200787 for (const auto& i : factory->getMulticastFaces()) {
788 multicastFacesToRemove.insert(i.second);
789 }
790
Yanbiao Li73860e32015-08-19 16:30:16 -0700791 if (useMcast && enableV4) {
792 std::vector<NetworkInterfaceInfo> ipv4MulticastInterfaces;
793 for (const auto& nic : nicList) {
794 if (nic.isUp() && nic.isMulticastCapable() && !nic.ipv4Addresses.empty()) {
795 ipv4MulticastInterfaces.push_back(nic);
796 }
797 }
798
799 bool isNicNameNecessary = false;
800#if defined(__linux__)
801 if (ipv4MulticastInterfaces.size() > 1) {
802 // On Linux if we have more than one MulticastUdpFace
803 // we need to specify the name of the interface
804 isNicNameNecessary = true;
805 }
806#endif
807
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200808 udp::Endpoint mcastEndpoint(mcastGroup, mcastPort);
Yanbiao Li73860e32015-08-19 16:30:16 -0700809 for (const auto& nic : ipv4MulticastInterfaces) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200810 udp::Endpoint localEndpoint(nic.ipv4Addresses[0], mcastPort);
811 auto newFace = factory->createMulticastFace(localEndpoint, mcastEndpoint,
Yukai Tu0a49d342015-09-13 12:54:22 +0800812 isNicNameNecessary ? nic.name : "");
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200813 m_faceTable.add(newFace);
814 multicastFacesToRemove.erase(newFace);
Yanbiao Li73860e32015-08-19 16:30:16 -0700815 }
816 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700817
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200818 for (const auto& face : multicastFacesToRemove) {
819 face->close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700820 }
821 }
822}
823
824void
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200825FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryRun,
Yanbiao Li73860e32015-08-19 16:30:16 -0700826 const std::vector<NetworkInterfaceInfo>& nicList)
827{
828 // ; the ether section contains settings of Ethernet faces and channels
829 // ether
830 // {
831 // ; NFD creates one Ethernet multicast face per NIC
832 // mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
833 // mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
834 // }
835
836#if defined(HAVE_LIBPCAP)
837 bool useMcast = true;
838 ethernet::Address mcastGroup(ethernet::getDefaultMulticastAddress());
839
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200840 for (const auto& i : configSection) {
841 if (i.first == "mcast") {
842 useMcast = ConfigFile::parseYesNo(i, "ether");
Yanbiao Li73860e32015-08-19 16:30:16 -0700843 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200844 else if (i.first == "mcast_group") {
845 mcastGroup = ethernet::Address::fromString(i.second.get_value<std::string>());
Yanbiao Li73860e32015-08-19 16:30:16 -0700846 if (mcastGroup.isNull()) {
847 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200848 i.first + "\" in \"ether\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700849 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200850 NFD_LOG_TRACE("Ethernet multicast group set to " << mcastGroup);
Yanbiao Li73860e32015-08-19 16:30:16 -0700851 }
852 else {
853 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200854 i.first + "\" in \"ether\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700855 }
856 }
857
858 if (!isDryRun) {
859 shared_ptr<EthernetFactory> factory;
860 if (m_factories.count("ether") > 0) {
861 factory = static_pointer_cast<EthernetFactory>(m_factories["ether"]);
862 }
863 else {
864 factory = make_shared<EthernetFactory>();
865 m_factories.insert(std::make_pair("ether", factory));
866 }
867
Junxiao Shicde37ad2015-12-24 01:02:05 -0700868 std::set<shared_ptr<Face>> multicastFacesToRemove;
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200869 for (const auto& i : factory->getMulticastFaces()) {
870 multicastFacesToRemove.insert(i.second);
871 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700872
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200873 if (useMcast) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700874 for (const auto& nic : nicList) {
875 if (nic.isUp() && nic.isMulticastCapable()) {
876 try {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200877 auto newFace = factory->createMulticastFace(nic, mcastGroup);
878 m_faceTable.add(newFace);
879 multicastFacesToRemove.erase(newFace);
Yanbiao Li73860e32015-08-19 16:30:16 -0700880 }
881 catch (const EthernetFactory::Error& factoryError) {
882 NFD_LOG_ERROR(factoryError.what() << ", continuing");
883 }
Davide Pesavento35120ea2015-11-17 21:13:18 +0100884 catch (const face::EthernetTransport::Error& faceError) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700885 NFD_LOG_ERROR(faceError.what() << ", continuing");
886 }
887 }
888 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700889 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700890
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200891 for (const auto& face : multicastFacesToRemove) {
892 face->close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700893 }
894 }
895#else
896 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section"));
897#endif // HAVE_LIBPCAP
898}
899
900void
901FaceManager::processSectionWebSocket(const ConfigSection& configSection, bool isDryRun)
902{
903 // ; the websocket section contains settings of WebSocket faces and channels
904 // websocket
905 // {
906 // listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
907 // port 9696 ; WebSocket listener port number
908 // enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
909 // enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
910 // }
911
912#if defined(HAVE_WEBSOCKET)
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200913 uint16_t port = 9696;
Yanbiao Li73860e32015-08-19 16:30:16 -0700914 bool needToListen = true;
915 bool enableV4 = true;
916 bool enableV6 = true;
917
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200918 for (const auto& i : configSection) {
919 if (i.first == "port") {
920 port = ConfigFile::parseNumber<uint16_t>(i, "websocket");
921 NFD_LOG_TRACE("WebSocket port set to " << port);
Yanbiao Li73860e32015-08-19 16:30:16 -0700922 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200923 else if (i.first == "listen") {
924 needToListen = ConfigFile::parseYesNo(i, "websocket");
Yanbiao Li73860e32015-08-19 16:30:16 -0700925 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200926 else if (i.first == "enable_v4") {
927 enableV4 = ConfigFile::parseYesNo(i, "websocket");
Yanbiao Li73860e32015-08-19 16:30:16 -0700928 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200929 else if (i.first == "enable_v6") {
930 enableV6 = ConfigFile::parseYesNo(i, "websocket");
Yanbiao Li73860e32015-08-19 16:30:16 -0700931 }
932 else {
933 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200934 i.first + "\" in \"websocket\" section"));
Yanbiao Li73860e32015-08-19 16:30:16 -0700935 }
936 }
937
938 if (!enableV4 && !enableV6) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200939 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 WebSocket channels have been disabled."
Yanbiao Li73860e32015-08-19 16:30:16 -0700940 " Remove \"websocket\" section to disable WebSocket channels or"
941 " re-enable at least one channel type."));
942 }
943
944 if (!enableV4 && enableV6) {
945 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel."));
946 }
947
948 if (!isDryRun) {
949 if (m_factories.count("websocket") > 0) {
950 return;
951 }
952
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200953 auto factory = make_shared<WebSocketFactory>();
Yanbiao Li73860e32015-08-19 16:30:16 -0700954 m_factories.insert(std::make_pair("websocket", factory));
955
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200956 shared_ptr<WebSocketChannel> channel;
957
Yanbiao Li73860e32015-08-19 16:30:16 -0700958 if (enableV6 && enableV4) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200959 websocket::Endpoint endpoint(boost::asio::ip::address_v6::any(), port);
960 channel = factory->createChannel(endpoint);
Yanbiao Li73860e32015-08-19 16:30:16 -0700961
962 m_factories.insert(std::make_pair("websocket46", factory));
963 }
964 else if (enableV4) {
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200965 websocket::Endpoint endpoint(boost::asio::ip::address_v4::any(), port);
966 channel = factory->createChannel(endpoint);
Yanbiao Li73860e32015-08-19 16:30:16 -0700967
968 m_factories.insert(std::make_pair("websocket4", factory));
969 }
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200970
971 if (channel && needToListen) {
972 channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
973 }
Yanbiao Li73860e32015-08-19 16:30:16 -0700974 }
975#else
976 BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD was compiled without WebSocket, "
977 "cannot process \"websocket\" section"));
978#endif // HAVE_WEBSOCKET
979}
980
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200981} // namespace nfd