31 #include <ndn-cxx/net/address-converter.hpp> 32 #include <boost/range/adaptors.hpp> 33 #include <boost/range/algorithm/copy.hpp> 38 #include <sys/socket.h> 44 namespace ip = boost::asio::ip;
52 static std::string id(
"udp");
59 m_netifAddConn =
netmon->onInterfaceAdded.connect(bind(&UdpFactory::applyMcastConfigToNetif,
this, _1));
87 bool enableV4 =
false;
88 bool enableV6 =
false;
89 uint32_t idleTimeout = 600;
90 MulticastConfig mcastConfig;
94 enableV4 = enableV6 = mcastConfig.isEnabled =
true;
96 for (
const auto& pair : *configSection) {
97 const std::string& key = pair.first;
101 port = ConfigFile::parseNumber<uint16_t>(pair,
"face_system.udp");
103 else if (key ==
"enable_v4") {
106 else if (key ==
"enable_v6") {
109 else if (key ==
"idle_timeout") {
110 idleTimeout = ConfigFile::parseNumber<uint32_t>(pair,
"face_system.udp");
112 else if (key ==
"keep_alive_interval") {
115 else if (key ==
"mcast") {
118 else if (key ==
"mcast_group") {
119 const std::string& valueStr = value.get_value<std::string>();
120 boost::system::error_code ec;
121 mcastConfig.group.address(boost::asio::ip::address_v4::from_string(valueStr, ec));
124 valueStr +
"' cannot be parsed as an IPv4 address"));
126 else if (!mcastConfig.group.address().is_multicast()) {
128 valueStr +
"' is not a multicast address"));
131 else if (key ==
"mcast_port") {
132 mcastConfig.group.port(ConfigFile::parseNumber<uint16_t>(pair,
"face_system.udp"));
134 else if (key ==
"mcast_ad_hoc") {
136 mcastConfig.linkType = wantAdHoc ? ndn::nfd::LINK_TYPE_AD_HOC : ndn::nfd::LINK_TYPE_MULTI_ACCESS;
138 else if (key ==
"whitelist") {
139 mcastConfig.netifPredicate.parseWhitelist(value);
141 else if (key ==
"blacklist") {
142 mcastConfig.netifPredicate.parseBlacklist(value);
145 BOOST_THROW_EXCEPTION(
ConfigFile::Error(
"Unrecognized option face_system.udp." + key));
149 if (!enableV4 && !enableV6 && !mcastConfig.isEnabled) {
151 "IPv4 and IPv6 UDP channels and UDP multicast have been disabled. " 152 "Remove face_system.udp section to disable UDP channels or enable at least one of them."));
162 shared_ptr<UdpChannel> v4Channel = this->
createChannel(endpoint, time::seconds(idleTimeout));
163 if (!v4Channel->isListening()) {
164 v4Channel->listen(this->
addFace,
nullptr);
170 NFD_LOG_WARN(
"Cannot close udp4 channel after its creation");
175 shared_ptr<UdpChannel> v6Channel = this->
createChannel(endpoint, time::seconds(idleTimeout));
176 if (!v6Channel->isListening()) {
177 v6Channel->listen(this->
addFace,
nullptr);
183 NFD_LOG_WARN(
"Cannot close udp6 channel after its creation");
186 if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
187 if (mcastConfig.isEnabled) {
188 NFD_LOG_INFO(
"enabling multicast on " << mcastConfig.group);
194 else if (mcastConfig.isEnabled) {
195 if (m_mcastConfig.linkType != mcastConfig.linkType && !m_mcastFaces.empty()) {
196 NFD_LOG_WARN(
"Cannot change ad hoc setting on existing faces");
198 if (m_mcastConfig.group != mcastConfig.group) {
199 NFD_LOG_INFO(
"changing multicast group from " << m_mcastConfig.group <<
200 " to " << mcastConfig.group);
202 if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
209 m_mcastConfig = mcastConfig;
210 this->applyMcastConfig(context);
218 BOOST_ASSERT(params.
remoteUri.isCanonical());
221 NFD_LOG_TRACE(
"Cannot create unicast UDP face with LocalUri");
222 onFailure(406,
"Unicast UDP faces cannot be created with a LocalUri");
226 if (params.
persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
227 NFD_LOG_TRACE(
"createFace does not support FACE_PERSISTENCY_ON_DEMAND");
228 onFailure(406,
"Outgoing UDP faces do not support on-demand persistency");
233 boost::lexical_cast<uint16_t>(params.
remoteUri.getPort()));
235 if (endpoint.address().is_multicast()) {
236 NFD_LOG_TRACE(
"createFace does not support multicast faces");
237 onFailure(406,
"Cannot create multicast UDP faces");
243 NFD_LOG_TRACE(
"createFace cannot create non-local face with local fields enabled");
244 onFailure(406,
"Local fields can only be enabled on faces with local scope");
249 for (
const auto& i : m_channels) {
250 if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
251 (i.first.address().is_v6() && endpoint.address().is_v6())) {
253 onCreated, onFailure);
258 NFD_LOG_TRACE(
"No channels available to connect to " << endpoint);
259 onFailure(504,
"No channels available to connect");
262 shared_ptr<UdpChannel>
264 time::nanoseconds idleTimeout)
266 auto it = m_channels.find(localEndpoint);
267 if (it != m_channels.end())
270 if (localEndpoint.address().is_multicast()) {
271 BOOST_THROW_EXCEPTION(
Error(
"createChannel is only for unicast channels. The provided endpoint " 272 "is multicast. Use createMulticastFace to create a multicast face"));
276 if (m_mcastFaces.find(localEndpoint) != m_mcastFaces.end()) {
277 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP unicast channel, local " 278 "endpoint is already allocated for a UDP multicast face"));
281 auto channel = std::make_shared<UdpChannel>(localEndpoint, idleTimeout);
282 m_channels[localEndpoint] = channel;
287 std::vector<shared_ptr<const Channel>>
296 const std::string& networkInterfaceName)
299 auto it = m_mcastFaces.find(localEndpoint);
300 if (it != m_mcastFaces.end()) {
301 if (it->second->getRemoteUri() == FaceUri(multicastEndpoint))
304 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, local " 305 "endpoint is already allocated for a UDP multicast face " 306 "on a different multicast group"));
310 if (m_channels.find(localEndpoint) != m_channels.end()) {
311 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, local " 312 "endpoint is already allocated for a UDP unicast channel"));
315 if (localEndpoint.address().is_v6() || multicastEndpoint.address().is_v6()) {
316 BOOST_THROW_EXCEPTION(
Error(
"IPv6 multicast is not supported yet. Please provide an IPv4 " 320 if (localEndpoint.port() != multicastEndpoint.port()) {
321 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, " 322 "both endpoints should have the same port number. "));
325 if (!multicastEndpoint.address().is_multicast()) {
326 BOOST_THROW_EXCEPTION(
Error(
"Cannot create the requested UDP multicast face, " 327 "the multicast group given as input is not a multicast address"));
331 receiveSocket.open(multicastEndpoint.protocol());
332 receiveSocket.set_option(ip::udp::socket::reuse_address(
true));
333 receiveSocket.bind(multicastEndpoint);
336 sendSocket.open(multicastEndpoint.protocol());
337 sendSocket.set_option(ip::udp::socket::reuse_address(
true));
338 sendSocket.set_option(ip::multicast::enable_loopback(
false));
339 sendSocket.bind(
udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
340 if (localEndpoint.address() != ip::address_v4::any())
341 sendSocket.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
343 sendSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
344 localEndpoint.address().to_v4()));
345 receiveSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
346 localEndpoint.address().to_v4()));
355 if (!networkInterfaceName.empty()) {
356 if (::setsockopt(receiveSocket.native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
357 networkInterfaceName.c_str(), networkInterfaceName.size() + 1) < 0) {
358 BOOST_THROW_EXCEPTION(
Error(
"Cannot bind multicast face to " + networkInterfaceName +
359 ": " + std::strerror(errno)));
364 auto linkService = make_unique<GenericLinkService>();
365 auto transport = make_unique<MulticastUdpTransport>(localEndpoint, multicastEndpoint,
366 std::move(receiveSocket),
367 std::move(sendSocket),
368 m_mcastConfig.linkType);
369 auto face = make_shared<Face>(std::move(linkService), std::move(transport));
371 m_mcastFaces[localEndpoint] = face;
379 const std::string& multicastIp,
380 const std::string& multicastPort,
381 const std::string& networkInterfaceName)
383 udp::Endpoint localEndpoint(ndn::ip::addressFromString(localIp),
384 boost::lexical_cast<uint16_t>(multicastPort));
385 udp::Endpoint multicastEndpoint(ndn::ip::addressFromString(multicastIp),
386 boost::lexical_cast<uint16_t>(multicastPort));
390 static ndn::optional<ndn::net::NetworkAddress>
393 using namespace ndn::net;
394 for (
const NetworkAddress& na : netif.getNetworkAddresses()) {
395 if (na.getFamily() == AddressFamily::V4 && na.getScope() != AddressScope::NOWHERE) {
403 UdpFactory::applyMcastConfigToNetif(
const shared_ptr<const ndn::net::NetworkInterface>& netif)
405 if (!m_mcastConfig.isEnabled) {
409 if (!netif->isUp()) {
410 NFD_LOG_DEBUG(
"Not creating multicast face on " << netif->getName() <<
": netif is down");
414 if (!netif->canMulticast()) {
415 NFD_LOG_DEBUG(
"Not creating multicast face on " << netif->getName() <<
": netif cannot multicast");
421 NFD_LOG_DEBUG(
"Not creating multicast face on " << netif->getName() <<
": no IPv4 address");
423 m_netifConns[netif->getIndex()].addrAddConn =
424 netif->onAddressAdded.connectSingleShot(bind(&UdpFactory::applyMcastConfigToNetif,
this, netif));
428 if (!m_mcastConfig.netifPredicate(*netif)) {
429 NFD_LOG_DEBUG(
"Not creating multicast face on " << netif->getName() <<
": rejected by whitelist/blacklist");
433 NFD_LOG_DEBUG(
"Creating multicast face on " << netif->getName());
434 udp::Endpoint localEndpoint(address->getIp(), m_mcastConfig.group.port());
435 auto face = this->
createMulticastFace(localEndpoint, m_mcastConfig.group, netif->getName());
450 std::set<shared_ptr<Face>> oldFaces;
451 boost::copy(m_mcastFaces | boost::adaptors::map_values, std::inserter(oldFaces, oldFaces.end()));
454 for (
const auto& netif :
netmon->listNetworkInterfaces()) {
455 auto face = this->applyMcastConfigToNetif(netif);
456 if (face !=
nullptr) {
458 oldFaces.erase(face);
463 for (
const auto& face : oldFaces) {
void createFace(const CreateFaceParams ¶ms, const FaceCreatedCallback &onCreated, const FaceCreationFailedCallback &onFailure) override
Try to create face using the supplied parameters.
UdpFactory(const CtorParams ¶ms)
FaceCreatedCallback addFace
callback when a new face is created
#define NFD_LOG_DEBUG(expression)
std::set< std::string > providedSchemes
FaceUri schemes provided by this ProtocolFactory.
std::vector< shared_ptr< const Channel > > getChannels() const override
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"
shared_ptr< ndn::net::NetworkMonitor > netmon
NetworkMonitor for listing available network interfaces and monitoring their changes.
shared_ptr< UdpChannel > createChannel(const udp::Endpoint &localEndpoint, time::nanoseconds idleTimeout)
Create UDP-based channel using udp::Endpoint.
#define NFD_REGISTER_PROTOCOL_FACTORY(PF)
registers a protocol factory
void connectFaceClosedSignal(Face &face, const std::function< void()> &f)
invokes a callback when the face is closed
#define NFD_LOG_WARN(expression)
ndn::nfd::FacePersistency persistency
ndn::optional< FaceUri > localUri
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
function< void(uint32_t status, const std::string &reason)> FaceCreationFailedCallback
Prototype for the callback that is invoked when a face fails to be created.
boost::asio::ip::udp::endpoint Endpoint
Provides support for an underlying protocol.
static ndn::optional< ndn::net::NetworkAddress > getV4Address(const ndn::net::NetworkInterface &netif)
void processConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext &context) override
process face_system.udp config section
Parameters to ProtocolFactory constructor.
static const std::string & getId()
#define NFD_LOG_INIT(name)
#define NFD_LOG_TRACE(expression)
Parameters to ProtocolFactory::createFace.
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 multicast UDP face using udp::Endpoint.
function< void(const shared_ptr< Face > &newFace)> FaceCreatedCallback
Prototype for the callback that is invoked when a face is created (in response to an incoming connect...
boost::asio::io_service & getGlobalIoService()