From: g0dil Date: Wed, 8 Oct 2008 10:44:17 +0000 (+0000) Subject: Socket/Protocols/INet: Implement SSM Multicast API X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=9ded1690d676ba7c7054a7a272debf99102f94c0;p=senf.git Socket/Protocols/INet: Implement SSM Multicast API git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@931 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Scheduler/Console/Mainpage.dox b/Scheduler/Console/Mainpage.dox index b1636e3..ce49820 100644 --- a/Scheduler/Console/Mainpage.dox +++ b/Scheduler/Console/Mainpage.dox @@ -118,7 +118,7 @@ \see \ref console_testserver for a complete example application - \section intro_usage Using the Console: Configuration files, Network console, ... + \section intro_usage Using the Console: Configuration files, Network console There are several ways to access the node tree: \li By parsing configuration files diff --git a/Socket/Protocols/INet/MulticastSocketProtocol.cc b/Socket/Protocols/INet/MulticastSocketProtocol.cc index dca071e..42f2126 100644 --- a/Socket/Protocols/INet/MulticastSocketProtocol.cc +++ b/Socket/Protocols/INet/MulticastSocketProtocol.cc @@ -183,6 +183,40 @@ prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address c SENF_THROW_SYSTEM_EXCEPTION(""); } +namespace { + void mc4SSMSourceRequest(int operation, int fd, senf::INet4Address const & group, + senf::INet4Address const & source, std::string const & iface) + { + struct group_source_req req; + ::memset(&req, 0, sizeof(req)); + req.gsr_interface = if_nametoindex(iface.c_str()); + if (req.gsr_interface == 0) + throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO); + req.gsr_group.ss_family = AF_INET; + reinterpret_cast(req.gsr_group).sin_addr.s_addr = group.inaddr(); + req.gsr_source.ss_family = AF_INET; + reinterpret_cast(req.gsr_source).sin_addr.s_addr = source.inaddr(); + if (::setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0) + SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()"); + } +} + +prefix_ void senf::INet4MulticastSocketProtocol::mcJoinSSMSource(INet4Address const & group, + INet4Address const & source, + std::string const & iface) + const +{ + mc4SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface); +} + +prefix_ void senf::INet4MulticastSocketProtocol::mcLeaveSSMSource(INet4Address const & group, + INet4Address const & source, + std::string const & iface) + const +{ + mc4SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface); +} + /////////////////////////////////////////////////////////////////////////// // senf::INet6MulticastSocketProtocol @@ -276,6 +310,42 @@ senf::INet6MulticastSocketProtocol::mcDropMembership(INet6Address const & mcAddr } } +namespace { + void mc6SSMSourceRequest(int operation, int fd, senf::INet6Address const & group, + senf::INet6Address const & source, std::string const & iface) + { + struct group_source_req req; + ::memset(&req, 0, sizeof(req)); + req.gsr_interface = if_nametoindex(iface.c_str()); + if (req.gsr_interface == 0) + throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO); + req.gsr_group.ss_family = AF_INET6; + std::copy(group.begin(), group.end(), + reinterpret_cast(req.gsr_group).sin6_addr.s6_addr); + req.gsr_source.ss_family = AF_INET6; + std::copy(source.begin(), source.end(), + reinterpret_cast(req.gsr_source).sin6_addr.s6_addr); + if (::setsockopt(fd, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0) + SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()"); + } +} + +prefix_ void senf::INet6MulticastSocketProtocol::mcJoinSSMSource(INet6Address const & group, + INet6Address const & source, + std::string const & iface) + const +{ + mc6SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface); +} + +prefix_ void senf::INet6MulticastSocketProtocol::mcLeaveSSMSource(INet6Address const & group, + INet6Address const & source, + std::string const & iface) + const +{ + mc6SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface); +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "MulticastSocketProtocol.mpp" diff --git a/Socket/Protocols/INet/MulticastSocketProtocol.hh b/Socket/Protocols/INet/MulticastSocketProtocol.hh index 0de6997..cf80740 100644 --- a/Socket/Protocols/INet/MulticastSocketProtocol.hh +++ b/Socket/Protocols/INet/MulticastSocketProtocol.hh @@ -40,6 +40,9 @@ namespace senf { ///\{ /** \brief Generic addressing type independent multicast protocol facet + + \todo implement complete new multicast API from RFC3678 (as far as supported by linux) + \bug mcLeaveSSMSource fails with EADDRNOTAVAIL */ class MulticastSocketProtocol : public virtual SocketProtocol @@ -125,6 +128,26 @@ namespace senf { interface with the given local address. \param[in] mcAddr address of group to leave \param[in] iface interface name */ + + void mcJoinSSMSource(INet4Address const & group, INet4Address const & source, + std::string const & iface) const; + ///< join SSM multicast group + /**< This call will join the multicast group \a group for + traffic from \a source. A single group may be joined + multiple times on different sources. + \param[in] group multicast group to join + \param[in] source SSM multicast source to join the + group on + \param[in] iface interface to join the group on */ + void mcLeaveSSMSource(INet4Address const & group, INet4Address const & source, + std::string const & iface) const; + ///< leave SSM multicast group + /**< This call will leave the multicast group \a group for + traffic from \a source. + \param[in] group multicast group to leave + \param[in] source SSM multicast source to leave the + group from + \param[in] iface interface to leave the group on */ }; /** \brief Multicast protocol facet for INet6 addressable multicast enabled sockets @@ -156,14 +179,33 @@ namespace senf { multicast groups received. The group is left from the default interface. \param[in] mcAddr address of group to leave */ - void mcDropMembership(INet6Address const & mcAddr, std::string const & iface) - const; + void mcDropMembership(INet6Address const & mcAddr, std::string const & iface) const; ///< leave multicast group on a specific interface /**< This member will remove \a mcAddr from the list of multicast groups received. The group is left from the interface with the given local address. \param[in] mcAddr address of group to leave \param[in] iface interface name */ + + void mcJoinSSMSource(INet6Address const & group, INet6Address const & source, + std::string const & iface) const; + ///< join SSM multicast group + /**< This call will join the multicast group \a group for + traffic from \a source. A single group may be joined + multiple times on different sources. + \param[in] group multicast group to join + \param[in] source SSM multicast source to join the + group on + \param[in] iface interface to join the group on */ + void mcLeaveSSMSource(INet6Address const & group, INet6Address const & source, + std::string const & iface) const; + ///< leave SSM multicast group + /**< This call will leave the multicast group \a group for + traffic from \a source. + \param[in] group multicast group to leave + \param[in] source SSM multicast source to leave the + group from + \param[in] iface interface to leave the group on */ }; ///\} diff --git a/Socket/Protocols/INet/MulticastSocketProtocol.test.cc b/Socket/Protocols/INet/MulticastSocketProtocol.test.cc index 8a02f0b..2212645 100644 --- a/Socket/Protocols/INet/MulticastSocketProtocol.test.cc +++ b/Socket/Protocols/INet/MulticastSocketProtocol.test.cc @@ -53,8 +53,32 @@ BOOST_AUTO_UNIT_TEST(multicastSocketProtocol) BOOST_CHECK( ! sock.protocol().mcLoop() ); sock.protocol().mcLoop(true); BOOST_CHECK( sock.protocol().mcLoop() ); - + sock.protocol().mcIface("lo"); + + SENF_CHECK_NO_THROW( sock.protocol().mcJoinSSMSource( + senf::INet4Address(0xE0000001u), + senf::INet4Address(0x7F000001u), + "lo") ); + // This fails with EADDRNOTAVAIL .. no idea why. I tried with 'eth' interface + // and a real address (not loopback) to no avail. +// SENF_CHECK_NO_THROW( sock.protocol().mcLeaveSSMSource( +// senf::INet4Address(0xE0000001u), +// senf::INet4Address(0x7F000001u), +// "lo") ); + + senf::UDPv6ClientSocketHandle sock6; + + SENF_CHECK_NO_THROW( sock6.protocol().mcJoinSSMSource( + senf::INet6Address(0xFF00u, 0, 0, 0, 0, 0, 0, 1), + senf::INet6Address::Loopback, + "lo") ); + // This fails with EADDRNOTAVAIL .. no idea why. I tried with 'eth' interface + // and a real address (not loopback) to no avail. +// SENF_CHECK_NO_THROW( sock6.protocol().mcLeaveSSMSource( +// senf::INet6Address(0xFF00u, 0, 0, 0, 0, 0, 0, 1), +// senf::INet6Address::Loopback, +// "lo") ); } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Utils/Exception.hh b/Utils/Exception.hh index bb947e2..b151b88 100644 --- a/Utils/Exception.hh +++ b/Utils/Exception.hh @@ -308,7 +308,7 @@ namespace senf { # define SENF_EXC_DEBUGINFO # endif -# define SENF_THROW_SYSTEM_EXCEPTION(desc) throw SystemException(desc SENF_EXC_DEBUGINFO) +# define SENF_THROW_SYSTEM_EXCEPTION(desc) throw senf::SystemException(desc SENF_EXC_DEBUGINFO) }