2009-06-25 21:24:55 -06:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
2021-02-19 16:35:10 -07:00
|
|
|
//go:build !js
|
2018-03-04 04:18:32 -07:00
|
|
|
|
2009-06-25 21:24:55 -06:00
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
2016-10-15 09:56:51 -06:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2011-11-01 20:05:34 -06:00
|
|
|
"io"
|
2016-02-19 01:45:22 -07:00
|
|
|
"net/internal/socktest"
|
2012-05-29 16:08:58 -06:00
|
|
|
"os"
|
2011-10-31 09:47:44 -06:00
|
|
|
"runtime"
|
2009-12-15 16:35:38 -07:00
|
|
|
"testing"
|
2016-01-27 19:05:03 -07:00
|
|
|
"time"
|
2009-06-25 21:24:55 -06:00
|
|
|
)
|
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
func TestCloseRead(t *testing.T) {
|
|
|
|
switch runtime.GOOS {
|
2016-10-15 08:52:57 -06:00
|
|
|
case "plan9":
|
2015-04-29 02:16:21 -06:00
|
|
|
t.Skipf("not supported on %s", runtime.GOOS)
|
2011-10-31 09:47:44 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
2015-04-29 02:16:21 -06:00
|
|
|
|
|
|
|
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
2011-09-28 09:12:38 -06:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(ln.Addr().String())
|
|
|
|
}
|
|
|
|
defer ln.Close()
|
2011-09-28 09:12:38 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
c, err := Dial(ln.Addr().Network(), ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(c.LocalAddr().String())
|
|
|
|
}
|
|
|
|
defer c.Close()
|
2011-09-28 09:12:38 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
switch c := c.(type) {
|
|
|
|
case *TCPConn:
|
|
|
|
err = c.CloseRead()
|
|
|
|
case *UnixConn:
|
|
|
|
err = c.CloseRead()
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
if err != nil {
|
|
|
|
if perr := parseCloseError(err, true); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
var b [1]byte
|
|
|
|
n, err := c.Read(b[:])
|
|
|
|
if n != 0 || err == nil {
|
|
|
|
t.Fatalf("got (%d, %v); want (0, error)", n, err)
|
|
|
|
}
|
|
|
|
})
|
2011-09-28 09:12:38 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
func TestCloseWrite(t *testing.T) {
|
|
|
|
switch runtime.GOOS {
|
2019-10-08 13:19:13 -06:00
|
|
|
case "plan9":
|
2015-04-29 02:16:21 -06:00
|
|
|
t.Skipf("not supported on %s", runtime.GOOS)
|
2012-05-29 16:08:58 -06:00
|
|
|
}
|
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
|
|
|
deadline, _ := t.Deadline()
|
|
|
|
if !deadline.IsZero() {
|
|
|
|
// Leave 10% headroom on the deadline to report errors and clean up.
|
|
|
|
deadline = deadline.Add(-time.Until(deadline) / 10)
|
2012-05-29 16:08:58 -06:00
|
|
|
}
|
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
handler := func(ls *localServer, ln Listener) {
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !deadline.IsZero() {
|
|
|
|
c.SetDeadline(deadline)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
var b [1]byte
|
|
|
|
n, err := c.Read(b[:])
|
|
|
|
if n != 0 || err != io.EOF {
|
|
|
|
t.Errorf("got (%d, %v); want (0, io.EOF)", n, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch c := c.(type) {
|
|
|
|
case *TCPConn:
|
|
|
|
err = c.CloseWrite()
|
|
|
|
case *UnixConn:
|
|
|
|
err = c.CloseWrite()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseCloseError(err, true); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n, err = c.Write(b[:])
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("got (%d, %v); want (any, error)", n, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2012-05-29 16:08:58 -06:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
ls := newLocalServer(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
defer ls.teardown()
|
|
|
|
if err := ls.buildup(handler); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !deadline.IsZero() {
|
|
|
|
c.SetDeadline(deadline)
|
|
|
|
}
|
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(c.LocalAddr().String())
|
|
|
|
}
|
|
|
|
defer c.Close()
|
2015-04-29 02:16:21 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
switch c := c.(type) {
|
|
|
|
case *TCPConn:
|
|
|
|
err = c.CloseWrite()
|
|
|
|
case *UnixConn:
|
|
|
|
err = c.CloseWrite()
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
if err != nil {
|
|
|
|
if perr := parseCloseError(err, true); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
var b [1]byte
|
|
|
|
n, err := c.Read(b[:])
|
|
|
|
if n != 0 || err != io.EOF {
|
|
|
|
t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err)
|
|
|
|
}
|
|
|
|
n, err = c.Write(b[:])
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("got (%d, %v); want (any, error)", n, err)
|
|
|
|
}
|
|
|
|
})
|
2012-02-13 22:40:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
func TestConnClose(t *testing.T) {
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
2015-04-29 02:16:21 -06:00
|
|
|
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
2012-02-13 22:40:37 -07:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(ln.Addr().String())
|
|
|
|
}
|
|
|
|
defer ln.Close()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
c, err := Dial(ln.Addr().Network(), ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(c.LocalAddr().String())
|
|
|
|
}
|
|
|
|
defer c.Close()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
if err := c.Close(); err != nil {
|
|
|
|
if perr := parseCloseError(err, false); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Fatal(err)
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
var b [1]byte
|
|
|
|
n, err := c.Read(b[:])
|
|
|
|
if n != 0 || err == nil {
|
|
|
|
t.Fatalf("got (%d, %v); want (0, error)", n, err)
|
|
|
|
}
|
|
|
|
})
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
}
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
func TestListenerClose(t *testing.T) {
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
2015-04-29 02:16:21 -06:00
|
|
|
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
defer os.Remove(ln.Addr().String())
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
2015-10-15 22:41:34 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
if err := ln.Close(); err != nil {
|
|
|
|
if perr := parseCloseError(err, false); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
c, err := ln.Accept()
|
2015-10-15 22:41:34 -06:00
|
|
|
if err == nil {
|
2020-04-08 10:51:50 -06:00
|
|
|
c.Close()
|
|
|
|
t.Fatal("should fail")
|
2015-10-15 22:41:34 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
|
2021-12-09 15:00:51 -07:00
|
|
|
// Note: we cannot ensure that a subsequent Dial does not succeed, because
|
|
|
|
// we do not in general have any guarantee that ln.Addr is not immediately
|
|
|
|
// reused. (TCP sockets enter a TIME_WAIT state when closed, but that only
|
|
|
|
// applies to existing connections for the port — it does not prevent the
|
|
|
|
// port itself from being used for entirely new connections in the
|
|
|
|
// meantime.)
|
2020-04-08 10:51:50 -06:00
|
|
|
})
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2015-04-29 02:16:21 -06:00
|
|
|
func TestPacketConnClose(t *testing.T) {
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
2015-04-29 02:16:21 -06:00
|
|
|
for _, network := range []string{"udp", "unixgram"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
c := newLocalPacketListener(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
switch network {
|
|
|
|
case "unixgram":
|
|
|
|
defer os.Remove(c.LocalAddr().String())
|
|
|
|
}
|
|
|
|
defer c.Close()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
if err := c.Close(); err != nil {
|
|
|
|
if perr := parseCloseError(err, false); perr != nil {
|
|
|
|
t.Error(perr)
|
|
|
|
}
|
|
|
|
t.Fatal(err)
|
2015-04-29 02:16:21 -06:00
|
|
|
}
|
2020-04-08 10:51:50 -06:00
|
|
|
var b [1]byte
|
|
|
|
n, _, err := c.ReadFrom(b[:])
|
|
|
|
if n != 0 || err == nil {
|
|
|
|
t.Fatalf("got (%d, %v); want (0, error)", n, err)
|
|
|
|
}
|
|
|
|
})
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
}
|
|
|
|
}
|
2015-11-04 00:17:57 -07:00
|
|
|
|
|
|
|
func TestListenCloseListen(t *testing.T) {
|
|
|
|
const maxTries = 10
|
|
|
|
for tries := 0; tries < maxTries; tries++ {
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, "tcp")
|
2015-11-04 00:17:57 -07:00
|
|
|
addr := ln.Addr().String()
|
2021-12-09 09:42:42 -07:00
|
|
|
// TODO: This is racy. The selected address could be reused in between this
|
|
|
|
// Close and the subsequent Listen.
|
2015-11-04 00:17:57 -07:00
|
|
|
if err := ln.Close(); err != nil {
|
2017-04-07 16:53:19 -06:00
|
|
|
if perr := parseCloseError(err, false); perr != nil {
|
2016-01-27 19:05:03 -07:00
|
|
|
t.Error(perr)
|
|
|
|
}
|
2015-11-04 00:17:57 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2021-12-09 09:42:42 -07:00
|
|
|
ln, err := Listen("tcp", addr)
|
2015-11-04 00:17:57 -07:00
|
|
|
if err == nil {
|
2019-10-08 13:19:13 -06:00
|
|
|
// Success. (This test didn't always make it here earlier.)
|
2015-11-04 00:17:57 -07:00
|
|
|
ln.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
t.Errorf("failed on try %d/%d: %v", tries+1, maxTries, err)
|
|
|
|
}
|
2015-11-18 12:10:59 -07:00
|
|
|
t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
|
2015-11-04 00:17:57 -07:00
|
|
|
}
|
2016-02-19 01:45:22 -07:00
|
|
|
|
|
|
|
// See golang.org/issue/6163, golang.org/issue/6987.
|
|
|
|
func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "plan9":
|
|
|
|
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
|
|
|
|
}
|
|
|
|
|
|
|
|
syserr := make(chan error)
|
|
|
|
go func() {
|
|
|
|
defer close(syserr)
|
|
|
|
for _, err := range abortedConnRequestErrors {
|
|
|
|
syserr <- err
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) {
|
|
|
|
if err, ok := <-syserr; ok {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
})
|
|
|
|
defer sw.Set(socktest.FilterAccept, nil)
|
|
|
|
|
|
|
|
operr := make(chan error, 1)
|
|
|
|
handler := func(ls *localServer, ln Listener) {
|
|
|
|
defer close(operr)
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseAcceptError(err); perr != nil {
|
|
|
|
operr <- perr
|
|
|
|
}
|
|
|
|
operr <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Close()
|
|
|
|
}
|
2021-12-09 09:42:42 -07:00
|
|
|
ls := newLocalServer(t, "tcp")
|
2016-02-19 01:45:22 -07:00
|
|
|
defer ls.teardown()
|
|
|
|
if err := ls.buildup(handler); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
c.Close()
|
|
|
|
|
|
|
|
for err := range operr {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
}
|
2016-05-18 15:54:12 -06:00
|
|
|
|
|
|
|
func TestZeroByteRead(t *testing.T) {
|
2020-04-08 10:51:50 -06:00
|
|
|
t.Parallel()
|
2016-05-18 15:54:12 -06:00
|
|
|
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
2020-04-08 10:51:50 -06:00
|
|
|
network := network
|
|
|
|
t.Run(network, func(t *testing.T) {
|
|
|
|
if !testableNetwork(network) {
|
|
|
|
t.Skipf("network %s is not testable on the current platform", network)
|
|
|
|
}
|
|
|
|
t.Parallel()
|
2016-05-18 15:54:12 -06:00
|
|
|
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, network)
|
2020-04-08 10:51:50 -06:00
|
|
|
connc := make(chan Conn, 1)
|
|
|
|
go func() {
|
|
|
|
defer ln.Close()
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
connc <- c // might be nil
|
|
|
|
}()
|
|
|
|
c, err := Dial(network, ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
sc := <-connc
|
|
|
|
if sc == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer sc.Close()
|
2016-05-18 15:54:12 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
// A zero byte read on Windows caused a wait for readability first.
|
|
|
|
// Rather than change that behavior, satisfy it in this test.
|
|
|
|
// See Issue 15735.
|
|
|
|
go io.WriteString(sc, "a")
|
|
|
|
}
|
2016-05-18 15:54:12 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
n, err := c.Read(nil)
|
|
|
|
if n != 0 || err != nil {
|
|
|
|
t.Errorf("%s: zero byte client read = %v, %v; want 0, nil", network, n, err)
|
|
|
|
}
|
2016-05-18 15:54:12 -06:00
|
|
|
|
2020-04-08 10:51:50 -06:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
// Same as comment above.
|
|
|
|
go io.WriteString(c, "a")
|
|
|
|
}
|
|
|
|
n, err = sc.Read(nil)
|
|
|
|
if n != 0 || err != nil {
|
|
|
|
t.Errorf("%s: zero byte server read = %v, %v; want 0, nil", network, n, err)
|
|
|
|
}
|
|
|
|
})
|
2016-05-18 15:54:12 -06:00
|
|
|
}
|
|
|
|
}
|
2016-09-27 14:50:57 -06:00
|
|
|
|
|
|
|
// withTCPConnPair sets up a TCP connection between two peers, then
|
|
|
|
// runs peer1 and peer2 concurrently. withTCPConnPair returns when
|
|
|
|
// both have completed.
|
|
|
|
func withTCPConnPair(t *testing.T, peer1, peer2 func(c *TCPConn) error) {
|
2021-12-09 09:42:42 -07:00
|
|
|
ln := newLocalListener(t, "tcp")
|
2016-09-27 14:50:57 -06:00
|
|
|
defer ln.Close()
|
|
|
|
errc := make(chan error, 2)
|
|
|
|
go func() {
|
|
|
|
c1, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
errc <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer c1.Close()
|
|
|
|
errc <- peer1(c1.(*TCPConn))
|
|
|
|
}()
|
|
|
|
go func() {
|
|
|
|
c2, err := Dial("tcp", ln.Addr().String())
|
|
|
|
if err != nil {
|
|
|
|
errc <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer c2.Close()
|
|
|
|
errc <- peer2(c2.(*TCPConn))
|
|
|
|
}()
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
if err := <-errc; err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-15 09:56:51 -06:00
|
|
|
|
|
|
|
// Tests that a blocked Read is interrupted by a concurrent SetReadDeadline
|
|
|
|
// modifying that Conn's read deadline to the past.
|
|
|
|
// See golang.org/cl/30164 which documented this. The net/http package
|
|
|
|
// depends on this.
|
|
|
|
func TestReadTimeoutUnblocksRead(t *testing.T) {
|
|
|
|
serverDone := make(chan struct{})
|
|
|
|
server := func(cs *TCPConn) error {
|
|
|
|
defer close(serverDone)
|
|
|
|
errc := make(chan error, 1)
|
|
|
|
go func() {
|
|
|
|
defer close(errc)
|
|
|
|
go func() {
|
|
|
|
// TODO: find a better way to wait
|
|
|
|
// until we're blocked in the cs.Read
|
|
|
|
// call below. Sleep is lame.
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
// Interrupt the upcoming Read, unblocking it:
|
|
|
|
cs.SetReadDeadline(time.Unix(123, 0)) // time in the past
|
|
|
|
}()
|
|
|
|
var buf [1]byte
|
|
|
|
n, err := cs.Read(buf[:1])
|
|
|
|
if n != 0 || err == nil {
|
|
|
|
errc <- fmt.Errorf("Read = %v, %v; want 0, non-nil", n, err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case err := <-errc:
|
|
|
|
return err
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
buf := make([]byte, 2<<20)
|
|
|
|
buf = buf[:runtime.Stack(buf, true)]
|
|
|
|
println("Stacks at timeout:\n", string(buf))
|
|
|
|
return errors.New("timeout waiting for Read to finish")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// Do nothing in the client. Never write. Just wait for the
|
|
|
|
// server's half to be done.
|
|
|
|
client := func(*TCPConn) error {
|
|
|
|
<-serverDone
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
withTCPConnPair(t, client, server)
|
|
|
|
}
|
2016-11-14 20:31:47 -07:00
|
|
|
|
|
|
|
// Issue 17695: verify that a blocked Read is woken up by a Close.
|
|
|
|
func TestCloseUnblocksRead(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
server := func(cs *TCPConn) error {
|
|
|
|
// Give the client time to get stuck in a Read:
|
|
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
cs.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
client := func(ss *TCPConn) error {
|
|
|
|
n, err := ss.Read([]byte{0})
|
|
|
|
if n != 0 || err != io.EOF {
|
|
|
|
return fmt.Errorf("Read = %v, %v; want 0, EOF", n, err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
withTCPConnPair(t, client, server)
|
|
|
|
}
|
2018-04-30 21:23:37 -06:00
|
|
|
|
|
|
|
// Issue 24808: verify that ECONNRESET is not temporary for read.
|
|
|
|
func TestNotTemporaryRead(t *testing.T) {
|
|
|
|
t.Parallel()
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
|
|
|
|
ln := newLocalListener(t, "tcp")
|
|
|
|
serverDone := make(chan struct{})
|
|
|
|
dialed := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
defer close(serverDone)
|
|
|
|
|
|
|
|
cs, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
<-dialed
|
|
|
|
cs.(*TCPConn).SetLinger(0)
|
2018-04-30 21:23:37 -06:00
|
|
|
cs.Close()
|
2022-04-22 08:39:04 -06:00
|
|
|
}()
|
|
|
|
defer func() {
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
ln.Close()
|
2022-04-22 08:39:04 -06:00
|
|
|
<-serverDone
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
}()
|
|
|
|
|
|
|
|
ss, err := Dial("tcp", ln.Addr().String())
|
2022-04-22 08:39:04 -06:00
|
|
|
close(dialed)
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2018-04-30 21:23:37 -06:00
|
|
|
}
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
defer ss.Close()
|
2022-04-22 08:39:04 -06:00
|
|
|
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
_, err = ss.Read([]byte{0})
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Read succeeded unexpectedly")
|
|
|
|
} else if err == io.EOF {
|
|
|
|
// This happens on Plan 9, but for some reason (prior to CL 385314) it was
|
|
|
|
// accepted everywhere else too.
|
|
|
|
if runtime.GOOS == "plan9" {
|
|
|
|
return
|
2018-04-30 21:23:37 -06:00
|
|
|
}
|
2022-02-14 14:07:05 -07:00
|
|
|
t.Fatal("Read unexpectedly returned io.EOF after socket was abruptly closed")
|
net: in TestNotTemporaryRead, do not assume that a dialed connection has been accepted
Previously, TestNotTemporaryRead issued the Read on the Accept side of
the connection, and Closed the Dial side. It appears that on some
platforms, Dial may return before the connection has been Accepted,
and if that connection is immediately closed with no bytes written and
SO_LINGER set to 0, the connection may no longer even exist by the
time Accept returns, causing Accept to block indefinitely until the
Listener is closed.
If we were to just swap the directions, we would have an analogous
problem: Accept could accept the connection and close it before the
client even finishes dialing, causing Dial (instead of Read) to return
the ECONNRESET error.
Here, we take a middle path: we Accept and Dial the connection
concurrently, but wait until both the Accept and the Dial have
returned (indicating that the connection is completely established and
won't vanish from the accept queue) before resetting the connection.
Fixes #29685
Updates #25289
Change-Id: Ida06f70f7205fffcdafa3df78bd56184e6cec760
Reviewed-on: https://go-review.googlesource.com/c/go/+/385314
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-02-11 14:49:51 -07:00
|
|
|
}
|
|
|
|
if ne, ok := err.(Error); !ok {
|
|
|
|
t.Errorf("Read error does not implement net.Error: %v", err)
|
|
|
|
} else if ne.Temporary() {
|
|
|
|
t.Errorf("Read error is unexpectedly temporary: %v", err)
|
2018-04-30 21:23:37 -06:00
|
|
|
}
|
|
|
|
}
|
2021-04-02 15:36:36 -06:00
|
|
|
|
|
|
|
// The various errors should implement the Error interface.
|
|
|
|
func TestErrors(t *testing.T) {
|
|
|
|
var (
|
|
|
|
_ Error = &OpError{}
|
|
|
|
_ Error = &ParseError{}
|
|
|
|
_ Error = &AddrError{}
|
|
|
|
_ Error = UnknownNetworkError("")
|
|
|
|
_ Error = InvalidAddrError("")
|
|
|
|
_ Error = &timeoutError{}
|
|
|
|
_ Error = &DNSConfigError{}
|
|
|
|
_ Error = &DNSError{}
|
|
|
|
)
|
|
|
|
|
|
|
|
// ErrClosed was introduced as type error, so we can't check
|
|
|
|
// it using a declaration.
|
|
|
|
if _, ok := ErrClosed.(Error); !ok {
|
|
|
|
t.Fatal("ErrClosed does not implement Error")
|
|
|
|
}
|
|
|
|
}
|