Commit 7419921b authored by Mikio Hara's avatar Mikio Hara

net: platform-dependent default socket options

This CL revises existing platform-dependent default socket
options to make it possible to accomodate multiple multicast
datagram listeners on a single service port.

Also removes unnecessary SO_REUSEADDR, SO_REUSEPORT socket
options from unicast datagram sockets by default.

Fixes #1692.

R=devon.odell, alex.brainman, rsc
CC=golang-dev
https://golang.org/cl/5538052
parent 2374edc6
...@@ -95,6 +95,49 @@ func TestMulticastUDP(t *testing.T) { ...@@ -95,6 +95,49 @@ func TestMulticastUDP(t *testing.T) {
} }
} }
func TestSimpleMulticastUDP(t *testing.T) {
if runtime.GOOS == "plan9" {
return
}
if !*multicast {
t.Logf("test disabled; use --multicast to enable")
return
}
for _, tt := range multicastUDPTests {
var ifi *Interface
if tt.ipv6 {
continue
}
tt.flags = FlagUp | FlagMulticast
ift, err := Interfaces()
if err != nil {
t.Fatalf("Interfaces failed: %v", err)
}
for _, x := range ift {
if x.Flags&tt.flags == tt.flags {
ifi = &x
break
}
}
if ifi == nil {
t.Logf("an appropriate multicast interface not found")
return
}
c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr})
if err != nil {
t.Fatalf("ListenUDP failed: %v", err)
}
defer c.Close()
if err := c.JoinGroup(ifi, tt.gaddr); err != nil {
t.Fatalf("JoinGroup failed: %v", err)
}
if err := c.LeaveGroup(ifi, tt.gaddr); err != nil {
t.Fatalf("LeaveGroup failed: %v", err)
}
}
}
func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) { func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
ifmc, err := ipv4MulticastInterface(fd) ifmc, err := ipv4MulticastInterface(fd)
if err != nil { if err != nil {
......
...@@ -28,7 +28,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal ...@@ -28,7 +28,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
syscall.CloseOnExec(s) syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock() syscall.ForkLock.RUnlock()
setKernelSpecificSockopt(s, f) setDefaultSockopts(s, f, p)
if la != nil { if la != nil {
e = syscall.Bind(s, la) e = syscall.Bind(s, la)
......
...@@ -12,22 +12,33 @@ import ( ...@@ -12,22 +12,33 @@ import (
"syscall" "syscall"
) )
func setKernelSpecificSockopt(s, f int) { func setDefaultSockopts(s, f, p int) {
// Allow reuse of recently-used addresses. switch f {
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) case syscall.AF_INET6:
// Allow both IP versions even if the OS default is otherwise.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
}
// Allow reuse of recently-used ports. if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP {
// This option is supported only in descendants of 4.4BSD, // Allow reuse of recently-used addresses.
// to make an effective multicast application and an application syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
// that requires quick draw possible.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) // Allow reuse of recently-used ports.
// This option is supported only in descendants of 4.4BSD,
// to make an effective multicast application and an application
// that requires quick draw possible.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
}
// Allow broadcast. // Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
}
if f == syscall.AF_INET6 { func setDefaultMulticastSockopts(fd *netFD) {
// using ip, tcp, udp, etc. fd.incref()
// allow both protocols even if the OS default is otherwise. defer fd.decref()
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) // Allow multicast UDP and raw IP datagram sockets to listen
} // concurrently across multiple listeners.
syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
} }
...@@ -10,16 +10,27 @@ import ( ...@@ -10,16 +10,27 @@ import (
"syscall" "syscall"
) )
func setKernelSpecificSockopt(s, f int) { func setDefaultSockopts(s, f, p int) {
// Allow reuse of recently-used addresses. switch f {
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) case syscall.AF_INET6:
// Allow both IP versions even if the OS default is otherwise.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
}
if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP {
// Allow reuse of recently-used addresses.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
}
// Allow broadcast. // Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
if f == syscall.AF_INET6 { }
// using ip, tcp, udp, etc.
// allow both protocols even if the OS default is otherwise. func setDefaultMulticastSockopts(fd *netFD) {
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) fd.incref()
} defer fd.decref()
// Allow multicast UDP and raw IP datagram sockets to listen
// concurrently across multiple listeners.
syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
} }
...@@ -10,7 +10,13 @@ import ( ...@@ -10,7 +10,13 @@ import (
"syscall" "syscall"
) )
func setKernelSpecificSockopt(s syscall.Handle, f int) { func setDefaultSockopts(s syscall.Handle, f, p int) {
switch f {
case syscall.AF_INET6:
// Allow both IP versions even if the OS default is otherwise.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
}
// Windows will reuse recently-used addresses by default. // Windows will reuse recently-used addresses by default.
// SO_REUSEADDR should not be used here, as it allows // SO_REUSEADDR should not be used here, as it allows
// a socket to forcibly bind to a port in use by another socket. // a socket to forcibly bind to a port in use by another socket.
...@@ -21,9 +27,12 @@ func setKernelSpecificSockopt(s syscall.Handle, f int) { ...@@ -21,9 +27,12 @@ func setKernelSpecificSockopt(s syscall.Handle, f int) {
// Allow broadcast. // Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
if f == syscall.AF_INET6 { }
// using ip, tcp, udp, etc.
// allow both protocols even if the OS default is otherwise. func setDefaultMulticastSockopts(fd *netFD) {
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) fd.incref()
} defer fd.decref()
// Allow multicast UDP and raw IP datagram sockets to listen
// concurrently across multiple listeners.
syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
} }
...@@ -251,6 +251,7 @@ func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error { ...@@ -251,6 +251,7 @@ func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error {
if !c.ok() { if !c.ok() {
return os.EINVAL return os.EINVAL
} }
setDefaultMulticastSockopts(c.fd)
ip := addr.To4() ip := addr.To4()
if ip != nil { if ip != nil {
return joinIPv4GroupUDP(c, ifi, ip) return joinIPv4GroupUDP(c, ifi, ip)
......
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