face: implement IPv6 UDP multicast transport
Change-Id: Ib6ab956354dbbba00694c7949fa9ee4639579879 Refs: #4222
This commit is contained in:
committed by
Davide Pesavento
parent
b49313db62
commit
8ce09032ff
@@ -27,6 +27,8 @@
|
||||
#include "socket-utils.hpp"
|
||||
#include "udp-protocol.hpp"
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for std::strerror()
|
||||
@@ -39,8 +41,7 @@ namespace face {
|
||||
NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramTransport, MulticastUdpTransport::protocol,
|
||||
Multicast, "MulticastUdpTransport");
|
||||
|
||||
MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& localEndpoint,
|
||||
const protocol::endpoint& multicastGroup,
|
||||
MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& multicastGroup,
|
||||
protocol::socket&& recvSocket,
|
||||
protocol::socket&& sendSocket,
|
||||
ndn::nfd::LinkType linkType)
|
||||
@@ -48,12 +49,12 @@ MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& localEndp
|
||||
, m_multicastGroup(multicastGroup)
|
||||
, m_sendSocket(std::move(sendSocket))
|
||||
{
|
||||
this->setLocalUri(FaceUri(localEndpoint));
|
||||
this->setLocalUri(FaceUri(m_sendSocket.local_endpoint()));
|
||||
this->setRemoteUri(FaceUri(multicastGroup));
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(linkType);
|
||||
this->setMtu(udp::computeMtu(localEndpoint));
|
||||
this->setMtu(udp::computeMtu(m_sendSocket.local_endpoint()));
|
||||
|
||||
protocol::socket::send_buffer_size sendBufferSizeOption;
|
||||
boost::system::error_code error;
|
||||
@@ -117,16 +118,25 @@ MulticastUdpTransport::openRxSocket(protocol::socket& sock,
|
||||
|
||||
sock.open(multicastGroup.protocol());
|
||||
sock.set_option(protocol::socket::reuse_address(true));
|
||||
sock.bind(protocol::endpoint(multicastGroup.protocol(), multicastGroup.port()));
|
||||
|
||||
if (multicastGroup.address().is_v4()) {
|
||||
BOOST_ASSERT(localAddress.is_v4());
|
||||
sock.bind(multicastGroup);
|
||||
sock.set_option(boost::asio::ip::multicast::join_group(multicastGroup.address().to_v4(),
|
||||
localAddress.to_v4()));
|
||||
}
|
||||
else {
|
||||
// IPv6 multicast is not supported
|
||||
BOOST_ASSERT(false);
|
||||
BOOST_ASSERT(localAddress.is_v6());
|
||||
sock.set_option(boost::asio::ip::v6_only(true));
|
||||
#ifdef WITH_TESTS
|
||||
// To simplify unit tests, we bind to the "any" IPv6 address if the supplied multicast
|
||||
// address lacks a scope id. Calling bind() without a scope id would otherwise fail.
|
||||
if (multicastGroup.address().to_v6().scope_id() == 0)
|
||||
sock.bind(protocol::endpoint(boost::asio::ip::address_v6::any(), multicastGroup.port()));
|
||||
else
|
||||
#endif
|
||||
sock.bind(multicastGroup);
|
||||
sock.set_option(boost::asio::ip::multicast::join_group(multicastGroup.address().to_v6()));
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -149,6 +159,7 @@ MulticastUdpTransport::openRxSocket(protocol::socket& sock,
|
||||
void
|
||||
MulticastUdpTransport::openTxSocket(protocol::socket& sock,
|
||||
const protocol::endpoint& localEndpoint,
|
||||
const shared_ptr<const ndn::net::NetworkInterface>& netif,
|
||||
bool enableLoopback)
|
||||
{
|
||||
BOOST_ASSERT(!sock.is_open());
|
||||
@@ -156,15 +167,17 @@ MulticastUdpTransport::openTxSocket(protocol::socket& sock,
|
||||
sock.open(localEndpoint.protocol());
|
||||
sock.set_option(protocol::socket::reuse_address(true));
|
||||
sock.set_option(boost::asio::ip::multicast::enable_loopback(enableLoopback));
|
||||
sock.bind(localEndpoint);
|
||||
|
||||
if (localEndpoint.address().is_v4()) {
|
||||
sock.bind(localEndpoint);
|
||||
if (!localEndpoint.address().is_unspecified())
|
||||
sock.set_option(boost::asio::ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
|
||||
}
|
||||
else {
|
||||
// IPv6 multicast is not supported
|
||||
BOOST_ASSERT(false);
|
||||
sock.set_option(boost::asio::ip::v6_only(true));
|
||||
sock.bind(localEndpoint);
|
||||
if (netif)
|
||||
sock.set_option(boost::asio::ip::multicast::outbound_interface(netif->getIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,11 +185,17 @@ template<>
|
||||
Transport::EndpointId
|
||||
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep)
|
||||
{
|
||||
// IPv6 multicast is not supported
|
||||
BOOST_ASSERT(ep.address().is_v4());
|
||||
|
||||
return (static_cast<uint64_t>(ep.port()) << 32) |
|
||||
static_cast<uint64_t>(ep.address().to_v4().to_ulong());
|
||||
if (ep.address().is_v4()) {
|
||||
return (static_cast<uint64_t>(ep.port()) << 32) |
|
||||
static_cast<uint64_t>(ep.address().to_v4().to_ulong());
|
||||
}
|
||||
else {
|
||||
size_t seed = 0;
|
||||
const auto& addrBytes = ep.address().to_v6().to_bytes();
|
||||
boost::hash_range(seed, addrBytes.begin(), addrBytes.end());
|
||||
boost::hash_combine(seed, ep.port());
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -59,14 +59,12 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Creates a UDP-based transport for multicast communication
|
||||
* \param localEndpoint local endpoint
|
||||
* \param multicastGroup multicast group
|
||||
* \param recvSocket socket used to receive packets
|
||||
* \param recvSocket socket used to receive multicast packets
|
||||
* \param sendSocket socket used to send to the multicast group
|
||||
* \param linkType either LINK_TYPE_MULTI_ACCESS or LINK_TYPE_AD_HOC
|
||||
* \param linkType either `ndn::nfd::LINK_TYPE_MULTI_ACCESS` or `ndn::nfd::LINK_TYPE_AD_HOC`
|
||||
*/
|
||||
MulticastUdpTransport(const protocol::endpoint& localEndpoint,
|
||||
const protocol::endpoint& multicastGroup,
|
||||
MulticastUdpTransport(const protocol::endpoint& multicastGroup,
|
||||
protocol::socket&& recvSocket,
|
||||
protocol::socket&& sendSocket,
|
||||
ndn::nfd::LinkType linkType);
|
||||
@@ -83,6 +81,7 @@ public:
|
||||
static void
|
||||
openTxSocket(protocol::socket& sock,
|
||||
const protocol::endpoint& localEndpoint,
|
||||
const shared_ptr<const ndn::net::NetworkInterface>& netif = nullptr,
|
||||
bool enableLoopback = false);
|
||||
|
||||
private:
|
||||
|
||||
+107
-66
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -68,6 +68,8 @@ UdpFactory::processConfig(OptionalConfigSection configSection,
|
||||
// mcast yes
|
||||
// mcast_group 224.0.23.170
|
||||
// mcast_port 56363
|
||||
// mcast_group_v6 ff02::1234
|
||||
// mcast_port_v6 56363
|
||||
// mcast_ad_hoc no
|
||||
// whitelist
|
||||
// {
|
||||
@@ -126,6 +128,22 @@ UdpFactory::processConfig(OptionalConfigSection configSection,
|
||||
else if (key == "mcast_port") {
|
||||
mcastConfig.group.port(ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp"));
|
||||
}
|
||||
else if (key == "mcast_group_v6") {
|
||||
const std::string& valueStr = value.get_value<std::string>();
|
||||
boost::system::error_code ec;
|
||||
mcastConfig.groupV6.address(ndn::ip::addressV6FromString(valueStr, ec));
|
||||
if (ec) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group_v6: '" +
|
||||
valueStr + "' cannot be parsed as an IPv6 address"));
|
||||
}
|
||||
else if (!mcastConfig.groupV6.address().is_multicast()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group_v6: '" +
|
||||
valueStr + "' is not a multicast address"));
|
||||
}
|
||||
}
|
||||
else if (key == "mcast_port_v6") {
|
||||
mcastConfig.groupV6.port(ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp"));
|
||||
}
|
||||
else if (key == "mcast_ad_hoc") {
|
||||
bool wantAdHoc = ConfigFile::parseYesNo(pair, "face_system.udp");
|
||||
mcastConfig.linkType = wantAdHoc ? ndn::nfd::LINK_TYPE_AD_HOC : ndn::nfd::LINK_TYPE_MULTI_ACCESS;
|
||||
@@ -181,6 +199,7 @@ UdpFactory::processConfig(OptionalConfigSection configSection,
|
||||
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
|
||||
if (mcastConfig.isEnabled) {
|
||||
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
|
||||
NFD_LOG_INFO("enabling multicast on " << mcastConfig.groupV6);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_INFO("disabling multicast");
|
||||
@@ -191,9 +210,13 @@ UdpFactory::processConfig(OptionalConfigSection configSection,
|
||||
NFD_LOG_WARN("Cannot change ad hoc setting on existing faces");
|
||||
}
|
||||
if (m_mcastConfig.group != mcastConfig.group) {
|
||||
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
|
||||
NFD_LOG_INFO("changing IPv4 multicast group from " << m_mcastConfig.group <<
|
||||
" to " << mcastConfig.group);
|
||||
}
|
||||
if (m_mcastConfig.groupV6 != mcastConfig.groupV6) {
|
||||
NFD_LOG_INFO("changing IPv6 multicast group from " << m_mcastConfig.groupV6 <<
|
||||
" to " << mcastConfig.groupV6);
|
||||
}
|
||||
if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
|
||||
NFD_LOG_INFO("changing whitelist/blacklist");
|
||||
}
|
||||
@@ -262,15 +285,11 @@ UdpFactory::createChannel(const udp::Endpoint& localEndpoint,
|
||||
if (it != m_channels.end())
|
||||
return it->second;
|
||||
|
||||
if (localEndpoint.address().is_multicast()) {
|
||||
BOOST_THROW_EXCEPTION(Error("createChannel is only for unicast channels. The provided endpoint "
|
||||
"is multicast. Use createMulticastFace to create a multicast face"));
|
||||
}
|
||||
|
||||
// check if the endpoint is already used by a multicast face
|
||||
if (m_mcastFaces.find(localEndpoint) != m_mcastFaces.end()) {
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP unicast channel, local "
|
||||
"endpoint is already allocated for a UDP multicast face"));
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create UDP channel on " +
|
||||
boost::lexical_cast<std::string>(localEndpoint) +
|
||||
", endpoint already allocated for a UDP multicast face"));
|
||||
}
|
||||
|
||||
auto channel = std::make_shared<UdpChannel>(localEndpoint, idleTimeout);
|
||||
@@ -286,126 +305,148 @@ UdpFactory::getChannels() const
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
const udp::Endpoint& multicastEndpoint,
|
||||
const shared_ptr<const ndn::net::NetworkInterface>& netif)
|
||||
UdpFactory::createMulticastFace(const shared_ptr<const net::NetworkInterface>& netif,
|
||||
const ip::address& localAddress,
|
||||
const udp::Endpoint& multicastEndpoint)
|
||||
{
|
||||
BOOST_ASSERT(multicastEndpoint.address().is_multicast());
|
||||
BOOST_ASSERT(localEndpoint.port() == multicastEndpoint.port());
|
||||
|
||||
// check if the local and multicast endpoints are already in use for a multicast face
|
||||
auto it = m_mcastFaces.find(localEndpoint);
|
||||
udp::Endpoint localEp(localAddress, multicastEndpoint.port());
|
||||
BOOST_ASSERT(localEp.protocol() == multicastEndpoint.protocol());
|
||||
|
||||
auto mcastEp = multicastEndpoint;
|
||||
if (mcastEp.address().is_v6()) {
|
||||
// in IPv6, a scope id on the multicast address is always required
|
||||
auto mcastAddress = mcastEp.address().to_v6();
|
||||
mcastAddress.scope_id(netif->getIndex());
|
||||
mcastEp.address(mcastAddress);
|
||||
}
|
||||
|
||||
// check if the local endpoint is already used by another multicast face
|
||||
auto it = m_mcastFaces.find(localEp);
|
||||
if (it != m_mcastFaces.end()) {
|
||||
if (it->second->getRemoteUri() == FaceUri(multicastEndpoint))
|
||||
if (it->second->getRemoteUri() == FaceUri(mcastEp))
|
||||
return it->second;
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, local "
|
||||
"endpoint is already allocated for a UDP multicast face "
|
||||
"on a different multicast group"));
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create UDP multicast face on " +
|
||||
boost::lexical_cast<std::string>(localEp) +
|
||||
", endpoint already allocated for a different UDP multicast face"));
|
||||
}
|
||||
|
||||
// check if the local endpoint is already used by a unicast channel
|
||||
if (m_channels.find(localEndpoint) != m_channels.end()) {
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, local "
|
||||
"endpoint is already allocated for a UDP unicast channel"));
|
||||
}
|
||||
|
||||
if (localEndpoint.address().is_v6() || multicastEndpoint.address().is_v6()) {
|
||||
BOOST_THROW_EXCEPTION(Error("IPv6 multicast is not supported yet. Please provide an IPv4 "
|
||||
"address"));
|
||||
if (m_channels.find(localEp) != m_channels.end()) {
|
||||
BOOST_THROW_EXCEPTION(Error("Cannot create UDP multicast face on " +
|
||||
boost::lexical_cast<std::string>(localEp) +
|
||||
", endpoint already allocated for a UDP channel"));
|
||||
}
|
||||
|
||||
ip::udp::socket rxSock(getGlobalIoService());
|
||||
MulticastUdpTransport::openRxSocket(rxSock, multicastEndpoint, localEndpoint.address(), netif);
|
||||
MulticastUdpTransport::openRxSocket(rxSock, mcastEp, localAddress, netif);
|
||||
ip::udp::socket txSock(getGlobalIoService());
|
||||
MulticastUdpTransport::openTxSocket(txSock, localEndpoint);
|
||||
MulticastUdpTransport::openTxSocket(txSock, udp::Endpoint(localAddress, 0), netif);
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>();
|
||||
auto transport = make_unique<MulticastUdpTransport>(localEndpoint, multicastEndpoint,
|
||||
std::move(rxSock), std::move(txSock),
|
||||
auto transport = make_unique<MulticastUdpTransport>(mcastEp, std::move(rxSock), std::move(txSock),
|
||||
m_mcastConfig.linkType);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_mcastFaces[localEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEndpoint] { m_mcastFaces.erase(localEndpoint); });
|
||||
m_mcastFaces[localEp] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEp] { m_mcastFaces.erase(localEp); });
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
static ndn::optional<ip::address>
|
||||
getV4Address(const net::NetworkInterface& netif)
|
||||
pickAddress(const net::NetworkInterface& netif, net::AddressFamily af)
|
||||
{
|
||||
for (const auto& na : netif.getNetworkAddresses()) {
|
||||
if (na.getFamily() == net::AddressFamily::V4 && na.getScope() != net::AddressScope::NOWHERE) {
|
||||
if (na.getFamily() == af &&
|
||||
(na.getScope() == net::AddressScope::LINK || na.getScope() == net::AddressScope::GLOBAL)) {
|
||||
return na.getIp();
|
||||
}
|
||||
}
|
||||
return ndn::nullopt;
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
std::vector<shared_ptr<Face>>
|
||||
UdpFactory::applyMcastConfigToNetif(const shared_ptr<const net::NetworkInterface>& netif)
|
||||
{
|
||||
BOOST_ASSERT(netif != nullptr);
|
||||
|
||||
if (!m_mcastConfig.isEnabled) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!netif->isUp()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif->getName() << ": netif is down");
|
||||
return nullptr;
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": netif is down");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (netif->isLoopback()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": netif is loopback");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!netif->canMulticast()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif->getName() << ": netif cannot multicast");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto address = getV4Address(*netif);
|
||||
if (!address) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif->getName() << ": no IPv4 address");
|
||||
// keep an eye on new addresses
|
||||
m_netifConns[netif->getIndex()].addrAddConn =
|
||||
netif->onAddressAdded.connectSingleShot(bind(&UdpFactory::applyMcastConfigToNetif, this, netif));
|
||||
return nullptr;
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": netif cannot multicast");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_mcastConfig.netifPredicate(*netif)) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif->getName() << ": rejected by whitelist/blacklist");
|
||||
return nullptr;
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": rejected by whitelist/blacklist");
|
||||
return {};
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("Creating multicast face on " << netif->getName());
|
||||
|
||||
udp::Endpoint localEndpoint(*address, m_mcastConfig.group.port());
|
||||
auto face = this->createMulticastFace(localEndpoint, m_mcastConfig.group, netif);
|
||||
if (face->getId() == INVALID_FACEID) {
|
||||
// new face: register with forwarding
|
||||
this->addFace(face);
|
||||
std::vector<ip::address> addrs;
|
||||
for (auto af : {net::AddressFamily::V4, net::AddressFamily::V6}) {
|
||||
auto addr = pickAddress(*netif, af);
|
||||
if (addr)
|
||||
addrs.push_back(*addr);
|
||||
}
|
||||
|
||||
return face;
|
||||
if (addrs.empty()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": no viable IP address");
|
||||
// keep an eye on new addresses
|
||||
m_netifConns[netif->getIndex()].addrAddConn =
|
||||
netif->onAddressAdded.connect(bind(&UdpFactory::applyMcastConfigToNetif, this, netif));
|
||||
return {};
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("Creating multicast faces on " << netif->getName());
|
||||
|
||||
std::vector<shared_ptr<Face>> faces;
|
||||
for (const auto& addr : addrs) {
|
||||
auto face = this->createMulticastFace(netif, addr,
|
||||
addr.is_v4() ? m_mcastConfig.group : m_mcastConfig.groupV6);
|
||||
if (face->getId() == INVALID_FACEID) {
|
||||
// new face: register with forwarding
|
||||
this->addFace(face);
|
||||
}
|
||||
faces.push_back(std::move(face));
|
||||
}
|
||||
|
||||
return faces;
|
||||
}
|
||||
|
||||
void
|
||||
UdpFactory::applyMcastConfig(const FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// collect old faces
|
||||
std::set<shared_ptr<Face>> oldFaces;
|
||||
boost::copy(m_mcastFaces | boost::adaptors::map_values, std::inserter(oldFaces, oldFaces.end()));
|
||||
std::set<shared_ptr<Face>> facesToClose;
|
||||
boost::copy(m_mcastFaces | boost::adaptors::map_values,
|
||||
std::inserter(facesToClose, facesToClose.end()));
|
||||
|
||||
// create faces if requested by config
|
||||
for (const auto& netif : netmon->listNetworkInterfaces()) {
|
||||
auto face = this->applyMcastConfigToNetif(netif);
|
||||
if (face != nullptr) {
|
||||
auto facesToKeep = this->applyMcastConfigToNetif(netif);
|
||||
for (const auto& face : facesToKeep) {
|
||||
// don't destroy face
|
||||
oldFaces.erase(face);
|
||||
facesToClose.erase(face);
|
||||
}
|
||||
}
|
||||
|
||||
// destroy old faces that are not needed in new configuration
|
||||
for (const auto& face : oldFaces) {
|
||||
for (const auto& face : facesToClose) {
|
||||
face->close();
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -99,30 +99,31 @@ public:
|
||||
*
|
||||
* The face will join the specified multicast group.
|
||||
*
|
||||
* If this method is called twice with the same pair of endpoints, only one
|
||||
* If this method is called twice with the same set of arguments, only one
|
||||
* face will be created. The second call will just return the existing face.
|
||||
*
|
||||
* If a UDP channel, unicast face, or multicast face already exists on the
|
||||
* same local endpoint, the creation fails and an exception is thrown.
|
||||
* same combination of local address and multicast port, the creation fails
|
||||
* and an exception is thrown.
|
||||
*
|
||||
* \param localEndpoint the local endpoint
|
||||
* \param multicastEndpoint the multicast endpoint
|
||||
* \param netif the network interface to which the face will be bound
|
||||
* \param localAddress the local IP address to which the face will be bound
|
||||
* \param multicastEndpoint the multicast endpoint (multicast group and port number)
|
||||
*
|
||||
* \return always a valid shared pointer to the created face;
|
||||
* an exception is thrown if the face cannot be created.
|
||||
* \throw UdpFactory::Error
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
const udp::Endpoint& multicastEndpoint,
|
||||
const shared_ptr<const ndn::net::NetworkInterface>& netif);
|
||||
createMulticastFace(const shared_ptr<const ndn::net::NetworkInterface>& netif,
|
||||
const boost::asio::ip::address& localAddress,
|
||||
const udp::Endpoint& multicastEndpoint);
|
||||
|
||||
private:
|
||||
/** \brief Create UDP multicast face on \p netif if needed by \p m_mcastConfig
|
||||
* \return new or existing face, or nullptr if no face should be created
|
||||
/** \brief Create UDP multicast faces on \p netif if needed by \p m_mcastConfig
|
||||
* \return list of faces (just created or already existing) on \p netif
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
std::vector<shared_ptr<Face>>
|
||||
applyMcastConfigToNetif(const shared_ptr<const ndn::net::NetworkInterface>& netif);
|
||||
|
||||
/** \brief Create and destroy UDP multicast faces according to \p m_mcastConfig
|
||||
@@ -137,6 +138,7 @@ private:
|
||||
{
|
||||
bool isEnabled = false;
|
||||
udp::Endpoint group = udp::getDefaultMulticastGroup();
|
||||
udp::Endpoint groupV6 = udp::getDefaultMulticastGroupV6();
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS;
|
||||
NetworkInterfacePredicate netifPredicate;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -38,15 +38,22 @@ typedef boost::asio::ip::udp::endpoint Endpoint;
|
||||
ssize_t
|
||||
computeMtu(const Endpoint& localEndpoint);
|
||||
|
||||
/** \return default multicast group: 224.0.23.170:56363
|
||||
/** \return default IPv4 multicast group: 224.0.23.170:56363
|
||||
*/
|
||||
inline Endpoint
|
||||
getDefaultMulticastGroup()
|
||||
{
|
||||
// 224.0.23.170:56363
|
||||
return {boost::asio::ip::address_v4(0xE00017AA), 56363};
|
||||
}
|
||||
|
||||
/** \return default IPv6 multicast group: [FF02::1234]:56363
|
||||
*/
|
||||
inline Endpoint
|
||||
getDefaultMulticastGroupV6()
|
||||
{
|
||||
return {boost::asio::ip::address_v6::from_string("FF02::1234"), 56363};
|
||||
}
|
||||
|
||||
} // namespace udp
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
+4
-2
@@ -127,8 +127,10 @@ face_system
|
||||
; sudo setcap cap_net_raw=eip /path/to/nfd
|
||||
;
|
||||
mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
|
||||
mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
|
||||
mcast_port 56363 ; UDP multicast port number
|
||||
mcast_group 224.0.23.170 ; UDP multicast group (IPv4)
|
||||
mcast_port 56363 ; UDP multicast port number (IPv4)
|
||||
mcast_group_v6 ff02::1234 ; UDP multicast group (IPv6)
|
||||
mcast_port_v6 56363 ; UDP multicast port number (IPv6)
|
||||
mcast_ad_hoc no ; set to 'yes' to make all UDP multicast faces "ad hoc", default 'no'
|
||||
|
||||
; Whitelist and blacklist can contain, in no particular order:
|
||||
|
||||
@@ -39,7 +39,9 @@ BOOST_AUTO_TEST_SUITE(TestDatagramTransport)
|
||||
|
||||
using DatagramTransportFixtures = boost::mpl::vector<
|
||||
GENERATE_IP_TRANSPORT_FIXTURE_INSTANTIATIONS(UnicastUdpTransportFixture),
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V4, AddressScope::Global, MulticastInterface::Yes>
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V4, AddressScope::Global, MulticastInterface::Yes>,
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::LinkLocal, MulticastInterface::Yes>,
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::Global, MulticastInterface::Yes>
|
||||
>;
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE_TEMPLATE(Send, T, DatagramTransportFixtures, T)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -45,7 +45,7 @@ class MulticastUdpTransportFixture : public BaseFixture
|
||||
protected:
|
||||
MulticastUdpTransportFixture()
|
||||
: transport(nullptr)
|
||||
, multicastEp(ip::address::from_string("230.15.19.47"), 7070)
|
||||
, txPort(7001)
|
||||
, receivedPackets(nullptr)
|
||||
, remoteSockRx(g_io)
|
||||
, remoteSockTx(g_io)
|
||||
@@ -55,21 +55,32 @@ protected:
|
||||
void
|
||||
initialize(ip::address address)
|
||||
{
|
||||
localEp = udp::endpoint(address, 7001);
|
||||
ip::address mcastAddr;
|
||||
if (address.is_v4()) {
|
||||
// the administratively scoped group 224.0.0.254 is reserved for experimentation (RFC 4727)
|
||||
mcastAddr = ip::address_v4(0xE00000FE);
|
||||
}
|
||||
else {
|
||||
// the group FF0X::114 is reserved for experimentation at all scope levels (RFC 4727)
|
||||
auto v6Addr = ip::address_v6::from_string("FF01::114");
|
||||
v6Addr.scope_id(address.to_v6().scope_id());
|
||||
mcastAddr = v6Addr;
|
||||
}
|
||||
mcastEp = udp::endpoint(mcastAddr, 7373);
|
||||
remoteMcastEp = udp::endpoint(mcastAddr, 8383);
|
||||
|
||||
MulticastUdpTransport::openRxSocket(remoteSockRx, multicastEp, ip::address_v4::any());
|
||||
MulticastUdpTransport::openTxSocket(remoteSockTx, udp::endpoint(udp::v4(), 0), true);
|
||||
MulticastUdpTransport::openRxSocket(remoteSockRx, mcastEp, address);
|
||||
MulticastUdpTransport::openTxSocket(remoteSockTx, udp::endpoint(address, 0), nullptr, true);
|
||||
|
||||
udp::socket sockRx(g_io);
|
||||
udp::socket sockTx(g_io);
|
||||
MulticastUdpTransport::openRxSocket(sockRx, udp::endpoint(multicastEp.address(), localEp.port()),
|
||||
ip::address_v4::any());
|
||||
MulticastUdpTransport::openTxSocket(sockTx, udp::endpoint(udp::v4(), 0), true);
|
||||
MulticastUdpTransport::openRxSocket(sockRx, remoteMcastEp, address);
|
||||
MulticastUdpTransport::openTxSocket(sockTx, udp::endpoint(address, txPort), nullptr, true);
|
||||
|
||||
face = make_unique<Face>(
|
||||
make_unique<DummyReceiveLinkService>(),
|
||||
make_unique<MulticastUdpTransport>(localEp, multicastEp, std::move(sockRx),
|
||||
std::move(sockTx), ndn::nfd::LINK_TYPE_MULTI_ACCESS));
|
||||
make_unique<MulticastUdpTransport>(mcastEp, std::move(sockRx), std::move(sockTx),
|
||||
ndn::nfd::LINK_TYPE_MULTI_ACCESS));
|
||||
transport = static_cast<MulticastUdpTransport*>(face->getTransport());
|
||||
receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
|
||||
|
||||
@@ -92,24 +103,31 @@ protected:
|
||||
void
|
||||
remoteWrite(const std::vector<uint8_t>& buf, bool needToCheck = true)
|
||||
{
|
||||
remoteSockTx.async_send_to(boost::asio::buffer(buf), udp::endpoint(multicastEp.address(), 7001),
|
||||
sendToGroup(remoteSockTx, buf, needToCheck);
|
||||
limitedIo.defer(time::seconds(1));
|
||||
}
|
||||
|
||||
void
|
||||
sendToGroup(udp::socket& sock, const std::vector<uint8_t>& buf, bool needToCheck = true) const
|
||||
{
|
||||
sock.async_send_to(boost::asio::buffer(buf), remoteMcastEp,
|
||||
[needToCheck] (const boost::system::error_code& error, size_t) {
|
||||
if (needToCheck) {
|
||||
BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
|
||||
}
|
||||
});
|
||||
limitedIo.defer(time::seconds(1));
|
||||
}
|
||||
|
||||
protected:
|
||||
LimitedIo limitedIo;
|
||||
MulticastUdpTransport* transport;
|
||||
udp::endpoint localEp;
|
||||
udp::endpoint multicastEp;
|
||||
udp::endpoint mcastEp;
|
||||
uint16_t txPort;
|
||||
std::vector<Transport::Packet>* receivedPackets;
|
||||
|
||||
private:
|
||||
unique_ptr<Face> face;
|
||||
udp::endpoint remoteMcastEp;
|
||||
udp::socket remoteSockRx;
|
||||
udp::socket remoteSockTx;
|
||||
};
|
||||
|
||||
@@ -36,17 +36,15 @@ namespace tests {
|
||||
BOOST_AUTO_TEST_SUITE(Face)
|
||||
|
||||
using MulticastUdpTransportFixtureWithAddress =
|
||||
// TODO: change to AddressFamily::Any after IPv6 support is implemented
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V4,
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::Any,
|
||||
AddressScope::Global, MulticastInterface::Yes>;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(TestMulticastUdpTransport, MulticastUdpTransportFixtureWithAddress)
|
||||
|
||||
using MulticastUdpTransportFixtures = boost::mpl::vector<
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V4, AddressScope::Global, MulticastInterface::Yes>
|
||||
// TODO: IPv6 not supported yet
|
||||
//IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::LinkLocal, MulticastInterface::Yes>,
|
||||
//IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::Global, MulticastInterface::Yes>
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V4, AddressScope::Global, MulticastInterface::Yes>,
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::LinkLocal, MulticastInterface::Yes>,
|
||||
IpTransportFixture<MulticastUdpTransportFixture, AddressFamily::V6, AddressScope::Global, MulticastInterface::Yes>
|
||||
>;
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE_TEMPLATE(StaticProperties, T, MulticastUdpTransportFixtures, T)
|
||||
@@ -55,8 +53,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(StaticProperties, T, MulticastUdpTransportFixtu
|
||||
|
||||
checkStaticPropertiesInitialized(*this->transport);
|
||||
|
||||
BOOST_CHECK_EQUAL(this->transport->getLocalUri(), FaceUri(udp::endpoint(this->address, this->localEp.port())));
|
||||
BOOST_CHECK_EQUAL(this->transport->getRemoteUri(), FaceUri(this->multicastEp));
|
||||
BOOST_CHECK_EQUAL(this->transport->getLocalUri(), FaceUri(udp::endpoint(this->address, this->txPort)));
|
||||
BOOST_CHECK_EQUAL(this->transport->getRemoteUri(), FaceUri(this->mcastEp));
|
||||
BOOST_CHECK_EQUAL(this->transport->getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
BOOST_CHECK_EQUAL(this->transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
BOOST_CHECK_EQUAL(this->transport->getLinkType(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
@@ -78,9 +76,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(ReceiveMultipleRemoteEndpoints, T, MulticastUdp
|
||||
{
|
||||
TRANSPORT_TEST_INIT();
|
||||
|
||||
// remoteSockRx2 unnecessary for this test case - only remoteSockTx2 is needed
|
||||
// we need a second remote tx socket for this test case
|
||||
udp::socket remoteSockTx2(this->g_io);
|
||||
MulticastUdpTransport::openTxSocket(remoteSockTx2, udp::endpoint(udp::v4(), 7071), true);
|
||||
MulticastUdpTransport::openTxSocket(remoteSockTx2, udp::endpoint(this->address, 0), nullptr, true);
|
||||
|
||||
Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
|
||||
ndn::Buffer buf1(pkt1.begin(), pkt1.end());
|
||||
@@ -98,15 +96,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(ReceiveMultipleRemoteEndpoints, T, MulticastUdp
|
||||
BOOST_CHECK_EQUAL(this->receivedPackets->at(0).remoteEndpoint,
|
||||
this->receivedPackets->at(1).remoteEndpoint);
|
||||
|
||||
udp::endpoint destEp(this->multicastEp.address(), this->localEp.port());
|
||||
remoteSockTx2.async_send_to(boost::asio::buffer(buf1), destEp,
|
||||
[] (const boost::system::error_code& error, size_t) {
|
||||
BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
|
||||
});
|
||||
remoteSockTx2.async_send_to(boost::asio::buffer(buf2), destEp,
|
||||
[] (const boost::system::error_code& error, size_t) {
|
||||
BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
|
||||
});
|
||||
this->sendToGroup(remoteSockTx2, buf1);
|
||||
this->sendToGroup(remoteSockTx2, buf2);
|
||||
this->limitedIo.defer(time::seconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(this->transport->getCounters().nInPackets, 4);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "factory-test-common.hpp"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/range/algorithm/count_if.hpp>
|
||||
#include <ndn-cxx/net/address-converter.hpp>
|
||||
|
||||
namespace nfd {
|
||||
@@ -53,22 +52,54 @@ protected:
|
||||
UdpFactoryMcastFixture()
|
||||
{
|
||||
for (const auto& netif : collectNetworkInterfaces()) {
|
||||
if (netif->isUp() && netif->canMulticast() &&
|
||||
hasAddressFamily(*netif, ndn::net::AddressFamily::V4)) {
|
||||
netifs.push_back(netif);
|
||||
// same filtering logic as UdpFactory::applyMcastConfigToNetif()
|
||||
if (netif->isUp() && !netif->isLoopback() && netif->canMulticast()) {
|
||||
bool hasValidIpAddress = false;
|
||||
if (hasAddressFamily(*netif, ndn::net::AddressFamily::V4)) {
|
||||
hasValidIpAddress = true;
|
||||
netifsV4.push_back(netif);
|
||||
}
|
||||
if (hasAddressFamily(*netif, ndn::net::AddressFamily::V6)) {
|
||||
hasValidIpAddress = true;
|
||||
netifsV6.push_back(netif);
|
||||
}
|
||||
if (hasValidIpAddress) {
|
||||
netifs.push_back(netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->copyRealNetifsToNetmon();
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const std::string& localIp, const std::string& mcastIp, uint16_t mcastPort)
|
||||
{
|
||||
BOOST_ASSERT(!netifs.empty());
|
||||
udp::Endpoint localEndpoint(ndn::ip::addressFromString(localIp), mcastPort);
|
||||
auto localAddress = ndn::ip::addressFromString(localIp);
|
||||
udp::Endpoint mcastEndpoint(ndn::ip::addressFromString(mcastIp), mcastPort);
|
||||
return factory.createMulticastFace(localEndpoint, mcastEndpoint, netifs.front());
|
||||
|
||||
if (localAddress.is_v4()) {
|
||||
BOOST_ASSERT(!netifsV4.empty());
|
||||
return factory.createMulticastFace(netifsV4.front(), localAddress, mcastEndpoint);
|
||||
}
|
||||
else {
|
||||
BOOST_ASSERT(!netifsV6.empty());
|
||||
return factory.createMulticastFace(netifsV6.front(), localAddress, mcastEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief returns a non-loopback IP address suitable for the creation of a UDP multicast face
|
||||
*/
|
||||
boost::asio::ip::address
|
||||
findNonLoopbackAddressForMulticastFace(ndn::net::AddressFamily af) const
|
||||
{
|
||||
const auto& netifList = af == ndn::net::AddressFamily::V4 ? netifsV4 : netifsV6;
|
||||
for (const auto& netif : netifList) {
|
||||
for (const auto& a : netif->getNetworkAddresses()) {
|
||||
if (a.getFamily() == af && !a.getIp().is_loopback())
|
||||
return a.getIp();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<const Face*>
|
||||
@@ -77,7 +108,13 @@ protected:
|
||||
return this->listFacesByScheme("udp4", linkType);
|
||||
}
|
||||
|
||||
/** \brief determine whether \p netif has at least one address of the given family
|
||||
std::vector<const Face*>
|
||||
listUdp6McastFaces(ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS) const
|
||||
{
|
||||
return this->listFacesByScheme("udp6", linkType);
|
||||
}
|
||||
|
||||
/** \brief determine whether \p netif has at least one IP address of the given family
|
||||
*/
|
||||
static bool
|
||||
hasAddressFamily(const NetworkInterface& netif, ndn::net::AddressFamily af)
|
||||
@@ -89,17 +126,27 @@ protected:
|
||||
/** \brief determine whether a UDP multicast face is created on \p netif
|
||||
*/
|
||||
static bool
|
||||
isFaceOnNetif(const Face& face, const shared_ptr<const NetworkInterface>& netif)
|
||||
isFaceOnNetif(const Face& face, const NetworkInterface& netif)
|
||||
{
|
||||
auto ip = boost::asio::ip::address_v4::from_string(face.getLocalUri().getHost());
|
||||
return std::any_of(netif->getNetworkAddresses().begin(), netif->getNetworkAddresses().end(),
|
||||
auto ip = ndn::ip::addressFromString(face.getLocalUri().getHost());
|
||||
return std::any_of(netif.getNetworkAddresses().begin(), netif.getNetworkAddresses().end(),
|
||||
[ip] (const NetworkAddress& a) { return a.getIp() == ip; });
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief MulticastUdpTransport-capable network interfaces
|
||||
/** \brief MulticastUdpTransport-capable network interfaces (IPv4 + IPv6)
|
||||
*
|
||||
* This should be used in test cases that do not depend on a specific address family
|
||||
*/
|
||||
std::vector<shared_ptr<const NetworkInterface>> netifs;
|
||||
|
||||
/** \brief MulticastUdpTransport-capable network interfaces (IPv4 only)
|
||||
*/
|
||||
std::vector<shared_ptr<const NetworkInterface>> netifsV4;
|
||||
|
||||
/** \brief MulticastUdpTransport-capable network interfaces (IPv6 only)
|
||||
*/
|
||||
std::vector<shared_ptr<const NetworkInterface>> netifsV6;
|
||||
};
|
||||
|
||||
#define SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(n) \
|
||||
@@ -111,6 +158,24 @@ protected:
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define SKIP_IF_UDP_MCAST_V4_NETIF_COUNT_LT(n) \
|
||||
do { \
|
||||
if (this->netifsV4.size() < (n)) { \
|
||||
BOOST_WARN_MESSAGE(false, "skipping assertions that require " #n \
|
||||
" or more IPv4 MulticastUdpTransport-capable network interfaces"); \
|
||||
return; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define SKIP_IF_UDP_MCAST_V6_NETIF_COUNT_LT(n) \
|
||||
do { \
|
||||
if (this->netifsV6.size() < (n)) { \
|
||||
BOOST_WARN_MESSAGE(false, "skipping assertions that require " #n \
|
||||
" or more IPv6 MulticastUdpTransport-capable network interfaces"); \
|
||||
return; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Face)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestUdpFactory, UdpFactoryFixture)
|
||||
|
||||
@@ -184,11 +249,6 @@ BOOST_AUTO_TEST_CASE(ChannelV6)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(EnableDisableMcast, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
|
||||
const std::string CONFIG_WITH_MCAST = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
@@ -210,22 +270,28 @@ BOOST_FIXTURE_TEST_CASE(EnableDisableMcast, UdpFactoryMcastFixture)
|
||||
|
||||
parseConfig(CONFIG_WITHOUT_MCAST, false);
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces().size(), 0);
|
||||
BOOST_CHECK_EQUAL(this->listUdp6McastFaces().size(), 0);
|
||||
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
#ifdef __linux__
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
|
||||
parseConfig(CONFIG_WITH_MCAST, false);
|
||||
g_io.poll();
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces().size(), netifs.size());
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces().size(), netifsV4.size());
|
||||
BOOST_CHECK_EQUAL(this->listUdp6McastFaces().size(), netifsV6.size());
|
||||
|
||||
parseConfig(CONFIG_WITHOUT_MCAST, false);
|
||||
g_io.poll();
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces().size(), 0);
|
||||
BOOST_CHECK_EQUAL(this->listUdp6McastFaces().size(), 0);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(McastAdHoc, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
@@ -241,16 +307,17 @@ BOOST_FIXTURE_TEST_CASE(McastAdHoc, UdpFactoryMcastFixture)
|
||||
)CONFIG";
|
||||
|
||||
parseConfig(CONFIG, false);
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces(ndn::nfd::LINK_TYPE_AD_HOC).size(), netifs.size());
|
||||
BOOST_CHECK_EQUAL(this->listUdp4McastFaces(ndn::nfd::LINK_TYPE_AD_HOC).size(), netifsV4.size());
|
||||
BOOST_CHECK_EQUAL(this->listUdp6McastFaces(ndn::nfd::LINK_TYPE_AD_HOC).size(), netifsV6.size());
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(ChangeMcastEndpoint, UdpFactoryMcastFixture)
|
||||
BOOST_FIXTURE_TEST_CASE(ChangeMcastEndpointV4, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
SKIP_IF_UDP_MCAST_V4_NETIF_COUNT_LT(1);
|
||||
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
face_system
|
||||
@@ -275,22 +342,65 @@ BOOST_FIXTURE_TEST_CASE(ChangeMcastEndpoint, UdpFactoryMcastFixture)
|
||||
|
||||
parseConfig(CONFIG1, false);
|
||||
auto udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifs.size());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(),
|
||||
FaceUri("udp4://239.66.30.1:7011"));
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifsV4.size());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(), FaceUri("udp4://239.66.30.1:7011"));
|
||||
|
||||
parseConfig(CONFIG2, false);
|
||||
g_io.poll();
|
||||
udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifs.size());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(),
|
||||
FaceUri("udp4://239.66.30.2:7012"));
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifsV4.size());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(), FaceUri("udp4://239.66.30.2:7012"));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(ChangeMcastEndpointV6, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_V6_NETIF_COUNT_LT(1);
|
||||
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_group_v6 ff02::1101
|
||||
mcast_port_v6 7011
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
const std::string CONFIG2 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_group_v6 ff02::1102
|
||||
mcast_port_v6 7012
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
parseConfig(CONFIG1, false);
|
||||
auto udpMcastFaces = this->listUdp6McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifsV6.size());
|
||||
auto expectedAddr = boost::asio::ip::address_v6::from_string("ff02::1101");
|
||||
expectedAddr.scope_id(netifsV6.front()->getIndex());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(), FaceUri(udp::Endpoint(expectedAddr, 7011)));
|
||||
|
||||
parseConfig(CONFIG2, false);
|
||||
g_io.poll();
|
||||
udpMcastFaces = this->listUdp6McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), netifsV6.size());
|
||||
expectedAddr = boost::asio::ip::address_v6::from_string("ff02::1102");
|
||||
expectedAddr.scope_id(netifsV6.front()->getIndex());
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.front()->getRemoteUri(), FaceUri(udp::Endpoint(expectedAddr, 7012)));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Whitelist, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
@@ -310,15 +420,21 @@ BOOST_FIXTURE_TEST_CASE(Whitelist, UdpFactoryMcastFixture)
|
||||
boost::replace_first(CONFIG, "%ifname", netifs.front()->getName());
|
||||
|
||||
parseConfig(CONFIG, false);
|
||||
|
||||
auto udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(isFaceOnNetif(*udpMcastFaces.front(), netifs.front()));
|
||||
BOOST_CHECK_LE(udpMcastFaces.size(), 1);
|
||||
auto udpMcastFacesV6 = this->listUdp6McastFaces();
|
||||
BOOST_CHECK_LE(udpMcastFacesV6.size(), 1);
|
||||
udpMcastFaces.insert(udpMcastFaces.end(), udpMcastFacesV6.begin(), udpMcastFacesV6.end());
|
||||
BOOST_CHECK_GE(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(std::all_of(udpMcastFaces.begin(), udpMcastFaces.end(),
|
||||
[this] (const Face* face) { return isFaceOnNetif(*face, *netifs.front()); }));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Blacklist, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
@@ -338,17 +454,21 @@ BOOST_FIXTURE_TEST_CASE(Blacklist, UdpFactoryMcastFixture)
|
||||
boost::replace_first(CONFIG, "%ifname", netifs.front()->getName());
|
||||
|
||||
parseConfig(CONFIG, false);
|
||||
|
||||
auto udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_CHECK_EQUAL(udpMcastFaces.size(), netifs.size() - 1);
|
||||
BOOST_CHECK_EQUAL(boost::count_if(udpMcastFaces, [this] (const Face* face) {
|
||||
return isFaceOnNetif(*face, netifs.front());
|
||||
}), 0);
|
||||
BOOST_CHECK_GE(udpMcastFaces.size(), netifsV4.size() - 1);
|
||||
auto udpMcastFacesV6 = this->listUdp6McastFaces();
|
||||
BOOST_CHECK_GE(udpMcastFacesV6.size(), netifsV6.size() - 1);
|
||||
udpMcastFaces.insert(udpMcastFaces.end(), udpMcastFacesV6.begin(), udpMcastFacesV6.end());
|
||||
BOOST_CHECK_LT(udpMcastFaces.size(), netifsV4.size() + netifsV6.size());
|
||||
BOOST_CHECK(std::none_of(udpMcastFaces.begin(), udpMcastFaces.end(),
|
||||
[this] (const Face* face) { return isFaceOnNetif(*face, *netifs.front()); }));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(ChangePredicate, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(2);
|
||||
@@ -370,15 +490,23 @@ BOOST_FIXTURE_TEST_CASE(ChangePredicate, UdpFactoryMcastFixture)
|
||||
boost::replace_first(CONFIG2, "%ifname", netifs.back()->getName());
|
||||
|
||||
parseConfig(CONFIG1, false);
|
||||
|
||||
auto udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(isFaceOnNetif(*udpMcastFaces.front(), netifs.front()));
|
||||
auto udpMcastFacesV6 = this->listUdp6McastFaces();
|
||||
udpMcastFaces.insert(udpMcastFaces.end(), udpMcastFacesV6.begin(), udpMcastFacesV6.end());
|
||||
BOOST_CHECK_GE(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(std::all_of(udpMcastFaces.begin(), udpMcastFaces.end(),
|
||||
[this] (const Face* face) { return isFaceOnNetif(*face, *netifs.front()); }));
|
||||
|
||||
parseConfig(CONFIG2, false);
|
||||
g_io.poll();
|
||||
|
||||
udpMcastFaces = this->listUdp4McastFaces();
|
||||
BOOST_REQUIRE_EQUAL(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(isFaceOnNetif(*udpMcastFaces.front(), netifs.back()));
|
||||
udpMcastFacesV6 = this->listUdp6McastFaces();
|
||||
udpMcastFaces.insert(udpMcastFaces.end(), udpMcastFacesV6.begin(), udpMcastFacesV6.end());
|
||||
BOOST_CHECK_GE(udpMcastFaces.size(), 1);
|
||||
BOOST_CHECK(std::all_of(udpMcastFaces.begin(), udpMcastFaces.end(),
|
||||
[this] (const Face* face) { return isFaceOnNetif(*face, *netifs.back()); }));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Omitted)
|
||||
@@ -394,6 +522,7 @@ BOOST_AUTO_TEST_CASE(Omitted)
|
||||
|
||||
BOOST_CHECK_EQUAL(factory.getChannels().size(), 0);
|
||||
BOOST_CHECK_EQUAL(this->listFacesByScheme("udp4", ndn::nfd::LINK_TYPE_MULTI_ACCESS).size(), 0);
|
||||
BOOST_CHECK_EQUAL(this->listFacesByScheme("udp6", ndn::nfd::LINK_TYPE_MULTI_ACCESS).size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(AllDisabled)
|
||||
@@ -446,7 +575,7 @@ BOOST_AUTO_TEST_CASE(BadMcast)
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(BadMcastGroup)
|
||||
BOOST_AUTO_TEST_CASE(BadMcastGroupV4)
|
||||
{
|
||||
// not an address
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
@@ -491,7 +620,52 @@ BOOST_AUTO_TEST_CASE(BadMcastGroup)
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG3, false), ConfigFile::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(BadMcastPort)
|
||||
BOOST_AUTO_TEST_CASE(BadMcastGroupV6)
|
||||
{
|
||||
// not an address
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_group_v6 foo
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG1, true), ConfigFile::Error);
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG1, false), ConfigFile::Error);
|
||||
|
||||
// non-multicast address
|
||||
const std::string CONFIG2 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_group_v6 fe80::1234
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG2, true), ConfigFile::Error);
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG2, false), ConfigFile::Error);
|
||||
|
||||
// wrong address family
|
||||
const std::string CONFIG3 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_group_v6 224.0.23.170
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG3, true), ConfigFile::Error);
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG3, false), ConfigFile::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(BadMcastPortV4)
|
||||
{
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
face_system
|
||||
@@ -520,6 +694,35 @@ BOOST_AUTO_TEST_CASE(BadMcastPort)
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG2, false), ConfigFile::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(BadMcastPortV6)
|
||||
{
|
||||
const std::string CONFIG1 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_port_v6 bar
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG1, true), ConfigFile::Error);
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG1, false), ConfigFile::Error);
|
||||
|
||||
const std::string CONFIG2 = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
udp
|
||||
{
|
||||
mcast_port_v6 99999
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG2, true), ConfigFile::Error);
|
||||
BOOST_CHECK_THROW(parseConfig(CONFIG2, false), ConfigFile::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UnknownOption)
|
||||
{
|
||||
const std::string CONFIG = R"CONFIG(
|
||||
@@ -563,67 +766,107 @@ BOOST_FIXTURE_TEST_CASE(CreateChannel, UdpFactoryMcastFixture)
|
||||
BOOST_CHECK_NE(channel2, channel3);
|
||||
BOOST_CHECK_EQUAL(channel3->getUri().toString(), "udp6://[::1]:20071");
|
||||
|
||||
// createChannel with multicast address
|
||||
BOOST_CHECK_EXCEPTION(createChannel("224.0.0.1", 20070), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"createChannel is only for unicast channels. The provided endpoint "
|
||||
"is multicast. Use createMulticastFace to create a multicast face") == 0;
|
||||
});
|
||||
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
|
||||
// createChannel with a local endpoint that has already been allocated for a UDP multicast face
|
||||
auto multicastFace = createMulticastFace("127.0.0.1", "224.0.0.1", 20072);
|
||||
BOOST_CHECK_EXCEPTION(createChannel("127.0.0.1", 20072), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create the requested UDP unicast channel, local "
|
||||
"endpoint is already allocated for a UDP multicast face") == 0;
|
||||
});
|
||||
if (!netifsV4.empty()) {
|
||||
auto mcastFace = createMulticastFace("127.0.0.1", "224.0.0.254", 20072);
|
||||
BOOST_CHECK_EXCEPTION(createChannel("127.0.0.1", 20072), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create UDP channel on 127.0.0.1:20072, "
|
||||
"endpoint already allocated for a UDP multicast face") == 0;
|
||||
});
|
||||
}
|
||||
if (!netifsV6.empty()) {
|
||||
auto mcastFace = createMulticastFace("::1", "ff02::114", 20072);
|
||||
BOOST_CHECK_EXCEPTION(createChannel("::1", 20072), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create UDP channel on [::1]:20072, "
|
||||
"endpoint already allocated for a UDP multicast face") == 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(CreateMulticastFace, UdpFactoryMcastFixture)
|
||||
BOOST_FIXTURE_TEST_CASE(CreateMulticastFaceV4, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privilege for creating multicast faces on Linux
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_NETIF_COUNT_LT(1);
|
||||
SKIP_IF_UDP_MCAST_V4_NETIF_COUNT_LT(1);
|
||||
|
||||
auto multicastFace1 = createMulticastFace("127.0.0.1", "224.0.0.1", 20070);
|
||||
auto multicastFace1a = createMulticastFace("127.0.0.1", "224.0.0.1", 20070);
|
||||
auto multicastFace1 = createMulticastFace("127.0.0.1", "224.0.0.254", 20070);
|
||||
auto multicastFace1a = createMulticastFace("127.0.0.1", "224.0.0.254", 20070);
|
||||
auto multicastFace2 = createMulticastFace("127.0.0.1", "224.0.0.254", 20030);
|
||||
BOOST_CHECK_EQUAL(multicastFace1, multicastFace1a);
|
||||
BOOST_CHECK_NE(multicastFace1, multicastFace2);
|
||||
|
||||
// createMulticastFace with an IPv4 local endpoint already used by a channel
|
||||
auto address = findNonLoopbackAddressForMulticastFace(ndn::net::AddressFamily::V4);
|
||||
if (!address.is_unspecified()) {
|
||||
auto multicastFace3 = createMulticastFace(address.to_string(), "224.0.0.254", 20070);
|
||||
BOOST_CHECK_NE(multicastFace1, multicastFace3);
|
||||
BOOST_CHECK_NE(multicastFace2, multicastFace3);
|
||||
}
|
||||
|
||||
// create with a local endpoint already used by a channel
|
||||
auto channel = createChannel("127.0.0.1", 20071);
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("127.0.0.1", "224.0.0.1", 20071), UdpFactory::Error,
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("127.0.0.1", "224.0.0.254", 20071), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create the requested UDP multicast face, local "
|
||||
"endpoint is already allocated for a UDP unicast channel") == 0;
|
||||
"Cannot create UDP multicast face on 127.0.0.1:20071, "
|
||||
"endpoint already allocated for a UDP channel") == 0;
|
||||
});
|
||||
|
||||
// createMulticastFace with an IPv4 local endpoint already
|
||||
// used by a multicast face on a different multicast group
|
||||
// create with a local endpoint already used by a multicast face on a different multicast group
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("127.0.0.1", "224.0.0.42", 20070), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create the requested UDP multicast face, local "
|
||||
"endpoint is already allocated for a UDP multicast face "
|
||||
"on a different multicast group") == 0;
|
||||
"Cannot create UDP multicast face on 127.0.0.1:20070, "
|
||||
"endpoint already allocated for a different UDP multicast face") == 0;
|
||||
});
|
||||
}
|
||||
|
||||
// createMulticastFace with an IPv6 multicast address
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("::1", "ff01::114", 20073), UdpFactory::Error,
|
||||
BOOST_FIXTURE_TEST_CASE(CreateMulticastFaceV6, UdpFactoryMcastFixture)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// need superuser privileges to create multicast faces on Linux
|
||||
SKIP_IF_NOT_SUPERUSER();
|
||||
#endif // __linux__
|
||||
SKIP_IF_UDP_MCAST_V6_NETIF_COUNT_LT(1);
|
||||
|
||||
auto multicastFace1 = createMulticastFace("::1", "ff02::114", 20070);
|
||||
auto multicastFace1a = createMulticastFace("::1", "ff02::114", 20070);
|
||||
auto multicastFace2 = createMulticastFace("::1", "ff02::114", 20030);
|
||||
BOOST_CHECK_EQUAL(multicastFace1, multicastFace1a);
|
||||
BOOST_CHECK_NE(multicastFace1, multicastFace2);
|
||||
|
||||
auto address = findNonLoopbackAddressForMulticastFace(ndn::net::AddressFamily::V6);
|
||||
if (!address.is_unspecified()) {
|
||||
auto multicastFace3 = createMulticastFace(address.to_string(), "ff02::114", 20070);
|
||||
BOOST_CHECK_NE(multicastFace1, multicastFace3);
|
||||
BOOST_CHECK_NE(multicastFace2, multicastFace3);
|
||||
}
|
||||
|
||||
// create with a local endpoint already used by a channel
|
||||
auto channel = createChannel("::1", 20071);
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("::1", "ff02::114", 20071), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"IPv6 multicast is not supported yet. Please provide an IPv4 "
|
||||
"address") == 0;
|
||||
"Cannot create UDP multicast face on [::1]:20071, "
|
||||
"endpoint already allocated for a UDP channel") == 0;
|
||||
});
|
||||
|
||||
// create with a local endpoint already used by a multicast face on a different multicast group
|
||||
BOOST_CHECK_EXCEPTION(createMulticastFace("::1", "ff02::42", 20070), UdpFactory::Error,
|
||||
[] (const UdpFactory::Error& e) {
|
||||
return strcmp(e.what(),
|
||||
"Cannot create UDP multicast face on [::1]:20070, "
|
||||
"endpoint already allocated for a different UDP multicast face") == 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user