face: Switching to 2 sockets in MulticastUdpFace for sending and receiving
To send over UDP multicast, we should not bind to multicast address. This is true at least on OSX 10.9, which generates "Can't assign requested address" error (error code: 49). However, without binding to the multicast address, the socket may receive unnecessary unrelated packets. To solve this problem, this commit splits sending and receiving into two sockets, one for sending and one for receiving. Change-Id: Ibce05c7071fd683a26b3c88cd2a168546c5dc605 Refs: #1668
This commit is contained in:
1 parent
cd591e1781
commit
dc01700b45
3 files changed
+37
-22
No files matched your search
@@ -31,12 +31,15 @@ NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace,
|
||||
MulticastUdpFace::protocol, Multicast,
|
||||
"MulticastUdpFace");
|
||||
|
||||
MulticastUdpFace::MulticastUdpFace(const shared_ptr<MulticastUdpFace::protocol::socket>& socket,
|
||||
const MulticastUdpFace::protocol::endpoint& localEndpoint)
|
||||
: DatagramFace<protocol, Multicast>(FaceUri(socket->local_endpoint()),
|
||||
MulticastUdpFace::MulticastUdpFace(const shared_ptr<MulticastUdpFace::protocol::socket>& recvSocket,
|
||||
const shared_ptr<MulticastUdpFace::protocol::socket>& sendSocket,
|
||||
const MulticastUdpFace::protocol::endpoint& localEndpoint,
|
||||
const MulticastUdpFace::protocol::endpoint& multicastEndpoint)
|
||||
: DatagramFace<protocol, Multicast>(FaceUri(multicastEndpoint),
|
||||
FaceUri(localEndpoint),
|
||||
socket, false)
|
||||
, m_multicastGroup(socket->local_endpoint())
|
||||
recvSocket, false)
|
||||
, m_multicastGroup(multicastEndpoint)
|
||||
, m_sendSocket(sendSocket)
|
||||
{
|
||||
NFD_LOG_INFO("Creating multicast UDP face for group " << m_multicastGroup);
|
||||
}
|
||||
@@ -50,10 +53,10 @@ MulticastUdpFace::getMulticastGroup() const
|
||||
void
|
||||
MulticastUdpFace::sendBlock(const Block& block)
|
||||
{
|
||||
m_socket->async_send_to(boost::asio::buffer(block.wire(), block.size()),
|
||||
m_multicastGroup,
|
||||
bind(&DatagramFace<protocol, Multicast>::handleSend,
|
||||
this, _1, block));
|
||||
m_sendSocket->async_send_to(boost::asio::buffer(block.wire(), block.size()),
|
||||
m_multicastGroup,
|
||||
bind(&DatagramFace<protocol, Multicast>::handleSend,
|
||||
this, _1, block));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -40,8 +40,10 @@ public:
|
||||
/**
|
||||
* \brief Creates a UDP-based face for multicast communication
|
||||
*/
|
||||
MulticastUdpFace(const shared_ptr<protocol::socket>& socket,
|
||||
const protocol::endpoint& localEndpoint);
|
||||
MulticastUdpFace(const shared_ptr<protocol::socket>& recvSocket,
|
||||
const shared_ptr<protocol::socket>& sendSocket,
|
||||
const protocol::endpoint& localEndpoint,
|
||||
const protocol::endpoint& multicastEndpoint);
|
||||
|
||||
const protocol::endpoint&
|
||||
getMulticastGroup() const;
|
||||
@@ -62,6 +64,7 @@ private:
|
||||
|
||||
private:
|
||||
protocol::endpoint m_multicastGroup;
|
||||
shared_ptr<protocol::socket> m_sendSocket;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
+20
-11
@@ -207,21 +207,31 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
"the multicast group given as input is not a multicast address");
|
||||
}
|
||||
|
||||
shared_ptr<ip::udp::socket> clientSocket =
|
||||
shared_ptr<ip::udp::socket> receiveSocket =
|
||||
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
|
||||
|
||||
clientSocket->open(multicastEndpoint.protocol());
|
||||
shared_ptr<ip::udp::socket> sendSocket =
|
||||
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
|
||||
|
||||
clientSocket->set_option(ip::udp::socket::reuse_address(true));
|
||||
receiveSocket->open(multicastEndpoint.protocol());
|
||||
receiveSocket->set_option(ip::udp::socket::reuse_address(true));
|
||||
|
||||
sendSocket->open(multicastEndpoint.protocol());
|
||||
sendSocket->set_option(ip::udp::socket::reuse_address(true));
|
||||
sendSocket->set_option(ip::multicast::enable_loopback(false));
|
||||
|
||||
try {
|
||||
clientSocket->bind(multicastEndpoint);
|
||||
sendSocket->bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
|
||||
receiveSocket->bind(multicastEndpoint);
|
||||
|
||||
if (localEndpoint.address() != ip::address::from_string("0.0.0.0")) {
|
||||
clientSocket->set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
|
||||
sendSocket->set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
|
||||
}
|
||||
clientSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
|
||||
localEndpoint.address().to_v4()));
|
||||
sendSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
|
||||
localEndpoint.address().to_v4()));
|
||||
|
||||
receiveSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
|
||||
localEndpoint.address().to_v4()));
|
||||
}
|
||||
catch (boost::system::system_error& e) {
|
||||
std::stringstream msg;
|
||||
@@ -238,7 +248,7 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
//This applies only on linux, for OS X the ip::multicast::join_group is enough to get
|
||||
//the desired behaviour
|
||||
if (!networkInterfaceName.empty()) {
|
||||
if (::setsockopt(clientSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
|
||||
if (::setsockopt(receiveSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
|
||||
networkInterfaceName.c_str(), networkInterfaceName.size()+1) == -1){
|
||||
throw Error("Cannot bind multicast face to " + networkInterfaceName
|
||||
+ " make sure you have CAP_NET_RAW capability" );
|
||||
@@ -247,9 +257,8 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
|
||||
#endif
|
||||
|
||||
clientSocket->set_option(ip::multicast::enable_loopback(false));
|
||||
|
||||
multicastFace = make_shared<MulticastUdpFace>(clientSocket, localEndpoint);
|
||||
multicastFace = make_shared<MulticastUdpFace>(receiveSocket, sendSocket,
|
||||
localEndpoint, multicastEndpoint);
|
||||
multicastFace->onFail += bind(&UdpFactory::afterFaceFailed, this, localEndpoint);
|
||||
|
||||
m_multicastFaces[localEndpoint] = multicastFace;
|
||||
|
||||
Reference in new issue
Block a user