aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikio Hara <mikioh.mikioh@gmail.com>2012-01-15 14:19:44 +0900
committerMikio Hara <mikioh.mikioh@gmail.com>2012-01-15 14:19:44 +0900
commit7419921bf3acebd462b48cbf1f4dfb14233f8872 (patch)
treeb69f09a4c4779d79b7db4ad75d2b869ada25ced4
parent2374edc6401401fcaa0d328bab38c9e3cffc9274 (diff)
downloadgo-7419921bf3acebd462b48cbf1f4dfb14233f8872.tar.gz
go-7419921bf3acebd462b48cbf1f4dfb14233f8872.zip
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
-rw-r--r--src/pkg/net/multicast_test.go43
-rw-r--r--src/pkg/net/sock.go2
-rw-r--r--src/pkg/net/sockopt_bsd.go37
-rw-r--r--src/pkg/net/sockopt_linux.go27
-rw-r--r--src/pkg/net/sockopt_windows.go21
-rw-r--r--src/pkg/net/udpsock_posix.go1
6 files changed, 103 insertions, 28 deletions
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 96bac458da..183d5a8aba 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -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) {
ifmc, err := ipv4MulticastInterface(fd)
if err != nil {
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index 7732d2e063..881c922a25 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -28,7 +28,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
- setKernelSpecificSockopt(s, f)
+ setDefaultSockopts(s, f, p)
if la != nil {
e = syscall.Bind(s, la)
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index 370831fe5f..e99fb418cd 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -12,22 +12,33 @@ import (
"syscall"
)
-func setKernelSpecificSockopt(s, f int) {
- // Allow reuse of recently-used addresses.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+func setDefaultSockopts(s, 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)
+ }
- // 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)
+ 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 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.
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.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
- }
+func setDefaultMulticastSockopts(fd *netFD) {
+ 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)
+ syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
}
diff --git a/src/pkg/net/sockopt_linux.go b/src/pkg/net/sockopt_linux.go
index e55c3c5ce8..51583844f1 100644
--- a/src/pkg/net/sockopt_linux.go
+++ b/src/pkg/net/sockopt_linux.go
@@ -10,16 +10,27 @@ import (
"syscall"
)
-func setKernelSpecificSockopt(s, f int) {
- // Allow reuse of recently-used addresses.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+func setDefaultSockopts(s, 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)
+ }
+
+ 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.
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.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
- }
+}
+
+func setDefaultMulticastSockopts(fd *netFD) {
+ 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)
}
diff --git a/src/pkg/net/sockopt_windows.go b/src/pkg/net/sockopt_windows.go
index df15b8c4c8..485c14a2d3 100644
--- a/src/pkg/net/sockopt_windows.go
+++ b/src/pkg/net/sockopt_windows.go
@@ -10,7 +10,13 @@ import (
"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.
// SO_REUSEADDR should not be used here, as it allows
// a socket to forcibly bind to a port in use by another socket.
@@ -21,9 +27,12 @@ func setKernelSpecificSockopt(s syscall.Handle, f int) {
// Allow broadcast.
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.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
- }
+}
+
+func setDefaultMulticastSockopts(fd *netFD) {
+ 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)
}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 7bc4cb9f7e..d0bdb14755 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -251,6 +251,7 @@ func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error {
if !c.ok() {
return os.EINVAL
}
+ setDefaultMulticastSockopts(c.fd)
ip := addr.To4()
if ip != nil {
return joinIPv4GroupUDP(c, ifi, ip)