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.
4
5// +build !plan9,!windows
6
7package net
8
9import (
10	"context"
11	"internal/testenv"
12	"math/rand"
13	"runtime"
14	"sync"
15	"syscall"
16	"testing"
17	"time"
18)
19
20// See golang.org/issue/14548.
21func TestTCPSpuriousConnSetupCompletion(t *testing.T) {
22	if testing.Short() {
23		t.Skip("skipping in short mode")
24	}
25
26	ln, err := newLocalListener("tcp")
27	if err != nil {
28		t.Fatal(err)
29	}
30	var wg sync.WaitGroup
31	wg.Add(1)
32	go func(ln Listener) {
33		defer wg.Done()
34		for {
35			c, err := ln.Accept()
36			if err != nil {
37				return
38			}
39			wg.Add(1)
40			go func(c Conn) {
41				var b [1]byte
42				c.Read(b[:])
43				c.Close()
44				wg.Done()
45			}(c)
46		}
47	}(ln)
48
49	attempts := int(1e4) // larger is better
50	wg.Add(attempts)
51	throttle := make(chan struct{}, runtime.GOMAXPROCS(-1)*2)
52	for i := 0; i < attempts; i++ {
53		throttle <- struct{}{}
54		go func(i int) {
55			defer func() {
56				<-throttle
57				wg.Done()
58			}()
59			d := Dialer{Timeout: 50 * time.Millisecond}
60			c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
61			if err != nil {
62				if perr := parseDialError(err); perr != nil {
63					t.Errorf("#%d: %v (original error: %v)", i, perr, err)
64				}
65				return
66			}
67			var b [1]byte
68			if _, err := c.Write(b[:]); err != nil {
69				if perr := parseWriteError(err); perr != nil {
70					t.Errorf("#%d: %v", i, err)
71				}
72				if samePlatformError(err, syscall.ENOTCONN) {
73					t.Errorf("#%d: %v", i, err)
74				}
75			}
76			c.Close()
77		}(i)
78	}
79
80	ln.Close()
81	wg.Wait()
82}
83
84// Issue 19289.
85// Test that a canceled Dial does not cause a subsequent Dial to succeed.
86func TestTCPSpuriousConnSetupCompletionWithCancel(t *testing.T) {
87	if testenv.Builder() == "" {
88		testenv.MustHaveExternalNetwork(t)
89	}
90	t.Parallel()
91	const tries = 10000
92	var wg sync.WaitGroup
93	wg.Add(tries * 2)
94	sem := make(chan bool, 5)
95	for i := 0; i < tries; i++ {
96		sem <- true
97		ctx, cancel := context.WithCancel(context.Background())
98		go func() {
99			defer wg.Done()
100			time.Sleep(time.Duration(rand.Int63n(int64(5 * time.Millisecond))))
101			cancel()
102		}()
103		go func(i int) {
104			defer wg.Done()
105			var dialer Dialer
106			// Try to connect to a real host on a port
107			// that it is not listening on.
108			_, err := dialer.DialContext(ctx, "tcp", "golang.org:3")
109			if err == nil {
110				t.Errorf("Dial to unbound port succeeded on attempt %d", i)
111			}
112			<-sem
113		}(i)
114	}
115	wg.Wait()
116}
117