aboutsummaryrefslogtreecommitdiff
path: root/src/net/dial_test.go
diff options
context:
space:
mode:
authorPaul Marks <pmarks@google.com>2016-04-04 14:13:56 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2016-04-05 05:12:22 +0000
commit869e576517f825aecdc8730b0d22f8d6b59bd749 (patch)
tree32f9c972642b9e37c8c78ea04d44cdc746ed2a12 /src/net/dial_test.go
parentbbbd572c10e8e28d343a559b9c0ceef9074c719c (diff)
downloadgo-869e576517f825aecdc8730b0d22f8d6b59bd749.tar.gz
go-869e576517f825aecdc8730b0d22f8d6b59bd749.zip
net: wait for cancelation goroutine before returning from connect.
This fixes a race which made it possible to cancel a connection after returning from net.Dial. Fixes #15035 Fixes #15078 Change-Id: Iec6215009538362f7ad9f408a33549f3e94d1606 Reviewed-on: https://go-review.googlesource.com/21497 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/net/dial_test.go')
-rw-r--r--src/net/dial_test.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 04e0fdae44..2fc75c6356 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "bufio"
"internal/testenv"
"io"
"net/internal/socktest"
@@ -871,3 +872,84 @@ func TestDialCancel(t *testing.T) {
}
}
}
+
+func TestCancelAfterDial(t *testing.T) {
+ if testing.Short() {
+ t.Skip("avoiding time.Sleep")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ defer func() {
+ ln.Close()
+ wg.Wait()
+ }()
+
+ // Echo back the first line of each incoming connection.
+ go func() {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ break
+ }
+ rb := bufio.NewReader(c)
+ line, err := rb.ReadString('\n')
+ if err != nil {
+ t.Error(err)
+ c.Close()
+ continue
+ }
+ if _, err := c.Write([]byte(line)); err != nil {
+ t.Error(err)
+ }
+ c.Close()
+ }
+ wg.Done()
+ }()
+
+ try := func() {
+ cancel := make(chan struct{})
+ d := &Dialer{Cancel: cancel}
+ c, err := d.Dial("tcp", ln.Addr().String())
+
+ // Immediately after dialing, request cancelation and sleep.
+ // Before Issue 15078 was fixed, this would cause subsequent operations
+ // to fail with an i/o timeout roughly 50% of the time.
+ close(cancel)
+ time.Sleep(10 * time.Millisecond)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ // Send some data to confirm that the connection is still alive.
+ const message = "echo!\n"
+ if _, err := c.Write([]byte(message)); err != nil {
+ t.Fatal(err)
+ }
+
+ // The server should echo the line, and close the connection.
+ rb := bufio.NewReader(c)
+ line, err := rb.ReadString('\n')
+ if err != nil {
+ t.Fatal(err)
+ }
+ if line != message {
+ t.Errorf("got %q; want %q", line, message)
+ }
+ if _, err := rb.ReadByte(); err != io.EOF {
+ t.Errorf("got %v; want %v", err, io.EOF)
+ }
+ }
+
+ // This bug manifested about 50% of the time, so try it a few times.
+ for i := 0; i < 10; i++ {
+ try()
+ }
+}