author | Mikio Hara
<mikioh.mikioh@gmail.com> 2016-09-03 02:20:35 UTC |
committer | Mikio Hara
<mikioh.mikioh@gmail.com> 2016-09-10 09:57:27 UTC |
parent | 9313baa13d9262e49d07b20ed57dceafcd7240cc |
icmp/listen_posix.go | +4 | -2 |
icmp/ping_test.go | +34 | -0 |
diff --git a/icmp/listen_posix.go b/icmp/listen_posix.go index b9f2607..7fac4f9 100644 --- a/icmp/listen_posix.go +++ b/icmp/listen_posix.go @@ -65,22 +65,24 @@ func ListenPacket(network, address string) (*PacketConn, error) { if err != nil { return nil, os.NewSyscallError("socket", err) } - defer syscall.Close(s) if runtime.GOOS == "darwin" && family == syscall.AF_INET { if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil { + syscall.Close(s) return nil, os.NewSyscallError("setsockopt", err) } } sa, err := sockaddr(family, address) if err != nil { + syscall.Close(s) return nil, err } if err := syscall.Bind(s, sa); err != nil { + syscall.Close(s) return nil, os.NewSyscallError("bind", err) } f := os.NewFile(uintptr(s), "datagram-oriented icmp") - defer f.Close() c, cerr = net.FilePacketConn(f) + f.Close() default: c, cerr = net.ListenPacket(network, address) } diff --git a/icmp/ping_test.go b/icmp/ping_test.go index 4ec2692..3171dad 100644 --- a/icmp/ping_test.go +++ b/icmp/ping_test.go @@ -10,6 +10,7 @@ import ( "net" "os" "runtime" + "sync" "testing" "time" @@ -164,3 +165,36 @@ func doPing(tt pingTest, seq int) error { return fmt.Errorf("got %+v from %v; want echo reply", rm, peer) } } + +func TestConcurrentNonPrivilegedListenPacket(t *testing.T) { + if testing.Short() { + t.Skip("avoid external network") + } + switch runtime.GOOS { + case "darwin": + case "linux": + t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state") + default: + t.Skipf("not supported on %s", runtime.GOOS) + } + + network, address := "udp4", "127.0.0.1" + if !nettest.SupportsIPv4() { + network, address = "udp6", "::1" + } + const N = 1000 + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + c, err := icmp.ListenPacket(network, address) + if err != nil { + t.Error(err) + return + } + c.Close() + }() + } + wg.Wait() +}