Commit cbdbdc4f authored by Mikio Hara's avatar Mikio Hara

net: add IP-level socket option helpers for Unix variants

Also reorganize socket options stuff but there are no API behavioral
changes.

R=rsc, fullung
CC=golang-dev
https://golang.org/cl/5494067
parent 6a0e6cc7
...@@ -36,7 +36,11 @@ GOFILES_darwin=\ ...@@ -36,7 +36,11 @@ GOFILES_darwin=\
port.go\ port.go\
sendfile_stub.go\ sendfile_stub.go\
sock.go\ sock.go\
sock_bsd.go\ sockopt.go\
sockopt_bsd.go\
sockoptip.go\
sockoptip_bsd.go\
sockoptip_darwin.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
...@@ -64,7 +68,11 @@ GOFILES_freebsd=\ ...@@ -64,7 +68,11 @@ GOFILES_freebsd=\
port.go\ port.go\
sendfile_stub.go\ sendfile_stub.go\
sock.go\ sock.go\
sock_bsd.go\ sockopt.go\
sockopt_bsd.go\
sockoptip.go\
sockoptip_bsd.go\
sockoptip_freebsd.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
...@@ -91,7 +99,10 @@ GOFILES_linux=\ ...@@ -91,7 +99,10 @@ GOFILES_linux=\
port.go\ port.go\
sendfile_linux.go\ sendfile_linux.go\
sock.go\ sock.go\
sock_linux.go\ sockopt.go\
sockopt_linux.go\
sockoptip.go\
sockoptip_linux.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
...@@ -119,7 +130,11 @@ GOFILES_netbsd=\ ...@@ -119,7 +130,11 @@ GOFILES_netbsd=\
port.go\ port.go\
sendfile_stub.go\ sendfile_stub.go\
sock.go\ sock.go\
sock_bsd.go\ sockopt.go\
sockopt_bsd.go\
sockoptip.go\
sockoptip_bsd.go\
sockoptip_netbsd.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
...@@ -140,7 +155,11 @@ GOFILES_openbsd=\ ...@@ -140,7 +155,11 @@ GOFILES_openbsd=\
port.go\ port.go\
sendfile_stub.go\ sendfile_stub.go\
sock.go\ sock.go\
sock_bsd.go\ sockopt.go\
sockopt_bsd.go\
sockoptip.go\
sockoptip_bsd.go\
sockoptip_openbsd.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
...@@ -165,7 +184,10 @@ GOFILES_windows=\ ...@@ -165,7 +184,10 @@ GOFILES_windows=\
lookup_windows.go\ lookup_windows.go\
sendfile_windows.go\ sendfile_windows.go\
sock.go\ sock.go\
sock_windows.go\ sockopt.go\
sockopt_windows.go\
sockoptip.go\
sockoptip_windows.go\
tcpsock_posix.go\ tcpsock_posix.go\
udpsock_posix.go\ udpsock_posix.go\
unixsock_posix.go\ unixsock_posix.go\
......
...@@ -12,6 +12,14 @@ import ( ...@@ -12,6 +12,14 @@ import (
"fmt" "fmt"
) )
var (
errInvalidInterface = errors.New("net: invalid interface")
errInvalidInterfaceIndex = errors.New("net: invalid interface index")
errInvalidInterfaceName = errors.New("net: invalid interface name")
errNoSuchInterface = errors.New("net: no such interface")
errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
)
// A HardwareAddr represents a physical hardware address. // A HardwareAddr represents a physical hardware address.
type HardwareAddr []byte type HardwareAddr []byte
...@@ -131,7 +139,7 @@ func (f Flags) String() string { ...@@ -131,7 +139,7 @@ func (f Flags) String() string {
// Addrs returns interface addresses for a specific interface. // Addrs returns interface addresses for a specific interface.
func (ifi *Interface) Addrs() ([]Addr, error) { func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil { if ifi == nil {
return nil, errors.New("net: invalid interface") return nil, errInvalidInterface
} }
return interfaceAddrTable(ifi.Index) return interfaceAddrTable(ifi.Index)
} }
...@@ -140,7 +148,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) { ...@@ -140,7 +148,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
// a specific interface. // a specific interface.
func (ifi *Interface) MulticastAddrs() ([]Addr, error) { func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil { if ifi == nil {
return nil, errors.New("net: invalid interface") return nil, errInvalidInterface
} }
return interfaceMulticastAddrTable(ifi.Index) return interfaceMulticastAddrTable(ifi.Index)
} }
...@@ -159,7 +167,7 @@ func InterfaceAddrs() ([]Addr, error) { ...@@ -159,7 +167,7 @@ func InterfaceAddrs() ([]Addr, error) {
// InterfaceByIndex returns the interface specified by index. // InterfaceByIndex returns the interface specified by index.
func InterfaceByIndex(index int) (*Interface, error) { func InterfaceByIndex(index int) (*Interface, error) {
if index <= 0 { if index <= 0 {
return nil, errors.New("net: invalid interface index") return nil, errInvalidInterfaceIndex
} }
ift, err := interfaceTable(index) ift, err := interfaceTable(index)
if err != nil { if err != nil {
...@@ -168,13 +176,13 @@ func InterfaceByIndex(index int) (*Interface, error) { ...@@ -168,13 +176,13 @@ func InterfaceByIndex(index int) (*Interface, error) {
for _, ifi := range ift { for _, ifi := range ift {
return &ifi, nil return &ifi, nil
} }
return nil, errors.New("net: no such interface") return nil, errNoSuchInterface
} }
// InterfaceByName returns the interface specified by name. // InterfaceByName returns the interface specified by name.
func InterfaceByName(name string) (*Interface, error) { func InterfaceByName(name string) (*Interface, error) {
if name == "" { if name == "" {
return nil, errors.New("net: invalid interface name") return nil, errInvalidInterfaceName
} }
ift, err := interfaceTable(0) ift, err := interfaceTable(0)
if err != nil { if err != nil {
...@@ -185,5 +193,5 @@ func InterfaceByName(name string) (*Interface, error) { ...@@ -185,5 +193,5 @@ func InterfaceByName(name string) (*Interface, error) {
return &ifi, nil return &ifi, nil
} }
} }
return nil, errors.New("net: no such interface") return nil, errNoSuchInterface
} }
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
var multicast = flag.Bool("multicast", false, "enable multicast tests") var multicast = flag.Bool("multicast", false, "enable multicast tests")
var joinAndLeaveGroupUDPTests = []struct { var multicastUDPTests = []struct {
net string net string
laddr IP laddr IP
gaddr IP gaddr IP
...@@ -32,8 +32,8 @@ var joinAndLeaveGroupUDPTests = []struct { ...@@ -32,8 +32,8 @@ var joinAndLeaveGroupUDPTests = []struct {
{"udp6", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true}, {"udp6", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true},
} }
func TestJoinAndLeaveGroupUDP(t *testing.T) { func TestMulticastUDP(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
return return
} }
if !*multicast { if !*multicast {
...@@ -41,7 +41,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { ...@@ -41,7 +41,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
return return
} }
for _, tt := range joinAndLeaveGroupUDPTests { for _, tt := range multicastUDPTests {
var ( var (
ifi *Interface ifi *Interface
found bool found bool
...@@ -51,7 +51,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
} }
ift, err := Interfaces() ift, err := Interfaces()
if err != nil { if err != nil {
t.Fatalf("Interfaces() failed: %v", err) t.Fatalf("Interfaces failed: %v", err)
} }
for _, x := range ift { for _, x := range ift {
if x.Flags&tt.flags == tt.flags { if x.Flags&tt.flags == tt.flags {
...@@ -65,15 +65,20 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { ...@@ -65,15 +65,20 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
} }
c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr}) c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr})
if err != nil { if err != nil {
t.Fatal(err) t.Fatalf("ListenUDP failed: %v", err)
} }
defer c.Close() defer c.Close()
if err := c.JoinGroup(ifi, tt.gaddr); err != nil { if err := c.JoinGroup(ifi, tt.gaddr); err != nil {
t.Fatal(err) t.Fatalf("JoinGroup failed: %v", err)
}
if !tt.ipv6 {
testIPv4MulticastSocketOptions(t, c.fd, ifi)
} else {
testIPv6MulticastSocketOptions(t, c.fd, ifi)
} }
ifmat, err := ifi.MulticastAddrs() ifmat, err := ifi.MulticastAddrs()
if err != nil { if err != nil {
t.Fatalf("MulticastAddrs() failed: %v", err) t.Fatalf("MulticastAddrs failed: %v", err)
} }
for _, ifma := range ifmat { for _, ifma := range ifmat {
if ifma.(*IPAddr).IP.Equal(tt.gaddr) { if ifma.(*IPAddr).IP.Equal(tt.gaddr) {
...@@ -85,7 +90,71 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { ...@@ -85,7 +90,71 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
t.Fatalf("%q not found in RIB", tt.gaddr.String()) t.Fatalf("%q not found in RIB", tt.gaddr.String())
} }
if err := c.LeaveGroup(ifi, tt.gaddr); err != nil { if err := c.LeaveGroup(ifi, tt.gaddr); err != nil {
t.Fatal(err) t.Fatalf("LeaveGroup failed: %v", err)
} }
} }
} }
func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
ifmc, err := ipv4MulticastInterface(fd)
if err != nil {
t.Fatalf("ipv4MulticastInterface failed: %v", err)
}
t.Logf("IPv4 multicast interface: %v", ifmc)
err = setIPv4MulticastInterface(fd, ifi)
if err != nil {
t.Fatalf("setIPv4MulticastInterface failed: %v", err)
}
ttl, err := ipv4MulticastTTL(fd)
if err != nil {
t.Fatalf("ipv4MulticastTTL failed: %v", err)
}
t.Logf("IPv4 multicast TTL: %v", ttl)
err = setIPv4MulticastTTL(fd, 1)
if err != nil {
t.Fatalf("setIPv4MulticastTTL failed: %v", err)
}
loop, err := ipv4MulticastLoopback(fd)
if err != nil {
t.Fatalf("ipv4MulticastLoopback failed: %v", err)
}
t.Logf("IPv4 multicast loopback: %v", loop)
err = setIPv4MulticastLoopback(fd, false)
if err != nil {
t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
}
}
func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
ifmc, err := ipv6MulticastInterface(fd)
if err != nil {
t.Fatalf("ipv6MulticastInterface failed: %v", err)
}
t.Logf("IPv6 multicast interface: %v", ifmc)
err = setIPv6MulticastInterface(fd, ifi)
if err != nil {
t.Fatalf("setIPv6MulticastInterface failed: %v", err)
}
hoplim, err := ipv6MulticastHopLimit(fd)
if err != nil {
t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
}
t.Logf("IPv6 multicast hop limit: %v", hoplim)
err = setIPv6MulticastHopLimit(fd, 1)
if err != nil {
t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
}
loop, err := ipv6MulticastLoopback(fd)
if err != nil {
t.Fatalf("ipv6MulticastLoopback failed: %v", err)
}
t.Logf("IPv6 multicast loopback: %v", loop)
err = setIPv6MulticastLoopback(fd, false)
if err != nil {
t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
}
}
...@@ -10,19 +10,10 @@ package net ...@@ -10,19 +10,10 @@ package net
import ( import (
"io" "io"
"os"
"reflect" "reflect"
"syscall" "syscall"
) )
// Boolean to int.
func boolint(b bool) int {
if b {
return 1
}
return 0
}
// Generic socket creation. // Generic socket creation.
func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
// See ../syscall/exec.go for description of ForkLock. // See ../syscall/exec.go for description of ForkLock.
...@@ -67,83 +58,6 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal ...@@ -67,83 +58,6 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
return fd, nil return fd, nil
} }
func setsockoptInt(fd *netFD, level, opt int, value int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value))
}
func setsockoptNsec(fd *netFD, level, opt int, nsec int64) error {
var tv = syscall.NsecToTimeval(nsec)
return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv))
}
func setReadBuffer(fd *netFD, bytes int) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
}
func setWriteBuffer(fd *netFD, bytes int) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
}
func setReadTimeout(fd *netFD, nsec int64) error {
fd.rdeadline_delta = nsec
return nil
}
func setWriteTimeout(fd *netFD, nsec int64) error {
fd.wdeadline_delta = nsec
return nil
}
func setTimeout(fd *netFD, nsec int64) error {
if e := setReadTimeout(fd, nsec); e != nil {
return e
}
return setWriteTimeout(fd, nsec)
}
func setReuseAddr(fd *netFD, reuse bool) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
}
func setDontRoute(fd *netFD, dontroute bool) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
}
func setKeepAlive(fd *netFD, keepalive bool) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
}
func setNoDelay(fd *netFD, noDelay bool) error {
fd.incref()
defer fd.decref()
return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
}
func setLinger(fd *netFD, sec int) error {
var l syscall.Linger
if sec >= 0 {
l.Onoff = 1
l.Linger = int32(sec)
} else {
l.Onoff = 0
l.Linger = 0
}
fd.incref()
defer fd.decref()
e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
return os.NewSyscallError("setsockopt", e)
}
type UnknownSocketError struct { type UnknownSocketError struct {
sa syscall.Sockaddr sa syscall.Sockaddr
} }
......
// Copyright 2009 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 freebsd linux netbsd openbsd windows
// Socket options
package net
import (
"bytes"
"os"
"syscall"
)
// Boolean to int.
func boolint(b bool) int {
if b {
return 1
}
return 0
}
func ipv4AddrToInterface(ip IP) (*Interface, error) {
ift, err := Interfaces()
if err != nil {
return nil, err
}
for _, ifi := range ift {
ifat, err := ifi.Addrs()
if err != nil {
return nil, err
}
for _, ifa := range ifat {
switch v := ifa.(type) {
case *IPAddr:
if ip.Equal(v.IP) {
return &ifi, nil
}
case *IPNet:
if ip.Equal(v.IP) {
return &ifi, nil
}
}
}
}
if ip.Equal(IPv4zero) {
return nil, nil
}
return nil, errNoSuchInterface
}
func interfaceToIPv4Addr(ifi *Interface) (IP, error) {
if ifi == nil {
return IPv4zero, nil
}
ifat, err := ifi.Addrs()
if err != nil {
return nil, err
}
for _, ifa := range ifat {
switch v := ifa.(type) {
case *IPAddr:
if v.IP.To4() != nil {
return v.IP, nil
}
case *IPNet:
if v.IP.To4() != nil {
return v.IP, nil
}
}
}
return nil, errNoSuchInterface
}
func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error {
if ifi == nil {
return nil
}
ifat, err := ifi.Addrs()
if err != nil {
return err
}
for _, ifa := range ifat {
switch v := ifa.(type) {
case *IPAddr:
if a := v.IP.To4(); a != nil {
copy(mreq.Interface[:], a)
goto done
}
case *IPNet:
if a := v.IP.To4(); a != nil {
copy(mreq.Interface[:], a)
goto done
}
}
}
done:
if bytes.Equal(mreq.Multiaddr[:], IPv4zero.To4()) {
return errNoSuchMulticastInterface
}
return nil
}
func setReadBuffer(fd *netFD, bytes int) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
}
func setWriteBuffer(fd *netFD, bytes int) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
}
func setReadTimeout(fd *netFD, nsec int64) error {
fd.rdeadline_delta = nsec
return nil
}
func setWriteTimeout(fd *netFD, nsec int64) error {
fd.wdeadline_delta = nsec
return nil
}
func setTimeout(fd *netFD, nsec int64) error {
if e := setReadTimeout(fd, nsec); e != nil {
return e
}
return setWriteTimeout(fd, nsec)
}
func setReuseAddr(fd *netFD, reuse bool) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)))
}
func setDontRoute(fd *netFD, dontroute bool) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)))
}
func setKeepAlive(fd *netFD, keepalive bool) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
}
func setNoDelay(fd *netFD, noDelay bool) error {
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
}
func setLinger(fd *netFD, sec int) error {
var l syscall.Linger
if sec >= 0 {
l.Onoff = 1
l.Linger = int32(sec)
} else {
l.Onoff = 0
l.Linger = 0
}
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// +build darwin freebsd netbsd openbsd // +build darwin freebsd netbsd openbsd
// Sockets for BSD variants // Socket options for BSD variants
package net package net
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Sockets for Linux // Socket options for Linux
package net package net
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Sockets for Windows // Socket options for Windows
package net package net
......
// Copyright 2011 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 freebsd linux netbsd openbsd windows
// IP-level socket options
package net
import (
"os"
"syscall"
)
func ipv4TOS(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv4TOS(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4TTL(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv4TTL(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}}
if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
return err
}
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
}
func leaveIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}}
if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
return err
}
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
}
func ipv6HopLimit(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv6HopLimit(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv6MulticastInterface(fd *netFD) (*Interface, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
if v == 0 {
return nil, nil
}
ifi, err := InterfaceByIndex(v)
if err != nil {
return nil, err
}
return ifi, nil
}
func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
var v int
if ifi != nil {
v = ifi.Index
}
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv6MulticastHopLimit(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv6MulticastHopLimit(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv6MulticastLoopback(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv6MulticastLoopback(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
mreq := &syscall.IPv6Mreq{}
copy(mreq.Multiaddr[:], ip)
if ifi != nil {
mreq.Interface = uint32(ifi.Index)
}
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
}
func leaveIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
mreq := &syscall.IPv6Mreq{}
copy(mreq.Multiaddr[:], ip)
if ifi != nil {
mreq.Interface = uint32(ifi.Index)
}
fd.incref()
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq))
}
// Copyright 2011 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 freebsd netbsd openbsd
// IP-level socket options for BSD variants
package net
import (
"os"
"syscall"
)
func ipv4MulticastTTL(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return int(v), nil
}
func setIPv4MulticastTTL(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv6TrafficClass(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv6TrafficClass(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
// Copyright 2011 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.
// IP-level socket options for Darwin
package net
import (
"os"
"syscall"
)
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
fd.incref()
defer fd.decref()
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3]))
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
ip, err := interfaceToIPv4Addr(ifi)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
var x [4]byte
copy(x[:], ip.To4())
fd.incref()
defer fd.decref()
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
// Copyright 2011 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.
// IP-level socket options for FreeBSD
package net
import (
"os"
"syscall"
)
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
fd.incref()
defer fd.decref()
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
if int(mreq.Ifindex) == 0 {
return nil, nil
}
return InterfaceByIndex(int(mreq.Ifindex))
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
var v int32
if ifi != nil {
v = int32(ifi.Index)
}
mreq := &syscall.IPMreqn{Ifindex: v}
fd.incref()
defer fd.decref()
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
// Copyright 2011 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.
// IP-level socket options for Linux
package net
import (
"os"
"syscall"
)
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
fd.incref()
defer fd.decref()
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
if int(mreq.Ifindex) == 0 {
return nil, nil
}
return InterfaceByIndex(int(mreq.Ifindex))
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
var v int32
if ifi != nil {
v = int32(ifi.Index)
}
mreq := &syscall.IPMreqn{Ifindex: v}
fd.incref()
defer fd.decref()
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4MulticastTTL(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv4MulticastTTL(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv6TrafficClass(fd *netFD) (int, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
if err != nil {
return -1, os.NewSyscallError("getsockopt", err)
}
return v, nil
}
func setIPv6TrafficClass(fd *netFD, v int) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
// Copyright 2011 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.
// IP-level socket options for OpenBSD
package net
import (
"os"
"syscall"
)
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
fd.incref()
defer fd.decref()
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3]))
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
ip, err := interfaceToIPv4Addr(ifi)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
var x [4]byte
copy(x[:], ip.To4())
fd.incref()
defer fd.decref()
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
fd.incref()
defer fd.decref()
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
fd.incref()
defer fd.decref()
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
if err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
// Copyright 2011 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.
// IP-level socket options for Windows
package net
import (
"os"
)
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
// TODO: Implement this
return nil, os.EWINDOWS
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
// TODO: Implement this
return os.EWINDOWS
}
func ipv4MulticastTTL(fd *netFD) (int, error) {
// TODO: Implement this
return -1, os.EWINDOWS
}
func setIPv4MulticastTTL(fd *netFD, v int) error {
// TODO: Implement this
return os.EWINDOWS
}
func ipv4MultiastLoopback(fd *netFD) (bool, error) {
// TODO: Implement this
return false, os.EWINDOWS
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
// TODO: Implement this
return os.EWINDOWS
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
// TODO: Implement this
return false, os.EWINDOWS
}
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
// TODO: Implement this
return os.EWINDOWS
}
func ipv6TrafficClass(fd *netFD) (int, error) {
// TODO: Implement this
return os.EWINDOWS
}
func setIPv6TrafficClass(fd *netFD, v int) error {
// TODO: Implement this
return os.EWINDOWS
}
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
package net package net
import ( import (
"bytes"
"os" "os"
"syscall" "syscall"
) )
...@@ -272,66 +271,32 @@ func (c *UDPConn) LeaveGroup(ifi *Interface, addr IP) error { ...@@ -272,66 +271,32 @@ func (c *UDPConn) LeaveGroup(ifi *Interface, addr IP) error {
} }
func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} err := joinIPv4Group(c.fd, ifi, ip)
if err := setIPv4InterfaceToJoin(mreq, ifi); err != nil { if err != nil {
return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err}
}
if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)); err != nil {
return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err} return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err}
} }
return nil return nil
} }
func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} err := leaveIPv4Group(c.fd, ifi, ip)
if err := setIPv4InterfaceToJoin(mreq, ifi); err != nil {
return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err}
}
if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)); err != nil {
return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err}
}
return nil
}
func setIPv4InterfaceToJoin(mreq *syscall.IPMreq, ifi *Interface) error {
if ifi == nil {
return nil
}
ifat, err := ifi.Addrs()
if err != nil { if err != nil {
return err return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err}
}
for _, ifa := range ifat {
if x := ifa.(*IPAddr).IP.To4(); x != nil {
copy(mreq.Interface[:], x)
break
}
}
if bytes.Equal(mreq.Multiaddr[:], IPv4zero) {
return os.EINVAL
} }
return nil return nil
} }
func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
mreq := &syscall.IPv6Mreq{} err := joinIPv6Group(c.fd, ifi, ip)
copy(mreq.Multiaddr[:], ip) if err != nil {
if ifi != nil {
mreq.Interface = uint32(ifi.Index)
}
if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(c.fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)); err != nil {
return &OpError{"joinipv6group", "udp", &IPAddr{ip}, err} return &OpError{"joinipv6group", "udp", &IPAddr{ip}, err}
} }
return nil return nil
} }
func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
mreq := &syscall.IPv6Mreq{} err := leaveIPv6Group(c.fd, ifi, ip)
copy(mreq.Multiaddr[:], ip) if err != nil {
if ifi != nil {
mreq.Interface = uint32(ifi.Index)
}
if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(c.fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq)); err != nil {
return &OpError{"leaveipv6group", "udp", &IPAddr{ip}, err} return &OpError{"leaveipv6group", "udp", &IPAddr{ip}, err}
} }
return nil return nil
......
// Copyright 2011 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.
package net
import (
"runtime"
"testing"
)
var unicastTests = []struct {
net string
laddr string
ipv6 bool
packet bool
}{
{"tcp4", "127.0.0.1:0", false, false},
{"tcp6", "[::1]:0", true, false},
{"udp4", "127.0.0.1:0", false, true},
{"udp6", "[::1]:0", true, true},
}
func TestUnicastTCPAndUDP(t *testing.T) {
if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
return
}
for _, tt := range unicastTests {
if tt.ipv6 && !supportsIPv6 {
continue
}
var fd *netFD
if !tt.packet {
c, err := Listen(tt.net, tt.laddr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
defer c.Close()
fd = c.(*TCPListener).fd
} else {
c, err := ListenPacket(tt.net, tt.laddr)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
defer c.Close()
fd = c.(*UDPConn).fd
}
if !tt.ipv6 {
testIPv4UnicastSocketOptions(t, fd)
} else {
testIPv6UnicastSocketOptions(t, fd)
}
}
}
func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
tos, err := ipv4TOS(fd)
if err != nil {
t.Fatalf("ipv4TOS failed: %v", err)
}
t.Logf("IPv4 TOS: %v", tos)
err = setIPv4TOS(fd, 1)
if err != nil {
t.Fatalf("setIPv4TOS failed: %v", err)
}
ttl, err := ipv4TTL(fd)
if err != nil {
t.Fatalf("ipv4TTL failed: %v", err)
}
t.Logf("IPv4 TTL: %v", ttl)
err = setIPv4TTL(fd, 1)
if err != nil {
t.Fatalf("setIPv4TTL failed: %v", err)
}
}
func testIPv6UnicastSocketOptions(t *testing.T, fd *netFD) {
tos, err := ipv6TrafficClass(fd)
if err != nil {
t.Fatalf("ipv6TrafficClass failed: %v", err)
}
t.Logf("IPv6 TrafficClass: %v", tos)
err = setIPv6TrafficClass(fd, 1)
if err != nil {
t.Fatalf("setIPv6TrafficClass failed: %v", err)
}
hoplim, err := ipv6HopLimit(fd)
if err != nil {
t.Fatalf("ipv6HopLimit failed: %v", err)
}
t.Logf("IPv6 HopLimit: %v", hoplim)
err = setIPv6HopLimit(fd, 1)
if err != nil {
t.Fatalf("setIPv6HopLimit failed: %v", err)
}
}
...@@ -641,10 +641,21 @@ type Linger struct { ...@@ -641,10 +641,21 @@ type Linger struct {
} }
const ( const (
IP_TOS = 0x3
IP_TTL = 0x4
IP_ADD_MEMBERSHIP = 0xc IP_ADD_MEMBERSHIP = 0xc
IP_DROP_MEMBERSHIP = 0xd IP_DROP_MEMBERSHIP = 0xd
) )
const (
IPV6_UNICAST_HOPS = 0x4
IPV6_MULTICAST_IF = 0x9
IPV6_MULTICAST_HOPS = 0xa
IPV6_MULTICAST_LOOP = 0xb
IPV6_JOIN_GROUP = 0xc
IPV6_LEAVE_GROUP = 0xd
)
type IPMreq struct { type IPMreq struct {
Multiaddr [4]byte /* in_addr */ Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */ Interface [4]byte /* in_addr */
...@@ -655,6 +666,7 @@ type IPv6Mreq struct { ...@@ -655,6 +666,7 @@ type IPv6Mreq struct {
Interface uint32 Interface uint32
} }
func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS }
func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { return EWINDOWS } func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { return EWINDOWS }
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment