]> Cypherpunks repositories - gostls13.git/commitdiff
net: platform-dependent default socket options
authorMikio Hara <mikioh.mikioh@gmail.com>
Sun, 15 Jan 2012 05:19:44 +0000 (14:19 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Sun, 15 Jan 2012 05:19:44 +0000 (14:19 +0900)
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

src/pkg/net/multicast_test.go
src/pkg/net/sock.go
src/pkg/net/sockopt_bsd.go
src/pkg/net/sockopt_linux.go
src/pkg/net/sockopt_windows.go
src/pkg/net/udpsock_posix.go

index 96bac458da7bcd6ffb14b65b2432c9acf7622606..183d5a8abaa837c9a136525098442614709896ad 100644 (file)
@@ -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 {
index 7732d2e06301456f8d6ff0981254dddc3fd70448..881c922a25f31f3cb7c3ca2ca1f526fa3f713ef0 100644 (file)
@@ -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)
index 370831fe5f4c18831077aa454725612065e603e7..e99fb418cddf99e351711216fae86097735c94b0 100644 (file)
@@ -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)
 }
index e55c3c5ce8cc6939978d69b1807c755944903e93..51583844f1f6204bfa358a3f3438d219c415c5d2 100644 (file)
@@ -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)
 }
index df15b8c4c83bccc675680f51f40d9d7d104f33c8..485c14a2d3ecc8c610b5ad45f48cd4b8e16b9923 100644 (file)
@@ -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)
 }
index 7bc4cb9f7ece0962e8f8a87a0151df3f86e3612c..d0bdb14755e4348772444095a8a3b6f079a7155c 100644 (file)
@@ -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)