mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
bbbd572c10
commit
869e576517
3 changed files with 93 additions and 3 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue