diff --git a/daemon/face/multicast-udp-face.cpp b/daemon/face/multicast-udp-face.cpp index d12ba5b0..c3d7e95a 100644 --- a/daemon/face/multicast-udp-face.cpp +++ b/daemon/face/multicast-udp-face.cpp @@ -31,12 +31,15 @@ NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, MulticastUdpFace::protocol, Multicast, "MulticastUdpFace"); -MulticastUdpFace::MulticastUdpFace(const shared_ptr& socket, - const MulticastUdpFace::protocol::endpoint& localEndpoint) - : DatagramFace(FaceUri(socket->local_endpoint()), +MulticastUdpFace::MulticastUdpFace(const shared_ptr& recvSocket, + const shared_ptr& sendSocket, + const MulticastUdpFace::protocol::endpoint& localEndpoint, + const MulticastUdpFace::protocol::endpoint& multicastEndpoint) + : DatagramFace(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::handleSend, - this, _1, block)); + m_sendSocket->async_send_to(boost::asio::buffer(block.wire(), block.size()), + m_multicastGroup, + bind(&DatagramFace::handleSend, + this, _1, block)); } void diff --git a/daemon/face/multicast-udp-face.hpp b/daemon/face/multicast-udp-face.hpp index 743cf564..0ac857e8 100644 --- a/daemon/face/multicast-udp-face.hpp +++ b/daemon/face/multicast-udp-face.hpp @@ -40,8 +40,10 @@ public: /** * \brief Creates a UDP-based face for multicast communication */ - MulticastUdpFace(const shared_ptr& socket, - const protocol::endpoint& localEndpoint); + MulticastUdpFace(const shared_ptr& recvSocket, + const shared_ptr& 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 m_sendSocket; }; } // namespace nfd diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp index fc156ea7..1a4ca010 100644 --- a/daemon/face/udp-factory.cpp +++ b/daemon/face/udp-factory.cpp @@ -207,21 +207,31 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint, "the multicast group given as input is not a multicast address"); } - shared_ptr clientSocket = + shared_ptr receiveSocket = make_shared(ref(getGlobalIoService())); - clientSocket->open(multicastEndpoint.protocol()); + shared_ptr sendSocket = + make_shared(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(clientSocket, localEndpoint); + multicastFace = make_shared(receiveSocket, sendSocket, + localEndpoint, multicastEndpoint); multicastFace->onFail += bind(&UdpFactory::afterFaceFailed, this, localEndpoint); m_multicastFaces[localEndpoint] = multicastFace;