1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
18 isEADDRINUSE
= func(err error
) bool {
19 return errors
.Is(err
, syscall
.EADDRINUSE
)
24 func TestDialContextCancelRace(t
*testing
.T
) {
25 oldConnectFunc
:= connectFunc
26 oldGetsockoptIntFunc
:= getsockoptIntFunc
27 oldTestHookCanceledDial
:= testHookCanceledDial
29 connectFunc
= oldConnectFunc
30 getsockoptIntFunc
= oldGetsockoptIntFunc
31 testHookCanceledDial
= oldTestHookCanceledDial
34 ln
:= newLocalListener(t
, "tcp")
35 listenerDone
:= make(chan struct{})
37 defer close(listenerDone
)
43 defer func() { <-listenerDone
}()
46 sawCancel
:= make(chan bool, 1)
47 testHookCanceledDial
= func() {
51 ctx
, cancelCtx
:= context
.WithCancel(context
.Background())
53 connectFunc
= func(fd
int, addr syscall
.Sockaddr
) error
{
54 err
:= oldConnectFunc(fd
, addr
)
55 t
.Logf("connect(%d, addr) = %v", fd
, err
)
57 // On some operating systems, localhost
58 // connects _sometimes_ succeed immediately.
59 // Prevent that, so we exercise the code path
60 // we're interested in testing. This seems
61 // harmless. It makes FreeBSD 10.10 work when
62 // run with many iterations. It failed about
63 // half the time previously.
64 return syscall
.EINPROGRESS
69 getsockoptIntFunc
= func(fd
, level
, opt
int) (val
int, err error
) {
70 val
, err
= oldGetsockoptIntFunc(fd
, level
, opt
)
71 t
.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd
, level
, opt
, val
, err
)
72 if level
== syscall
.SOL_SOCKET
&& opt
== syscall
.SO_ERROR
&& err
== nil && val
== 0 {
73 t
.Logf("canceling context")
75 // Cancel the context at just the moment which
76 // caused the race in issue 16523.
79 // And wait for the "interrupter" goroutine to
80 // cancel the dial by messing with its write
81 // timeout before returning.
85 case <-time
.After(5 * time
.Second
):
86 t
.Errorf("didn't see cancel after 5 seconds")
93 c
, err
:= d
.DialContext(ctx
, "tcp", ln
.Addr().String())
96 t
.Fatal("unexpected successful dial; want context canceled error")
101 case <-time
.After(5 * time
.Second
):
102 t
.Fatal("expected context to be canceled")
105 oe
, ok
:= err
.(*OpError
)
106 if !ok || oe
.Op
!= "dial" {
107 t
.Fatalf("Dial error = %#v; want dial *OpError", err
)
110 if oe
.Err
!= errCanceled
{
111 t
.Errorf("DialContext = (%v, %v); want OpError with error %v", c
, err
, errCanceled
)