Socket/Protocols/INet: Implement SSM Multicast API
[senf.git] / Socket / Protocols / INet / MulticastSocketProtocol.cc
index 8d47679..42f2126 100644 (file)
@@ -121,7 +121,7 @@ prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address co
 }
 
 prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address const & mcAddr,
-                                                           INet4Address const & localAddr)
+                                                                 INet4Address const & localAddr)
     const
 {
     struct ip_mreqn mreqn;
@@ -133,7 +133,7 @@ prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address co
 }
 
 prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address const & mcAddr,
-                                                           std::string const & iface)
+                                                                 std::string const & iface)
     const
 {
     struct ip_mreqn mreqn;
@@ -158,7 +158,7 @@ prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address c
 }
 
 prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address const & mcAddr,
-                                                            INet4Address const & localAddr)
+                                                                  INet4Address const & localAddr)
     const
 {
     struct ip_mreqn mreqn;
@@ -170,7 +170,7 @@ prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address c
 }
 
 prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address const & mcAddr,
-                                                            std::string const & iface)
+                                                                  std::string const & iface)
     const
 {
     struct ip_mreqn mreqn;
@@ -183,53 +183,167 @@ 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<struct sockaddr_in&>(req.gsr_group).sin_addr.s_addr = group.inaddr();
+        req.gsr_source.ss_family = AF_INET;
+        reinterpret_cast<struct sockaddr_in&>(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
 
 prefix_ void senf::INet6MulticastSocketProtocol::mcAddMembership(INet6Address const & mcAddr)
     const
 {
-    struct ipv6_mreq mreqn;
-    std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
-    mreqn.ipv6mr_interface = 0;
-    if (::setsockopt(fd(),SOL_IP,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
+    if (mcAddr.inet4Mapped()) {
+        struct ip_mreqn mreqn;
+        mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
+        mreqn.imr_address.s_addr = htons(INADDR_ANY);
+        mreqn.imr_ifindex = 0;
+        if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP)");
+    }
+    else {
+        struct ipv6_mreq mreqn;
+        std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
+        mreqn.ipv6mr_interface = 0;
+        if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
+    }
 }
 
 prefix_ void senf::INet6MulticastSocketProtocol::mcAddMembership(INet6Address const & mcAddr,
-                                                           std::string const & iface)
+                                                                 std::string const & iface)
 {
-    struct ipv6_mreq mreqn;
-    std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
-    mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
-    if (mreqn.ipv6mr_interface == 0)
-        throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
-    if (::setsockopt(fd(),SOL_IP,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
+    if (mcAddr.inet4Mapped()) {
+        struct ip_mreqn mreqn;
+        mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
+        mreqn.imr_address.s_addr = htons(INADDR_ANY);
+        mreqn.imr_ifindex = if_nametoindex(iface.c_str());
+        if (mreqn.imr_ifindex == 0)
+            throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
+        if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
+    }
+    else {
+        struct ipv6_mreq mreqn;
+        std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
+        mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
+        if (mreqn.ipv6mr_interface == 0)
+            throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
+        if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
+    }
 }
 
 prefix_ void senf::INet6MulticastSocketProtocol::mcDropMembership(INet6Address const & mcAddr)
     const
 {
-    struct ipv6_mreq mreqn;
-    std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
-    mreqn.ipv6mr_interface = 0;
-    if (::setsockopt(fd(),SOL_IP,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
+    if (mcAddr.inet4Mapped()) {
+        struct ip_mreqn mreqn;
+        mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
+        mreqn.imr_address.s_addr = htons(INADDR_ANY);
+        mreqn.imr_ifindex = 0;
+        if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("");
+    }
+    else {
+        struct ipv6_mreq mreqn;
+        std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
+        mreqn.ipv6mr_interface = 0;
+        if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("");
+    }
 }
 
 prefix_ void
 senf::INet6MulticastSocketProtocol::mcDropMembership(INet6Address const & mcAddr,
-                                               std::string const & iface)
+                                                     std::string const & iface)
     const
 {
-    struct ipv6_mreq mreqn;
-    std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
-    mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
-    if (mreqn.ipv6mr_interface == 0)
-        throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
-    if (::setsockopt(fd(),SOL_IP,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
+    if (mcAddr.inet4Mapped()) {
+        struct ip_mreqn mreqn;
+        mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
+        mreqn.imr_address.s_addr = htons(INADDR_ANY);
+        mreqn.imr_ifindex = if_nametoindex(iface.c_str());
+        if (mreqn.imr_ifindex == 0)
+            throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
+        if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("");
+    }
+    else {
+        struct ipv6_mreq mreqn;
+        std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
+        mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
+        if (mreqn.ipv6mr_interface == 0)
+            throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
+        if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("");
+    }
+}
+
+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<struct sockaddr_in6&>(req.gsr_group).sin6_addr.s6_addr);
+        req.gsr_source.ss_family = AF_INET6;
+        std::copy(source.begin(), source.end(),
+                  reinterpret_cast<struct sockaddr_in6&>(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////////////////////////////////////////