|  | // Copyright 2012 The Go Authors.  All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows | 
|  |  | 
|  | package ipv4 | 
|  |  | 
|  | import ( | 
|  | "net" | 
|  | "syscall" | 
|  |  | 
|  | "golang.org/x/net/internal/netreflect" | 
|  | ) | 
|  |  | 
|  | // MulticastTTL returns the time-to-live field value for outgoing | 
|  | // multicast packets. | 
|  | func (c *dgramOpt) MulticastTTL() (int, error) { | 
|  | if !c.ok() { | 
|  | return 0, syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return 0, err | 
|  | } | 
|  | return getInt(s, &sockOpts[ssoMulticastTTL]) | 
|  | } | 
|  |  | 
|  | // SetMulticastTTL sets the time-to-live field value for future | 
|  | // outgoing multicast packets. | 
|  | func (c *dgramOpt) SetMulticastTTL(ttl int) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | return setInt(s, &sockOpts[ssoMulticastTTL], ttl) | 
|  | } | 
|  |  | 
|  | // MulticastInterface returns the default interface for multicast | 
|  | // packet transmissions. | 
|  | func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { | 
|  | if !c.ok() { | 
|  | return nil, syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | return getInterface(s, &sockOpts[ssoMulticastInterface]) | 
|  | } | 
|  |  | 
|  | // SetMulticastInterface sets the default interface for future | 
|  | // multicast packet transmissions. | 
|  | func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | return setInterface(s, &sockOpts[ssoMulticastInterface], ifi) | 
|  | } | 
|  |  | 
|  | // MulticastLoopback reports whether transmitted multicast packets | 
|  | // should be copied and send back to the originator. | 
|  | func (c *dgramOpt) MulticastLoopback() (bool, error) { | 
|  | if !c.ok() { | 
|  | return false, syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return false, err | 
|  | } | 
|  | on, err := getInt(s, &sockOpts[ssoMulticastLoopback]) | 
|  | if err != nil { | 
|  | return false, err | 
|  | } | 
|  | return on == 1, nil | 
|  | } | 
|  |  | 
|  | // SetMulticastLoopback sets whether transmitted multicast packets | 
|  | // should be copied and send back to the originator. | 
|  | func (c *dgramOpt) SetMulticastLoopback(on bool) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | return setInt(s, &sockOpts[ssoMulticastLoopback], boolint(on)) | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | // JoinGroup 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) JoinGroup(ifi *net.Interface, group net.Addr) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setGroup(s, &sockOpts[ssoJoinGroup], ifi, grp) | 
|  | } | 
|  |  | 
|  | // LeaveGroup leaves the group address group on the interface ifi | 
|  | // regardless of whether the group is any-source group or | 
|  | // source-specific group. | 
|  | func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setGroup(s, &sockOpts[ssoLeaveGroup], ifi, grp) | 
|  | } | 
|  |  | 
|  | // JoinSourceSpecificGroup joins the source-specific group comprising | 
|  | // group and source on the interface ifi. | 
|  | // JoinSourceSpecificGroup 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 | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | src := netAddrToIP4(source) | 
|  | if src == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setSourceGroup(s, &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 | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | src := netAddrToIP4(source) | 
|  | if src == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setSourceGroup(s, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src) | 
|  | } | 
|  |  | 
|  | // ExcludeSourceSpecificGroup excludes the source-specific group from | 
|  | // the already joined any-source groups by JoinGroup on the interface | 
|  | // ifi. | 
|  | func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | src := netAddrToIP4(source) | 
|  | if src == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setSourceGroup(s, &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 | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | grp := netAddrToIP4(group) | 
|  | if grp == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | src := netAddrToIP4(source) | 
|  | if src == nil { | 
|  | return errMissingAddress | 
|  | } | 
|  | return setSourceGroup(s, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src) | 
|  | } | 
|  |  | 
|  | // ICMPFilter returns an ICMP filter. | 
|  | // Currently only Linux supports this. | 
|  | func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { | 
|  | if !c.ok() { | 
|  | return nil, syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | return getICMPFilter(s, &sockOpts[ssoICMPFilter]) | 
|  | } | 
|  |  | 
|  | // SetICMPFilter deploys the ICMP filter. | 
|  | // Currently only Linux supports this. | 
|  | func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { | 
|  | if !c.ok() { | 
|  | return syscall.EINVAL | 
|  | } | 
|  | s, err := netreflect.PacketSocketOf(c.PacketConn) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | return setICMPFilter(s, &sockOpts[ssoICMPFilter], f) | 
|  | } |