mirror of
https://github.com/golang/go
synced 2024-11-24 22:00:09 -07:00
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
This commit is contained in:
parent
6a0e6cc7f4
commit
cbdbdc4f61
@ -36,7 +36,11 @@ GOFILES_darwin=\
|
||||
port.go\
|
||||
sendfile_stub.go\
|
||||
sock.go\
|
||||
sock_bsd.go\
|
||||
sockopt.go\
|
||||
sockopt_bsd.go\
|
||||
sockoptip.go\
|
||||
sockoptip_bsd.go\
|
||||
sockoptip_darwin.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
@ -64,7 +68,11 @@ GOFILES_freebsd=\
|
||||
port.go\
|
||||
sendfile_stub.go\
|
||||
sock.go\
|
||||
sock_bsd.go\
|
||||
sockopt.go\
|
||||
sockopt_bsd.go\
|
||||
sockoptip.go\
|
||||
sockoptip_bsd.go\
|
||||
sockoptip_freebsd.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
@ -91,7 +99,10 @@ GOFILES_linux=\
|
||||
port.go\
|
||||
sendfile_linux.go\
|
||||
sock.go\
|
||||
sock_linux.go\
|
||||
sockopt.go\
|
||||
sockopt_linux.go\
|
||||
sockoptip.go\
|
||||
sockoptip_linux.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
@ -119,7 +130,11 @@ GOFILES_netbsd=\
|
||||
port.go\
|
||||
sendfile_stub.go\
|
||||
sock.go\
|
||||
sock_bsd.go\
|
||||
sockopt.go\
|
||||
sockopt_bsd.go\
|
||||
sockoptip.go\
|
||||
sockoptip_bsd.go\
|
||||
sockoptip_netbsd.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
@ -140,7 +155,11 @@ GOFILES_openbsd=\
|
||||
port.go\
|
||||
sendfile_stub.go\
|
||||
sock.go\
|
||||
sock_bsd.go\
|
||||
sockopt.go\
|
||||
sockopt_bsd.go\
|
||||
sockoptip.go\
|
||||
sockoptip_bsd.go\
|
||||
sockoptip_openbsd.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
@ -165,7 +184,10 @@ GOFILES_windows=\
|
||||
lookup_windows.go\
|
||||
sendfile_windows.go\
|
||||
sock.go\
|
||||
sock_windows.go\
|
||||
sockopt.go\
|
||||
sockopt_windows.go\
|
||||
sockoptip.go\
|
||||
sockoptip_windows.go\
|
||||
tcpsock_posix.go\
|
||||
udpsock_posix.go\
|
||||
unixsock_posix.go\
|
||||
|
@ -12,6 +12,14 @@ import (
|
||||
"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.
|
||||
type HardwareAddr []byte
|
||||
|
||||
@ -131,7 +139,7 @@ func (f Flags) String() string {
|
||||
// Addrs returns interface addresses for a specific interface.
|
||||
func (ifi *Interface) Addrs() ([]Addr, error) {
|
||||
if ifi == nil {
|
||||
return nil, errors.New("net: invalid interface")
|
||||
return nil, errInvalidInterface
|
||||
}
|
||||
return interfaceAddrTable(ifi.Index)
|
||||
}
|
||||
@ -140,7 +148,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
|
||||
// a specific interface.
|
||||
func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
|
||||
if ifi == nil {
|
||||
return nil, errors.New("net: invalid interface")
|
||||
return nil, errInvalidInterface
|
||||
}
|
||||
return interfaceMulticastAddrTable(ifi.Index)
|
||||
}
|
||||
@ -159,7 +167,7 @@ func InterfaceAddrs() ([]Addr, error) {
|
||||
// InterfaceByIndex returns the interface specified by index.
|
||||
func InterfaceByIndex(index int) (*Interface, error) {
|
||||
if index <= 0 {
|
||||
return nil, errors.New("net: invalid interface index")
|
||||
return nil, errInvalidInterfaceIndex
|
||||
}
|
||||
ift, err := interfaceTable(index)
|
||||
if err != nil {
|
||||
@ -168,13 +176,13 @@ func InterfaceByIndex(index int) (*Interface, error) {
|
||||
for _, ifi := range ift {
|
||||
return &ifi, nil
|
||||
}
|
||||
return nil, errors.New("net: no such interface")
|
||||
return nil, errNoSuchInterface
|
||||
}
|
||||
|
||||
// InterfaceByName returns the interface specified by name.
|
||||
func InterfaceByName(name string) (*Interface, error) {
|
||||
if name == "" {
|
||||
return nil, errors.New("net: invalid interface name")
|
||||
return nil, errInvalidInterfaceName
|
||||
}
|
||||
ift, err := interfaceTable(0)
|
||||
if err != nil {
|
||||
@ -185,5 +193,5 @@ func InterfaceByName(name string) (*Interface, error) {
|
||||
return &ifi, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("net: no such interface")
|
||||
return nil, errNoSuchInterface
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
var multicast = flag.Bool("multicast", false, "enable multicast tests")
|
||||
|
||||
var joinAndLeaveGroupUDPTests = []struct {
|
||||
var multicastUDPTests = []struct {
|
||||
net string
|
||||
laddr IP
|
||||
gaddr IP
|
||||
@ -32,8 +32,8 @@ var joinAndLeaveGroupUDPTests = []struct {
|
||||
{"udp6", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true},
|
||||
}
|
||||
|
||||
func TestJoinAndLeaveGroupUDP(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
func TestMulticastUDP(t *testing.T) {
|
||||
if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
|
||||
return
|
||||
}
|
||||
if !*multicast {
|
||||
@ -41,7 +41,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, tt := range joinAndLeaveGroupUDPTests {
|
||||
for _, tt := range multicastUDPTests {
|
||||
var (
|
||||
ifi *Interface
|
||||
found bool
|
||||
@ -51,7 +51,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
|
||||
}
|
||||
ift, err := Interfaces()
|
||||
if err != nil {
|
||||
t.Fatalf("Interfaces() failed: %v", err)
|
||||
t.Fatalf("Interfaces failed: %v", err)
|
||||
}
|
||||
for _, x := range ift {
|
||||
if x.Flags&tt.flags == tt.flags {
|
||||
@ -65,15 +65,20 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
|
||||
}
|
||||
c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("ListenUDP failed: %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
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()
|
||||
if err != nil {
|
||||
t.Fatalf("MulticastAddrs() failed: %v", err)
|
||||
t.Fatalf("MulticastAddrs failed: %v", err)
|
||||
}
|
||||
for _, ifma := range ifmat {
|
||||
if ifma.(*IPAddr).IP.Equal(tt.gaddr) {
|
||||
@ -85,7 +90,71 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) {
|
||||
t.Fatalf("%q not found in RIB", tt.gaddr.String())
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Boolean to int.
|
||||
func boolint(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Generic socket creation.
|
||||
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.
|
||||
@ -67,83 +58,6 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
|
||||
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 {
|
||||
sa syscall.Sockaddr
|
||||
}
|
||||
|
171
src/pkg/net/sockopt.go
Normal file
171
src/pkg/net/sockopt.go
Normal file
@ -0,0 +1,171 @@
|
||||
// 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 @@
|
||||
|
||||
// +build darwin freebsd netbsd openbsd
|
||||
|
||||
// Sockets for BSD variants
|
||||
// Socket options for BSD variants
|
||||
|
||||
package net
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Sockets for Linux
|
||||
// Socket options for Linux
|
||||
|
||||
package net
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Sockets for Windows
|
||||
// Socket options for Windows
|
||||
|
||||
package net
|
||||
|
187
src/pkg/net/sockoptip.go
Normal file
187
src/pkg/net/sockoptip.go
Normal file
@ -0,0 +1,187 @@
|
||||
// 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))
|
||||
}
|
54
src/pkg/net/sockoptip_bsd.go
Normal file
54
src/pkg/net/sockoptip_bsd.go
Normal file
@ -0,0 +1,54 @@
|
||||
// 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
|
||||
}
|
78
src/pkg/net/sockoptip_darwin.go
Normal file
78
src/pkg/net/sockoptip_darwin.go
Normal file
@ -0,0 +1,78 @@
|
||||
// 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
|
||||
}
|
80
src/pkg/net/sockoptip_freebsd.go
Normal file
80
src/pkg/net/sockoptip_freebsd.go
Normal file
@ -0,0 +1,80 @@
|
||||
// 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
|
||||
}
|
120
src/pkg/net/sockoptip_linux.go
Normal file
120
src/pkg/net/sockoptip_linux.go
Normal file
@ -0,0 +1,120 @@
|
||||
// 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
|
||||
}
|
78
src/pkg/net/sockoptip_openbsd.go
Normal file
78
src/pkg/net/sockoptip_openbsd.go
Normal file
@ -0,0 +1,78 @@
|
||||
// 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
|
||||
}
|
61
src/pkg/net/sockoptip_windows.go
Normal file
61
src/pkg/net/sockoptip_windows.go
Normal file
@ -0,0 +1,61 @@
|
||||
// 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 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
@ -272,66 +271,32 @@ func (c *UDPConn) LeaveGroup(ifi *Interface, addr 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]}}
|
||||
if err := setIPv4InterfaceToJoin(mreq, ifi); 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 {
|
||||
err := joinIPv4Group(c.fd, ifi, ip)
|
||||
if err != nil {
|
||||
return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
|
||||
mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}}
|
||||
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()
|
||||
err := leaveIPv4Group(c.fd, ifi, ip)
|
||||
if err != nil {
|
||||
return 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 &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
|
||||
mreq := &syscall.IPv6Mreq{}
|
||||
copy(mreq.Multiaddr[:], ip)
|
||||
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 {
|
||||
err := joinIPv6Group(c.fd, ifi, ip)
|
||||
if err != nil {
|
||||
return &OpError{"joinipv6group", "udp", &IPAddr{ip}, err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
|
||||
mreq := &syscall.IPv6Mreq{}
|
||||
copy(mreq.Multiaddr[:], ip)
|
||||
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 {
|
||||
err := leaveIPv6Group(c.fd, ifi, ip)
|
||||
if err != nil {
|
||||
return &OpError{"leaveipv6group", "udp", &IPAddr{ip}, err}
|
||||
}
|
||||
return nil
|
||||
|
99
src/pkg/net/unicast_test.go
Normal file
99
src/pkg/net/unicast_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
// 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 {
|
||||
}
|
||||
|
||||
const (
|
||||
IP_TOS = 0x3
|
||||
IP_TTL = 0x4
|
||||
IP_ADD_MEMBERSHIP = 0xc
|
||||
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 {
|
||||
Multiaddr [4]byte /* in_addr */
|
||||
Interface [4]byte /* in_addr */
|
||||
@ -655,6 +666,7 @@ type IPv6Mreq struct {
|
||||
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 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)))
|
||||
|
Loading…
Reference in New Issue
Block a user