x/net/ipv4: add support for source-specific multicast
This CL introduces methods for the manipulation of source-specifc
group into both PacketConn and RawConn as follows:
JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
Fixes golang/go#8266.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/174030043
diff --git a/ipv4/dgramopt_posix.go b/ipv4/dgramopt_posix.go
index fce881a..68e25e2 100644
--- a/ipv4/dgramopt_posix.go
+++ b/ipv4/dgramopt_posix.go
@@ -93,7 +93,11 @@
return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on))
}
-// JoinGroup joins the group address group on the interface ifi.
+// JoinGroup joins the group address group on the interface ifi. By
+// default all sources that can cast data to group are accepted. It's
+// possible to mute and unmute data transmission from a specific
+// source by using ExcludeSourceSpecificGroup and
+// IncludeSourceSpecificGroup.
// It uses the system assigned multicast interface when ifi is nil,
// although this is not recommended because the assignment depends on
// platforms and sometimes it might require routing configuration.
@@ -113,6 +117,8 @@
}
// LeaveGroup leaves the group address group on the interface ifi.
+// It's allowed to leave the group which is formed by
+// JoinSourceSpecificGroup for convenience.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return syscall.EINVAL
@@ -127,3 +133,91 @@
}
return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp)
}
+
+// JoinSourceSpecificGroup joins the source-specific group consisting
+// group and source on the interface ifi. It uses the system assigned
+// multicast interface when ifi is nil, although this is not
+// recommended because the assignment depends on platforms and
+// sometimes it might require routing configuration.
+func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ fd, err := c.sysfd()
+ if err != nil {
+ return err
+ }
+ grp := netAddrToIP4(group)
+ if grp == nil {
+ return errMissingAddress
+ }
+ src := netAddrToIP4(source)
+ if src == nil {
+ return errMissingAddress
+ }
+ return setSourceGroup(fd, &sockOpts[ssoJoinSourceGroup], ifi, grp, src)
+}
+
+// LeaveSourceSpecificGroup leaves the source-specific group on the
+// interface ifi.
+func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ fd, err := c.sysfd()
+ if err != nil {
+ return err
+ }
+ grp := netAddrToIP4(group)
+ if grp == nil {
+ return errMissingAddress
+ }
+ src := netAddrToIP4(source)
+ if src == nil {
+ return errMissingAddress
+ }
+ return setSourceGroup(fd, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src)
+}
+
+// ExcludeSourceSpecificGroup excludes the source-specific group from
+// the already joined groups by either JoinGroup or
+// JoinSourceSpecificGroup on the interface ifi.
+func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ fd, err := c.sysfd()
+ if err != nil {
+ return err
+ }
+ grp := netAddrToIP4(group)
+ if grp == nil {
+ return errMissingAddress
+ }
+ src := netAddrToIP4(source)
+ if src == nil {
+ return errMissingAddress
+ }
+ return setSourceGroup(fd, &sockOpts[ssoBlockSourceGroup], ifi, grp, src)
+}
+
+// IncludeSourceSpecificGroup includes the excluded source-specific
+// group by ExcludeSourceSpecificGroup again on the interface ifi.
+func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ fd, err := c.sysfd()
+ if err != nil {
+ return err
+ }
+ grp := netAddrToIP4(group)
+ if grp == nil {
+ return errMissingAddress
+ }
+ src := netAddrToIP4(source)
+ if src == nil {
+ return errMissingAddress
+ }
+ return setSourceGroup(fd, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src)
+}