]> Cypherpunks repositories - gostls13.git/commitdiff
net: add socket system call hooks for testing
authorMikio Hara <mikioh.mikioh@gmail.com>
Sun, 1 Mar 2015 03:27:01 +0000 (12:27 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 31 Mar 2015 23:07:42 +0000 (23:07 +0000)
This change adds socket system call hooks to existing test cases for
simulating a bit complicated network conditions to help making timeout
and dual IP stack test cases work more properly in followup changes.

Also test cases print debugging information in non-short mode like the
following:

Leaked goroutines:
net.TestWriteTimeout.func2(0xc20802a5a0, 0xc20801d000, 0x1000, 0x1000, 0xc2081d2ae0)
/go/src/net/timeout_test.go:170 +0x98
created by net.TestWriteTimeout
/go/src/net/timeout_test.go:173 +0x745
net.runDatagramPacketConnServer(0xc2080730e0, 0x2bd270, 0x3, 0x2c1770, 0xb, 0xc2081d2ba0, 0xc2081d2c00)
/go/src/net/server_test.go:398 +0x667
created by net.TestTimeoutUDP
/go/src/net/timeout_test.go:247 +0xc9
(snip)

Leaked sockets:
3: {Cookie:615726511685632 Err:<nil> SocketErr:0}
5: {Cookie:7934075906097152 Err:<nil> SocketErr:0}

Socket statistical information:
{Family:1 Type:805306370 Protocol:0 Opened:17 Accepted:0 Connected:5 Closed:17}
{Family:2 Type:805306369 Protocol:0 Opened:450 Accepted:234 Connected:279 Closed:636}
{Family:1 Type:805306369 Protocol:0 Opened:11 Accepted:5 Connected:5 Closed:16}
{Family:28 Type:805306369 Protocol:0 Opened:95 Accepted:22 Connected:16 Closed:116}
{Family:2 Type:805306370 Protocol:0 Opened:84 Accepted:0 Connected:34 Closed:83}
{Family:28 Type:805306370 Protocol:0 Opened:52 Accepted:0 Connected:4 Closed:52}

Change-Id: I0e84be59a0699bc31245c78e2249423459b8cdda
Reviewed-on: https://go-review.googlesource.com/6390
Reviewed-by: Ian Lance Taylor <iant@golang.org>
21 files changed:
src/net/dnsclient_unix_test.go
src/net/dnsname_test.go
src/net/fd_unix.go
src/net/fd_windows.go
src/net/file_unix.go
src/net/hook_cloexec.go [new file with mode: 0644]
src/net/hook_unix.go [new file with mode: 0644]
src/net/hook_windows.go [new file with mode: 0644]
src/net/interface_test.go
src/net/ip_test.go
src/net/ipsock_posix.go
src/net/main_cloexec_test.go [new file with mode: 0644]
src/net/main_plan9_test.go [new file with mode: 0644]
src/net/main_test.go [new file with mode: 0644]
src/net/main_unix_test.go [new file with mode: 0644]
src/net/main_windows_test.go [new file with mode: 0644]
src/net/sock_cloexec.go
src/net/sock_posix.go
src/net/sock_windows.go
src/net/sys_cloexec.go
src/net/tcp_test.go

index 40b78bda98a9a3e898c8e5c19fe30c6d9f933879..2934634769ad07193c9a523fc9584b2495cdd7dc 100644 (file)
@@ -219,18 +219,27 @@ func TestReloadResolvConfChange(t *testing.T) {
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                goLookupIP("www.example.com")
        }
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                goLookupIP("some.nonexistent")
        }
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        onceLoadConfig.Do(loadDefaultConfig)
        if cfg.dnserr != nil || cfg.dnsConfig == nil {
                b.Fatalf("loadConfig failed: %v", cfg.dnserr)
index 57dd25fe4c6dec1752858c13c926ed1bc228a74a..4fecf8dbe24fa01b09a457e618df1d94b447c09a 100644 (file)
@@ -69,6 +69,9 @@ func TestDNSNames(t *testing.T) {
 }
 
 func BenchmarkDNSNames(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        benchmarks := append(tests, []testCase{
                {strings.Repeat("a", 63), true},
                {strings.Repeat("a", 64), false},
index 24e6c59f370785d141c1be6a1b6529e826ad8c1c..9e1976136dc911e232671af8121bfd57271d56eb 100644 (file)
@@ -72,7 +72,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
-       switch err := syscall.Connect(fd.sysfd, ra); err {
+       switch err := connectFunc(fd.sysfd, ra); err {
        case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
        case nil, syscall.EISCONN:
                if !deadline.IsZero() && deadline.Before(time.Now()) {
@@ -114,7 +114,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
                if err := fd.pd.WaitWrite(); err != nil {
                        return err
                }
-               nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+               nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
                if err != nil {
                        return err
                }
@@ -130,9 +130,9 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 
 func (fd *netFD) destroy() {
        // Poller may want to unregister fd in readiness notification mechanism,
-       // so this must be executed before closesocket.
+       // so this must be executed before closeFunc.
        fd.pd.Close()
-       closesocket(fd.sysfd)
+       closeFunc(fd.sysfd)
        fd.sysfd = -1
        runtime.SetFinalizer(fd, nil)
 }
@@ -417,7 +417,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
        }
 
        if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
-               closesocket(s)
+               closeFunc(s)
                return nil, err
        }
        if err = netfd.init(); err != nil {
@@ -492,7 +492,3 @@ func (fd *netFD) dup() (f *os.File, err error) {
 
        return os.NewFile(uintptr(ns), fd.name()), nil
 }
-
-func closesocket(s int) error {
-       return syscall.Close(s)
-}
index 995bc4a7f50505fc26a24f9036691e4867c808f7..d6858837166800db6356e757bf4a57100154f409 100644 (file)
@@ -69,10 +69,6 @@ func sysInit() {
        }
 }
 
-func closesocket(s syscall.Handle) error {
-       return syscall.Closesocket(s)
-}
-
 func canUseConnectEx(net string) bool {
        switch net {
        case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
@@ -336,7 +332,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
                defer fd.setWriteDeadline(noDeadline)
        }
        if !canUseConnectEx(fd.net) {
-               return syscall.Connect(fd.sysfd, ra)
+               return connectFunc(fd.sysfd, ra)
        }
        // ConnectEx windows API requires an unconnected, previously bound socket.
        if la == nil {
@@ -356,7 +352,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
        o := &fd.wop
        o.sa = ra
        _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
-               return syscall.ConnectEx(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
+               return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
        })
        if err != nil {
                return err
@@ -370,9 +366,9 @@ func (fd *netFD) destroy() {
                return
        }
        // Poller may want to unregister fd in readiness notification mechanism,
-       // so this must be executed before closesocket.
+       // so this must be executed before closeFunc.
        fd.pd.Close()
-       closesocket(fd.sysfd)
+       closeFunc(fd.sysfd)
        fd.sysfd = syscall.InvalidHandle
        // no need for a finalizer anymore
        runtime.SetFinalizer(fd, nil)
@@ -540,7 +536,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
        // Associate our new socket with IOCP.
        netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
        if err != nil {
-               closesocket(s)
+               closeFunc(s)
                return nil, &OpError{"accept", fd.net, fd.laddr, err}
        }
        if err := netfd.init(); err != nil {
index 214a4196c8e3cfca5376ab380ef7912c07e7de97..8d806a1d6342099a139f5d2bff9903bdc052fb7d 100644 (file)
@@ -18,13 +18,13 @@ func newFileFD(f *os.File) (*netFD, error) {
        }
 
        if err = syscall.SetNonblock(fd, true); err != nil {
-               closesocket(fd)
+               closeFunc(fd)
                return nil, err
        }
 
        sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
        if err != nil {
-               closesocket(fd)
+               closeFunc(fd)
                return nil, os.NewSyscallError("getsockopt", err)
        }
 
@@ -33,7 +33,7 @@ func newFileFD(f *os.File) (*netFD, error) {
        lsa, _ := syscall.Getsockname(fd)
        switch lsa.(type) {
        default:
-               closesocket(fd)
+               closeFunc(fd)
                return nil, syscall.EINVAL
        case *syscall.SockaddrInet4:
                family = syscall.AF_INET
@@ -64,7 +64,7 @@ func newFileFD(f *os.File) (*netFD, error) {
 
        netfd, err := newFD(fd, family, sotype, laddr.Network())
        if err != nil {
-               closesocket(fd)
+               closeFunc(fd)
                return nil, err
        }
        if err := netfd.init(); err != nil {
diff --git a/src/net/hook_cloexec.go b/src/net/hook_cloexec.go
new file mode 100644 (file)
index 0000000..870f0d7
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2015 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 freebsd linux
+
+package net
+
+import "syscall"
+
+var (
+       // Placeholders for socket system calls.
+       accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
+)
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
new file mode 100644 (file)
index 0000000..626d07f
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 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 dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package net
+
+import "syscall"
+
+var (
+       // Placeholders for socket system calls.
+       socketFunc        func(int, int, int) (int, error)         = syscall.Socket
+       closeFunc         func(int) error                          = syscall.Close
+       connectFunc       func(int, syscall.Sockaddr) error        = syscall.Connect
+       acceptFunc        func(int) (int, syscall.Sockaddr, error) = syscall.Accept
+       getsockoptIntFunc func(int, int, int) (int, error)         = syscall.GetsockoptInt
+)
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
new file mode 100644 (file)
index 0000000..2a6e5bf
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2015 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 "syscall"
+
+var (
+       // Placeholders for socket system calls.
+       socketFunc    func(int, int, int) (syscall.Handle, error)                                               = syscall.Socket
+       closeFunc     func(syscall.Handle) error                                                                = syscall.Closesocket
+       connectFunc   func(syscall.Handle, syscall.Sockaddr) error                                              = syscall.Connect
+       connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
+)
index 16217e7c26dde9079969a457e6396712409715e1..666f11a980c2c8919508460290d1c4b0f9e66a2a 100644 (file)
@@ -229,6 +229,9 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
 }
 
 func BenchmarkInterfaces(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                if _, err := Interfaces(); err != nil {
                        b.Fatal(err)
@@ -237,6 +240,9 @@ func BenchmarkInterfaces(b *testing.B) {
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        ifi := loopbackInterface()
        if ifi == nil {
                b.Skip("loopback interface not found")
@@ -249,6 +255,9 @@ func BenchmarkInterfaceByIndex(b *testing.B) {
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        ifi := loopbackInterface()
        if ifi == nil {
                b.Skip("loopback interface not found")
@@ -261,6 +270,9 @@ func BenchmarkInterfaceByName(b *testing.B) {
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                if _, err := InterfaceAddrs(); err != nil {
                        b.Fatal(err)
@@ -269,6 +281,9 @@ func BenchmarkInterfaceAddrs(b *testing.B) {
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        ifi := loopbackInterface()
        if ifi == nil {
                b.Skip("loopback interface not found")
@@ -281,6 +296,9 @@ func BenchmarkInterfacesAndAddrs(b *testing.B) {
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        ifi := loopbackInterface()
        if ifi == nil {
                b.Skip("loopback interface not found")
index 604da3923a4e3bec679d5c8d0eb774f6f748facd..e6f4e650ca74e9334bf4525fa8b97d24a465518e 100644 (file)
@@ -53,6 +53,9 @@ func TestParseIP(t *testing.T) {
 }
 
 func BenchmarkParseIP(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                for _, tt := range parseIPTests {
                        ParseIP(tt.in)
@@ -108,6 +111,9 @@ func TestIPString(t *testing.T) {
 }
 
 func BenchmarkIPString(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                for _, tt := range ipStringTests {
                        if tt.in != nil {
@@ -158,6 +164,9 @@ func TestIPMaskString(t *testing.T) {
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        for i := 0; i < b.N; i++ {
                for _, tt := range ipMaskStringTests {
                        tt.in.String()
index f9ebe40a21efc345d70717f3011d6e0569defdb4..7597a92f6fa90435b73f28f37f832fec64aef0e5 100644 (file)
@@ -14,12 +14,12 @@ import (
 )
 
 func probeIPv4Stack() bool {
-       s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+       s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
        switch err {
        case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
                return false
        case nil:
-               closesocket(s)
+               closeFunc(s)
        }
        return true
 }
@@ -50,11 +50,11 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
        }
 
        for i := range probes {
-               s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+               s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
                if err != nil {
                        continue
                }
-               defer closesocket(s)
+               defer closeFunc(s)
                syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
                sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
                if err != nil {
diff --git a/src/net/main_cloexec_test.go b/src/net/main_cloexec_test.go
new file mode 100644 (file)
index 0000000..7903819
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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 freebsd linux
+
+package net
+
+func init() {
+       extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook)
+       extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook)
+}
+
+var (
+       // Placeholders for saving original socket system calls.
+       origAccept4 = accept4Func
+)
+
+func installAccept4TestHook() {
+       accept4Func = sw.Accept4
+}
+
+func uninstallAccept4TestHook() {
+       accept4Func = origAccept4
+}
diff --git a/src/net/main_plan9_test.go b/src/net/main_plan9_test.go
new file mode 100644 (file)
index 0000000..bbd47aa
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2015 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
+
+func installTestHooks() {}
+
+func uninstallTestHooks() {}
+
+func forceCloseSockets() {}
diff --git a/src/net/main_test.go b/src/net/main_test.go
new file mode 100644 (file)
index 0000000..bc0f92e
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2015 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 (
+       "fmt"
+       "net/internal/socktest"
+       "os"
+       "runtime"
+       "sort"
+       "strings"
+       "testing"
+)
+
+var sw socktest.Switch
+
+func TestMain(m *testing.M) {
+       installTestHooks()
+
+       st := m.Run()
+
+       if !testing.Short() {
+               printLeakedGoroutines()
+               printLeakedSockets()
+               printSocketStats()
+       }
+       forceCloseSockets()
+       uninstallTestHooks()
+       os.Exit(st)
+}
+
+func printLeakedGoroutines() {
+       gss := leakedGoroutines()
+       if len(gss) == 0 {
+               return
+       }
+       fmt.Fprintf(os.Stderr, "Leaked goroutines:\n")
+       for _, gs := range gss {
+               fmt.Fprintf(os.Stderr, "%v\n", gs)
+       }
+       fmt.Fprintf(os.Stderr, "\n")
+}
+
+// leakedGoroutines returns a list of remaining goroutins used in test
+// cases.
+func leakedGoroutines() []string {
+       var gss []string
+       b := make([]byte, 2<<20)
+       b = b[:runtime.Stack(b, true)]
+       for _, s := range strings.Split(string(b), "\n\n") {
+               ss := strings.SplitN(s, "\n", 2)
+               if len(ss) != 2 {
+                       continue
+               }
+               stack := strings.TrimSpace(ss[1])
+               if !strings.Contains(stack, "created by net") {
+                       continue
+               }
+               gss = append(gss, stack)
+       }
+       sort.Strings(gss)
+       return gss
+}
+
+func printLeakedSockets() {
+       sos := sw.Sockets()
+       if len(sos) == 0 {
+               return
+       }
+       fmt.Fprintf(os.Stderr, "Leaked sockets:\n")
+       for s, so := range sos {
+               fmt.Fprintf(os.Stderr, "%v: %+v\n", s, so)
+       }
+       fmt.Fprintf(os.Stderr, "\n")
+}
+
+func printSocketStats() {
+       sts := sw.Stats()
+       if len(sts) == 0 {
+               return
+       }
+       fmt.Fprintf(os.Stderr, "Socket statistical information:\n")
+       for _, st := range sts {
+               fmt.Fprintf(os.Stderr, "%+v\n", st)
+       }
+       fmt.Fprintf(os.Stderr, "\n")
+}
diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go
new file mode 100644 (file)
index 0000000..637ac3d
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 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 dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package net
+
+var (
+       // Placeholders for saving original socket system calls.
+       origSocket        = socketFunc
+       origClose         = closeFunc
+       origConnect       = connectFunc
+       origAccept        = acceptFunc
+       origGetsockoptInt = getsockoptIntFunc
+
+       extraTestHookInstallers   []func()
+       extraTestHookUninstallers []func()
+)
+
+func installTestHooks() {
+       socketFunc = sw.Socket
+       closeFunc = sw.Close
+       connectFunc = sw.Connect
+       acceptFunc = sw.Accept
+       getsockoptIntFunc = sw.GetsockoptInt
+
+       for _, fn := range extraTestHookInstallers {
+               fn()
+       }
+}
+
+func uninstallTestHooks() {
+       socketFunc = origSocket
+       closeFunc = origClose
+       connectFunc = origConnect
+       acceptFunc = origAccept
+       getsockoptIntFunc = origGetsockoptInt
+
+       for _, fn := range extraTestHookUninstallers {
+               fn()
+       }
+}
+
+func forceCloseSockets() {
+       for s := range sw.Sockets() {
+               closeFunc(s)
+       }
+}
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
new file mode 100644 (file)
index 0000000..03c3796
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 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
+
+var (
+       // Placeholders for saving original socket system calls.
+       origSocket      = socketFunc
+       origClosesocket = closeFunc
+       origConnect     = connectFunc
+       origConnectEx   = connectExFunc
+)
+
+func installTestHooks() {
+       socketFunc = sw.Socket
+       closeFunc = sw.Closesocket
+       connectFunc = sw.Connect
+       connectExFunc = sw.ConnectEx
+}
+
+func uninstallTestHooks() {
+       socketFunc = origSocket
+       closeFunc = origClosesocket
+       connectFunc = origConnect
+       connectExFunc = origConnectEx
+}
+
+func forceCloseSockets() {
+       for s := range sw.Sockets() {
+               closeFunc(s)
+       }
+}
index dec81855b689bf6678640e482d55d2cec2de58ac..842d7d553882997b741bb44eb49c7cf50d60aa13 100644 (file)
@@ -14,7 +14,7 @@ import "syscall"
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func sysSocket(family, sotype, proto int) (int, error) {
-       s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
+       s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
        // On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were
        // introduced in 2.6.27 kernel and on FreeBSD both flags were
        // introduced in 10 kernel. If we get an EINVAL error on Linux
@@ -26,7 +26,7 @@ func sysSocket(family, sotype, proto int) (int, error) {
 
        // See ../syscall/exec_unix.go for description of ForkLock.
        syscall.ForkLock.RLock()
-       s, err = syscall.Socket(family, sotype, proto)
+       s, err = socketFunc(family, sotype, proto)
        if err == nil {
                syscall.CloseOnExec(s)
        }
@@ -35,7 +35,7 @@ func sysSocket(family, sotype, proto int) (int, error) {
                return -1, err
        }
        if err = syscall.SetNonblock(s, true); err != nil {
-               syscall.Close(s)
+               closeFunc(s)
                return -1, err
        }
        return s, nil
@@ -44,7 +44,7 @@ func sysSocket(family, sotype, proto int) (int, error) {
 // Wrapper around the accept system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func accept(s int) (int, syscall.Sockaddr, error) {
-       ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+       ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
        // On Linux the accept4 system call was introduced in 2.6.28
        // kernel and on FreeBSD it was introduced in 10 kernel. If we
        // get an ENOSYS error on both Linux and FreeBSD, or EINVAL
@@ -63,7 +63,7 @@ func accept(s int) (int, syscall.Sockaddr, error) {
        // because we have put fd.sysfd into non-blocking mode.
        // However, a call to the File method will put it back into
        // blocking mode. We can't take that risk, so no use of ForkLock here.
-       ns, sa, err = syscall.Accept(s)
+       ns, sa, err = acceptFunc(s)
        if err == nil {
                syscall.CloseOnExec(ns)
        }
@@ -71,7 +71,7 @@ func accept(s int) (int, syscall.Sockaddr, error) {
                return -1, nil, err
        }
        if err = syscall.SetNonblock(ns, true); err != nil {
-               syscall.Close(ns)
+               closeFunc(ns)
                return -1, nil, err
        }
        return ns, sa, nil
index 3f956df65a6abc410b966984cf8e731306c9703c..013944ebec5b385da5b6a9ad8369df793f2cae2f 100644 (file)
@@ -42,11 +42,11 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
                return nil, err
        }
        if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
-               closesocket(s)
+               closeFunc(s)
                return nil, err
        }
        if fd, err = newFD(s, family, sotype, net); err != nil {
-               closesocket(s)
+               closeFunc(s)
                return nil, err
        }
 
index 6ccde3a24b94ecc88e6b547d4f0f305ce21ec1db..591861f443892200cf5c33d1e42022239e19a024 100644 (file)
@@ -12,10 +12,10 @@ func maxListenerBacklog() int {
        return syscall.SOMAXCONN
 }
 
-func sysSocket(f, t, p int) (syscall.Handle, error) {
+func sysSocket(family, sotype, proto int) (syscall.Handle, error) {
        // See ../syscall/exec_unix.go for description of ForkLock.
        syscall.ForkLock.RLock()
-       s, err := syscall.Socket(f, t, p)
+       s, err := socketFunc(family, sotype, proto)
        if err == nil {
                syscall.CloseOnExec(s)
        }
index 898fb7c0c2c5545bfca54a423253a00a56a2c6b2..5a631aa56d22e17347ae153929dc2fc6430630e1 100644 (file)
@@ -16,7 +16,7 @@ import "syscall"
 func sysSocket(family, sotype, proto int) (int, error) {
        // See ../syscall/exec_unix.go for description of ForkLock.
        syscall.ForkLock.RLock()
-       s, err := syscall.Socket(family, sotype, proto)
+       s, err := socketFunc(family, sotype, proto)
        if err == nil {
                syscall.CloseOnExec(s)
        }
@@ -25,7 +25,7 @@ func sysSocket(family, sotype, proto int) (int, error) {
                return -1, err
        }
        if err = syscall.SetNonblock(s, true); err != nil {
-               syscall.Close(s)
+               closeFunc(s)
                return -1, err
        }
        return s, nil
@@ -39,7 +39,7 @@ func accept(s int) (int, syscall.Sockaddr, error) {
        // because we have put fd.sysfd into non-blocking mode.
        // However, a call to the File method will put it back into
        // blocking mode. We can't take that risk, so no use of ForkLock here.
-       ns, sa, err := syscall.Accept(s)
+       ns, sa, err := acceptFunc(s)
        if err == nil {
                syscall.CloseOnExec(ns)
        }
@@ -47,7 +47,7 @@ func accept(s int) (int, syscall.Sockaddr, error) {
                return -1, nil, err
        }
        if err = syscall.SetNonblock(ns, true); err != nil {
-               syscall.Close(ns)
+               closeFunc(ns)
                return -1, nil, err
        }
        return ns, sa, nil
index f9a340d2d33961cb67f10c2cf133b24f34c4606f..434c9c6cef82c6972af39bff2579890fd1c2d452 100644 (file)
@@ -59,6 +59,9 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) {
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
+       uninstallTestHooks()
+       defer installTestHooks()
+
        const msgLen = 512
        conns := b.N
        numConcurrent := runtime.GOMAXPROCS(-1) * 2
@@ -172,6 +175,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
        // The benchmark stresses concurrent reading and writing to the same connection.
        // Such pattern is used in net/http and net/rpc.
 
+       uninstallTestHooks()
+       defer installTestHooks()
        b.StopTimer()
 
        P := runtime.GOMAXPROCS(0)