30 #include <boost/range/adaptors.hpp>
31 #include <boost/range/algorithm/copy.hpp>
36 #include <sys/socket.h>
42 namespace ip = boost::asio::ip;
50 static std::string id(
"udp");
79 bool enableV4 =
false;
80 bool enableV6 =
false;
81 uint32_t idleTimeout = 600;
82 MulticastConfig mcastConfig;
86 enableV4 = enableV6 = mcastConfig.isEnabled =
true;
88 for (
const auto& pair : *configSection) {
89 const std::string& key = pair.first;
93 port = ConfigFile::parseNumber<uint16_t>(pair,
"face_system.udp");
95 else if (key ==
"enable_v4") {
98 else if (key ==
"enable_v6") {
101 else if (key ==
"idle_timeout") {
102 idleTimeout = ConfigFile::parseNumber<uint32_t>(pair,
"face_system.udp");
104 else if (key ==
"keep_alive_interval") {
107 else if (key ==
"mcast") {
110 else if (key ==
"mcast_group") {
111 const std::string& valueStr = value.get_value<std::string>();
112 boost::system::error_code ec;
113 mcastConfig.group.address(boost::asio::ip::address_v4::from_string(valueStr, ec));
116 valueStr +
"' cannot be parsed as an IPv4 address"));
118 else if (!mcastConfig.group.address().is_multicast()) {
120 valueStr +
"' is not a multicast address"));
123 else if (key ==
"mcast_port") {
124 mcastConfig.group.port(ConfigFile::parseNumber<uint16_t>(pair,
"face_system.udp"));
126 else if (key ==
"whitelist") {
127 mcastConfig.netifPredicate.parseWhitelist(value);
129 else if (key ==
"blacklist") {
130 mcastConfig.netifPredicate.parseBlacklist(value);
133 BOOST_THROW_EXCEPTION(
ConfigFile::Error(
"Unrecognized option face_system.udp." + key));
137 if (!enableV4 && !enableV6 && !mcastConfig.isEnabled) {
139 "IPv4 and IPv6 UDP channels and UDP multicast have been disabled. "
140 "Remove face_system.udp section to disable UDP channels or enable at least one of them."));
147 shared_ptr<UdpChannel> v4Channel = this->
createChannel(endpoint, time::seconds(idleTimeout));
148 if (!v4Channel->isListening()) {
149 v4Channel->listen(context.
addFace,
nullptr);
155 NFD_LOG_WARN(
"Cannot close udp4 channel after its creation");
160 shared_ptr<UdpChannel> v6Channel = this->
createChannel(endpoint, time::seconds(idleTimeout));
161 if (!v6Channel->isListening()) {
162 v6Channel->listen(context.
addFace,
nullptr);
168 NFD_LOG_WARN(
"Cannot close udp6 channel after its creation");
171 if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
172 if (mcastConfig.isEnabled) {
173 NFD_LOG_INFO(
"enabling multicast on " << mcastConfig.group);
179 else if (m_mcastConfig.group != mcastConfig.group) {
180 NFD_LOG_INFO(
"changing multicast group from " << m_mcastConfig.group <<
181 " to " << mcastConfig.group);
183 else if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
191 m_mcastConfig = mcastConfig;
192 this->applyMulticastConfig(context);
198 ndn::nfd::FacePersistency persistency,
199 bool wantLocalFieldsEnabled,
203 BOOST_ASSERT(uri.isCanonical());
205 if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
206 NFD_LOG_TRACE(
"createFace does not support FACE_PERSISTENCY_ON_DEMAND");
207 onFailure(406,
"Outgoing unicast UDP faces do not support on-demand persistency");
211 udp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
212 boost::lexical_cast<uint16_t>(uri.getPort()));
214 if (endpoint.address().is_multicast()) {
215 NFD_LOG_TRACE(
"createFace does not support multicast faces");
216 onFailure(406,
"Cannot create multicast UDP faces");
220 if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
222 "(reserved by this NFD or disallowed by face management protocol)");
223 onFailure(406,
"Requested endpoint is prohibited");
227 if (wantLocalFieldsEnabled) {
229 NFD_LOG_TRACE(
"createFace cannot create non-local face with local fields enabled");
230 onFailure(406,
"Local fields can only be enabled on faces with local scope");
235 for (
const auto& i : m_channels) {
236 if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
237 (i.first.address().is_v6() && endpoint.address().is_v6())) {
238 i.second->connect(endpoint, persistency, onCreated, onFailure);
243 NFD_LOG_TRACE(
"No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
244 onFailure(504,
"No channels available to connect");
250 if (endpoint.address().is_v4() &&
251 endpoint.address() == ip::address_v4::any()) {
252 prohibitAllIpv4Endpoints(endpoint.port());
254 else if (endpoint.address().is_v6() &&
255 endpoint.address() == ip::address_v6::any()) {
256 prohibitAllIpv6Endpoints(endpoint.port());
260 m_prohibitedEndpoints.insert(endpoint);
264 UdpFactory::prohibitAllIpv4Endpoints(uint16_t port)
267 for (
const auto& addr : nic.ipv4Addresses) {
268 if (addr != ip::address_v4::any()) {
273 if (nic.isBroadcastCapable() &&
274 nic.broadcastAddress != ip::address_v4::any()) {
279 prohibitEndpoint(
udp::Endpoint(ip::address_v4::broadcast(), port));
283 UdpFactory::prohibitAllIpv6Endpoints(uint16_t port)
286 for (
const auto& addr : nic.ipv6Addresses) {
287 if (addr != ip::address_v6::any()) {
294 shared_ptr<UdpChannel>
296 const time::seconds& timeout)
300 auto channel = findChannel(endpoint);
304 if (endpoint.address().is_multicast()) {
305 BOOST_THROW_EXCEPTION(
Error(
"createChannel is only for unicast channels. The provided endpoint "
306 "is multicast. Use createMulticastFace to create a multicast face"));
310 auto face = findMulticastFace(endpoint);
312 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP unicast channel, local "
313 "endpoint is already allocated for a UDP multicast face"));
316 channel = std::make_shared<UdpChannel>(endpoint, timeout);
317 m_channels[endpoint] = channel;
318 prohibitEndpoint(endpoint);
323 shared_ptr<UdpChannel>
325 const time::seconds& timeout)
328 boost::lexical_cast<uint16_t>(localPort));
332 std::vector<shared_ptr<const Channel>>
338 shared_ptr<UdpChannel>
339 UdpFactory::findChannel(
const udp::Endpoint& localEndpoint)
const
341 auto i = m_channels.find(localEndpoint);
342 if (i != m_channels.end())
351 const std::string& networkInterfaceName)
354 auto face = findMulticastFace(localEndpoint);
356 if (face->getRemoteUri() == FaceUri(multicastEndpoint))
359 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, local "
360 "endpoint is already allocated for a UDP multicast face "
361 "on a different multicast group"));
365 auto unicastCh = findChannel(localEndpoint);
367 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, local "
368 "endpoint is already allocated for a UDP unicast channel"));
371 if (m_prohibitedEndpoints.find(multicastEndpoint) != m_prohibitedEndpoints.end()) {
372 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, "
373 "remote endpoint is owned by this NFD instance"));
376 if (localEndpoint.address().is_v6() || multicastEndpoint.address().is_v6()) {
377 BOOST_THROW_EXCEPTION(
Error(
"IPv6 multicast is not supported yet. Please provide an IPv4 "
381 if (localEndpoint.port() != multicastEndpoint.port()) {
382 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, "
383 "both endpoints should have the same port number. "));
386 if (!multicastEndpoint.address().is_multicast()) {
387 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, "
388 "the multicast group given as input is not a multicast address"));
392 receiveSocket.open(multicastEndpoint.protocol());
393 receiveSocket.set_option(ip::udp::socket::reuse_address(
true));
394 receiveSocket.bind(multicastEndpoint);
397 sendSocket.open(multicastEndpoint.protocol());
398 sendSocket.set_option(ip::udp::socket::reuse_address(
true));
399 sendSocket.set_option(ip::multicast::enable_loopback(
false));
400 sendSocket.bind(
udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
401 if (localEndpoint.address() != ip::address_v4::any())
402 sendSocket.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
404 sendSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
405 localEndpoint.address().to_v4()));
406 receiveSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
407 localEndpoint.address().to_v4()));
418 if (!networkInterfaceName.empty()) {
419 if (::setsockopt(receiveSocket.native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
420 networkInterfaceName.c_str(), networkInterfaceName.size() + 1) < 0) {
421 BOOST_THROW_EXCEPTION(
Error(
"Cannot bind multicast face to " + networkInterfaceName +
422 ": " + std::strerror(errno)));
427 auto linkService = make_unique<GenericLinkService>();
428 auto transport = make_unique<MulticastUdpTransport>(localEndpoint, multicastEndpoint,
429 std::move(receiveSocket),
430 std::move(sendSocket));
431 face = make_shared<Face>(std::move(linkService), std::move(transport));
433 m_mcastFaces[localEndpoint] = face;
441 const std::string& multicastIp,
442 const std::string& multicastPort,
443 const std::string& networkInterfaceName)
445 udp::Endpoint localEndpoint(ip::address::from_string(localIp),
446 boost::lexical_cast<uint16_t>(multicastPort));
447 udp::Endpoint multicastEndpoint(ip::address::from_string(multicastIp),
448 boost::lexical_cast<uint16_t>(multicastPort));
453 UdpFactory::findMulticastFace(
const udp::Endpoint& localEndpoint)
const
455 auto i = m_mcastFaces.find(localEndpoint);
456 if (i != m_mcastFaces.end())
463 UdpFactory::applyMulticastConfig(
const FaceSystem::ConfigContext& context)
466 std::set<shared_ptr<Face>> oldFaces;
467 boost::copy(m_mcastFaces | boost::adaptors::map_values,
468 std::inserter(oldFaces, oldFaces.end()));
470 if (m_mcastConfig.isEnabled) {
472 auto capableNetifRange = context.listNetifs() |
476 m_mcastConfig.netifPredicate(netif);
479 bool needIfname =
false;
481 std::vector<NetworkInterfaceInfo> capableNetifs;
482 boost::copy(capableNetifRange, std::back_inserter(capableNetifs));
484 needIfname = capableNetifs.size() > 1;
486 auto& capableNetifs = capableNetifRange;
490 for (
const auto& netif : capableNetifs) {
493 needIfname ? netif.
name :
"");
496 context.addFace(face);
500 oldFaces.erase(face);
506 for (
const auto& face : oldFaces) {
shared_ptr< UdpChannel > createChannel(const udp::Endpoint &localEndpoint, const time::seconds &timeout=time::seconds(600))
Create UDP-based channel using udp::Endpoint.
#define NFD_LOG_DEBUG(expression)
contains information about a network interface
std::set< std::string > providedSchemes
FaceUri schemes provided by this ProtocolFactory.
void connectFaceClosedSignal(Face &face, const std::function< void()> &f)
invokes a callback when the face is closed
void createFace(const FaceUri &uri, ndn::nfd::FacePersistency persistency, bool wantLocalFieldsEnabled, const FaceCreatedCallback &onCreated, const FaceCreationFailedCallback &onFailure) override
Try to create Face using the supplied FaceUri.
FaceCreatedCallback addFace
static bool parseYesNo(const ConfigSection &node, const std::string &key, const std::string §ionName)
parse a config option that can be either "yes" or "no"
#define NFD_REGISTER_PROTOCOL_FACTORY(PF)
registers a protocol factory
std::vector< NetworkInterfaceInfo > listNetworkInterfaces()
List configured network interfaces on the system and their info.
#define NFD_LOG_WARN(expression)
std::vector< boost::asio::ip::address_v4 > ipv4Addresses
context for processing a config section in ProtocolFactory
static std::vector< shared_ptr< const Channel > > getChannelsFromMap(const ChannelMap &channelMap)
#define NFD_LOG_INFO(expression)
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
boost::optional< const ConfigSection & > OptionalConfigSection
an optional config file section
boost::property_tree::ptree ConfigSection
a config file section
boost::asio::ip::udp::endpoint Endpoint
function< void(uint32_t status, const std::string &reason)> FaceCreationFailedCallback
Prototype for the callback that is invoked when the face fails to be created.
void processConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext &context) override
process face_system.udp config section
static const std::string & getId()
#define NFD_LOG_INIT(name)
#define NFD_LOG_TRACE(expression)
function< void(const shared_ptr< Face > &newFace)> FaceCreatedCallback
Prototype for the callback that is invoked when the face is created (as a response to incoming connec...
std::vector< shared_ptr< const Channel > > getChannels() const override
bool isMulticastCapable() const
const FaceId INVALID_FACEID
indicates an invalid FaceId
shared_ptr< Face > createMulticastFace(const udp::Endpoint &localEndpoint, const udp::Endpoint &multicastEndpoint, const std::string &networkInterfaceName="")
Create MulticastUdpFace using udp::Endpoint.
boost::asio::io_service & getGlobalIoService()