blob: d80a3736bfb437f0cd62cd893386f3be2b0a8d68 [file] [log] [blame]
Dmitriy Vyukov922056d2012-08-20 21:27:52 +04001// Copyright 2012 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
5package net
6
7import (
Mikio Haraed7cd252016-04-14 12:17:44 +09008 "internal/testenv"
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +04009 "io"
Mikio Hara4f74bbd2012-11-28 06:36:05 +090010 "reflect"
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040011 "runtime"
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +040012 "sync"
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040013 "testing"
14 "time"
15)
16
Mikio Hara13393fb2013-03-03 11:25:49 +090017func BenchmarkTCP4OneShot(b *testing.B) {
18 benchmarkTCP(b, false, false, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040019}
20
Mikio Hara13393fb2013-03-03 11:25:49 +090021func BenchmarkTCP4OneShotTimeout(b *testing.B) {
22 benchmarkTCP(b, false, true, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040023}
24
Mikio Hara13393fb2013-03-03 11:25:49 +090025func BenchmarkTCP4Persistent(b *testing.B) {
26 benchmarkTCP(b, true, false, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040027}
28
Mikio Hara13393fb2013-03-03 11:25:49 +090029func BenchmarkTCP4PersistentTimeout(b *testing.B) {
30 benchmarkTCP(b, true, true, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040031}
32
Mikio Hara13393fb2013-03-03 11:25:49 +090033func BenchmarkTCP6OneShot(b *testing.B) {
34 if !supportsIPv6 {
35 b.Skip("ipv6 is not supported")
36 }
37 benchmarkTCP(b, false, false, "[::1]:0")
38}
39
40func BenchmarkTCP6OneShotTimeout(b *testing.B) {
41 if !supportsIPv6 {
42 b.Skip("ipv6 is not supported")
43 }
44 benchmarkTCP(b, false, true, "[::1]:0")
45}
46
47func BenchmarkTCP6Persistent(b *testing.B) {
48 if !supportsIPv6 {
49 b.Skip("ipv6 is not supported")
50 }
51 benchmarkTCP(b, true, false, "[::1]:0")
52}
53
54func BenchmarkTCP6PersistentTimeout(b *testing.B) {
55 if !supportsIPv6 {
56 b.Skip("ipv6 is not supported")
57 }
58 benchmarkTCP(b, true, true, "[::1]:0")
59}
60
61func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
Mikio Haraef549302015-05-14 09:25:24 +090062 testHookUninstaller.Do(uninstallTestHooks)
Mikio Hara29d1f3b2015-03-01 12:27:01 +090063
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040064 const msgLen = 512
65 conns := b.N
Dmitriy Vyukov905f2962013-08-06 21:29:35 +040066 numConcurrent := runtime.GOMAXPROCS(-1) * 2
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040067 msgs := 1
68 if persistent {
69 conns = numConcurrent
70 msgs = b.N / conns
71 if msgs == 0 {
72 msgs = 1
73 }
74 if conns > b.N {
75 conns = b.N
76 }
77 }
78 sendMsg := func(c Conn, buf []byte) bool {
79 n, err := c.Write(buf)
80 if n != len(buf) || err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +090081 b.Log(err)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040082 return false
83 }
84 return true
85 }
86 recvMsg := func(c Conn, buf []byte) bool {
87 for read := 0; read != len(buf); {
88 n, err := c.Read(buf)
89 read += n
90 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +090091 b.Log(err)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040092 return false
93 }
94 }
95 return true
96 }
Mikio Hara13393fb2013-03-03 11:25:49 +090097 ln, err := Listen("tcp", laddr)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040098 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +090099 b.Fatal(err)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400100 }
101 defer ln.Close()
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400102 serverSem := make(chan bool, numConcurrent)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400103 // Acceptor.
104 go func() {
105 for {
106 c, err := ln.Accept()
107 if err != nil {
108 break
109 }
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400110 serverSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400111 // Server connection.
112 go func(c Conn) {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400113 defer func() {
114 c.Close()
115 <-serverSem
116 }()
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400117 if timeout {
118 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
119 }
120 var buf [msgLen]byte
121 for m := 0; m < msgs; m++ {
122 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
123 break
124 }
125 }
126 }(c)
127 }
128 }()
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400129 clientSem := make(chan bool, numConcurrent)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400130 for i := 0; i < conns; i++ {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400131 clientSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400132 // Client connection.
133 go func() {
134 defer func() {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400135 <-clientSem
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400136 }()
137 c, err := Dial("tcp", ln.Addr().String())
138 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900139 b.Log(err)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400140 return
141 }
142 defer c.Close()
143 if timeout {
144 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
145 }
146 var buf [msgLen]byte
147 for m := 0; m < msgs; m++ {
148 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
149 break
150 }
151 }
152 }()
153 }
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400154 for i := 0; i < numConcurrent; i++ {
155 clientSem <- true
156 serverSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400157 }
158}
Mikio Hara677c6e62012-11-13 12:56:28 +0900159
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400160func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
161 benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
162}
163
164func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
165 if !supportsIPv6 {
166 b.Skip("ipv6 is not supported")
167 }
168 benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
169}
170
171func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
Mikio Haraef549302015-05-14 09:25:24 +0900172 testHookUninstaller.Do(uninstallTestHooks)
Mikio Hara93553dd2015-04-01 12:21:15 +0900173
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400174 // The benchmark creates GOMAXPROCS client/server pairs.
175 // Each pair creates 4 goroutines: client reader/writer and server reader/writer.
176 // The benchmark stresses concurrent reading and writing to the same connection.
177 // Such pattern is used in net/http and net/rpc.
178
179 b.StopTimer()
180
181 P := runtime.GOMAXPROCS(0)
182 N := b.N / P
183 W := 1000
184
185 // Setup P client/server connections.
186 clients := make([]Conn, P)
187 servers := make([]Conn, P)
188 ln, err := Listen("tcp", laddr)
189 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900190 b.Fatal(err)
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400191 }
192 defer ln.Close()
193 done := make(chan bool)
194 go func() {
195 for p := 0; p < P; p++ {
196 s, err := ln.Accept()
197 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900198 b.Error(err)
Mikio Haraf0433e42014-03-15 13:43:02 +0900199 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400200 }
201 servers[p] = s
202 }
203 done <- true
204 }()
205 for p := 0; p < P; p++ {
206 c, err := Dial("tcp", ln.Addr().String())
207 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900208 b.Fatal(err)
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400209 }
210 clients[p] = c
211 }
212 <-done
213
214 b.StartTimer()
215
216 var wg sync.WaitGroup
217 wg.Add(4 * P)
218 for p := 0; p < P; p++ {
219 // Client writer.
220 go func(c Conn) {
221 defer wg.Done()
222 var buf [1]byte
223 for i := 0; i < N; i++ {
224 v := byte(i)
225 for w := 0; w < W; w++ {
226 v *= v
227 }
228 buf[0] = v
229 _, err := c.Write(buf[:])
230 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900231 b.Error(err)
Mikio Haraf0433e42014-03-15 13:43:02 +0900232 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400233 }
234 }
235 }(clients[p])
236
237 // Pipe between server reader and server writer.
238 pipe := make(chan byte, 128)
239
240 // Server reader.
241 go func(s Conn) {
242 defer wg.Done()
243 var buf [1]byte
244 for i := 0; i < N; i++ {
245 _, err := s.Read(buf[:])
246 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900247 b.Error(err)
Mikio Haraf0433e42014-03-15 13:43:02 +0900248 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400249 }
250 pipe <- buf[0]
251 }
252 }(servers[p])
253
254 // Server writer.
255 go func(s Conn) {
256 defer wg.Done()
257 var buf [1]byte
258 for i := 0; i < N; i++ {
259 v := <-pipe
260 for w := 0; w < W; w++ {
261 v *= v
262 }
263 buf[0] = v
264 _, err := s.Write(buf[:])
265 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900266 b.Error(err)
Mikio Haraf0433e42014-03-15 13:43:02 +0900267 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400268 }
269 }
270 s.Close()
271 }(servers[p])
272
273 // Client reader.
274 go func(c Conn) {
275 defer wg.Done()
276 var buf [1]byte
277 for i := 0; i < N; i++ {
278 _, err := c.Read(buf[:])
279 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900280 b.Error(err)
Mikio Haraf0433e42014-03-15 13:43:02 +0900281 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400282 }
283 }
284 c.Close()
285 }(clients[p])
286 }
287 wg.Wait()
288}
289
Mikio Hara9d97b552013-03-27 01:06:48 +0900290type resolveTCPAddrTest struct {
Mikio Hara5a83f062015-04-05 17:00:14 +0900291 network string
Mikio Hara7c59c8b2013-08-31 10:28:49 +0900292 litAddrOrName string
293 addr *TCPAddr
294 err error
Mikio Hara9d97b552013-03-27 01:06:48 +0900295}
296
297var resolveTCPAddrTests = []resolveTCPAddrTest{
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900298 {"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
299 {"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
300
Mikio Hara5a83f062015-04-05 17:00:14 +0900301 {"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
302 {"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900303
Mikio Haraaa0dda72013-03-23 09:57:40 +0900304 {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
305 {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
Mikio Haraaa0dda72013-03-23 09:57:40 +0900306
Mikio Harae3e885b2012-12-01 14:49:54 +0900307 {"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
308 {"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
309
Russ Coxe8bbbe02013-09-23 22:40:24 -0400310 {"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
311
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900312 {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
313}
314
315func TestResolveTCPAddr(t *testing.T) {
Mikio Hara5a83f062015-04-05 17:00:14 +0900316 origTestHookLookupIP := testHookLookupIP
317 defer func() { testHookLookupIP = origTestHookLookupIP }()
318 testHookLookupIP = lookupLocalhost
319
320 for i, tt := range resolveTCPAddrTests {
321 addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900322 if err != tt.err {
Mikio Hara5a83f062015-04-05 17:00:14 +0900323 t.Errorf("#%d: %v", i, err)
324 } else if !reflect.DeepEqual(addr, tt.addr) {
325 t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900326 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900327 if err != nil {
328 continue
Russ Coxe8bbbe02013-09-23 22:40:24 -0400329 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900330 rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
331 if err != nil {
332 t.Errorf("#%d: %v", i, err)
333 } else if !reflect.DeepEqual(rtaddr, addr) {
334 t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900335 }
336 }
337}
338
Mikio Hara677c6e62012-11-13 12:56:28 +0900339var tcpListenerNameTests = []struct {
340 net string
341 laddr *TCPAddr
342}{
343 {"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
344 {"tcp4", &TCPAddr{}},
345 {"tcp4", nil},
346}
347
348func TestTCPListenerName(t *testing.T) {
Mikio Haraed7cd252016-04-14 12:17:44 +0900349 testenv.MustHaveExternalNetwork(t)
Mikio Hara677c6e62012-11-13 12:56:28 +0900350
351 for _, tt := range tcpListenerNameTests {
352 ln, err := ListenTCP(tt.net, tt.laddr)
353 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900354 t.Fatal(err)
Mikio Hara677c6e62012-11-13 12:56:28 +0900355 }
356 defer ln.Close()
357 la := ln.Addr()
358 if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
Mikio Harabfb32dc2013-03-23 22:32:19 +0900359 t.Fatalf("got %v; expected a proper address with non-zero port number", la)
Mikio Hara677c6e62012-11-13 12:56:28 +0900360 }
361 }
362}
Mikio Haraaa0dda72013-03-23 09:57:40 +0900363
364func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
Mikio Haraed7cd252016-04-14 12:17:44 +0900365 testenv.MustHaveExternalNetwork(t)
366
Mikio Haraaa0dda72013-03-23 09:57:40 +0900367 if !supportsIPv6 {
Mikio Haraeeb64b72015-05-14 10:18:10 +0900368 t.Skip("IPv6 is not supported")
Mikio Haraaa0dda72013-03-23 09:57:40 +0900369 }
370
Mikio Haraeeb64b72015-05-14 10:18:10 +0900371 for i, tt := range ipv6LinkLocalUnicastTCPTests {
372 ln, err := Listen(tt.network, tt.address)
Mikio Haraaa0dda72013-03-23 09:57:40 +0900373 if err != nil {
374 // It might return "LookupHost returned no
375 // suitable address" error on some platforms.
Mikio Haraf77e10f2015-05-01 12:38:42 +0900376 t.Log(err)
Mikio Haraaa0dda72013-03-23 09:57:40 +0900377 continue
378 }
Mikio Haraf0775052015-04-02 23:11:39 +0900379 ls, err := (&streamListener{Listener: ln}).newLocalServer()
380 if err != nil {
381 t.Fatal(err)
382 }
383 defer ls.teardown()
Mikio Hara832c5732015-04-19 23:42:11 +0900384 ch := make(chan error, 1)
385 handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
Mikio Haraf0775052015-04-02 23:11:39 +0900386 if err := ls.buildup(handler); err != nil {
387 t.Fatal(err)
388 }
Mikio Haraaa0dda72013-03-23 09:57:40 +0900389 if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
390 t.Fatalf("got %v; expected a proper address with zone identifier", la)
391 }
392
Mikio Haraeeb64b72015-05-14 10:18:10 +0900393 c, err := Dial(tt.network, ls.Listener.Addr().String())
Mikio Haraaa0dda72013-03-23 09:57:40 +0900394 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900395 t.Fatal(err)
Mikio Haraaa0dda72013-03-23 09:57:40 +0900396 }
397 defer c.Close()
398 if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
399 t.Fatalf("got %v; expected a proper address with zone identifier", la)
400 }
401 if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
402 t.Fatalf("got %v; expected a proper address with zone identifier", ra)
403 }
404
405 if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900406 t.Fatal(err)
Mikio Haraaa0dda72013-03-23 09:57:40 +0900407 }
408 b := make([]byte, 32)
409 if _, err := c.Read(b); err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900410 t.Fatal(err)
Mikio Haraaa0dda72013-03-23 09:57:40 +0900411 }
Mikio Hara832c5732015-04-19 23:42:11 +0900412
413 for err := range ch {
414 t.Errorf("#%d: %v", i, err)
415 }
Mikio Haraaa0dda72013-03-23 09:57:40 +0900416 }
417}
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400418
419func TestTCPConcurrentAccept(t *testing.T) {
420 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
421 ln, err := Listen("tcp", "127.0.0.1:0")
422 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900423 t.Fatal(err)
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400424 }
425 const N = 10
426 var wg sync.WaitGroup
427 wg.Add(N)
428 for i := 0; i < N; i++ {
429 go func() {
430 for {
431 c, err := ln.Accept()
432 if err != nil {
433 break
434 }
435 c.Close()
436 }
437 wg.Done()
438 }()
439 }
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900440 attempts := 10 * N
441 fails := 0
442 d := &Dialer{Timeout: 200 * time.Millisecond}
443 for i := 0; i < attempts; i++ {
444 c, err := d.Dial("tcp", ln.Addr().String())
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400445 if err != nil {
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900446 fails++
447 } else {
448 c.Close()
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400449 }
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400450 }
451 ln.Close()
452 wg.Wait()
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900453 if fails > attempts/9 { // see issues 7400 and 7541
454 t.Fatalf("too many Dial failed: %v", fails)
455 }
456 if fails > 0 {
457 t.Logf("# of failed Dials: %v", fails)
458 }
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400459}
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400460
Mikio Hara3dd029a2015-02-24 14:13:47 +0900461func TestTCPReadWriteAllocs(t *testing.T) {
462 switch runtime.GOOS {
Alex Brainmanfca3dd32016-09-10 14:04:46 +1000463 case "nacl":
Mikio Hara3dd029a2015-02-24 14:13:47 +0900464 // NaCl needs to allocate pseudo file descriptor
465 // stuff. See syscall/fd_nacl.go.
Mikio Hara3dd029a2015-02-24 14:13:47 +0900466 t.Skipf("not supported on %s", runtime.GOOS)
Rob Pikef5787262013-08-21 14:00:45 +1000467 }
Mikio Hara3dd029a2015-02-24 14:13:47 +0900468
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400469 ln, err := Listen("tcp", "127.0.0.1:0")
470 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900471 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400472 }
473 defer ln.Close()
474 var server Conn
Alex Brainmanfca3dd32016-09-10 14:04:46 +1000475 errc := make(chan error, 1)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400476 go func() {
477 var err error
478 server, err = ln.Accept()
479 errc <- err
480 }()
481 client, err := Dial("tcp", ln.Addr().String())
482 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900483 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400484 }
Mikio Hara3dd029a2015-02-24 14:13:47 +0900485 defer client.Close()
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400486 if err := <-errc; err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900487 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400488 }
489 defer server.Close()
Alex Brainmanfca3dd32016-09-10 14:04:46 +1000490
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400491 var buf [128]byte
Mikio Hara3dd029a2015-02-24 14:13:47 +0900492 allocs := testing.AllocsPerRun(1000, func() {
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400493 _, err := server.Write(buf[:])
494 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900495 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400496 }
497 _, err = io.ReadFull(client, buf[:])
498 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900499 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400500 }
501 })
Mikio Hara3dd029a2015-02-24 14:13:47 +0900502 if allocs > 0 {
503 t.Fatalf("got %v; want 0", allocs)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400504 }
Alex Brainmanfca3dd32016-09-10 14:04:46 +1000505
506 var bufwrt [128]byte
507 ch := make(chan bool)
508 defer close(ch)
509 go func() {
510 for <-ch {
511 _, err := server.Write(bufwrt[:])
512 errc <- err
513 }
514 }()
515 allocs = testing.AllocsPerRun(1000, func() {
516 ch <- true
517 if _, err = io.ReadFull(client, buf[:]); err != nil {
518 t.Fatal(err)
519 }
520 if err := <-errc; err != nil {
521 t.Fatal(err)
522 }
523 })
524 if allocs > 0 {
525 t.Fatalf("got %v; want 0", allocs)
526 }
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400527}
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400528
529func TestTCPStress(t *testing.T) {
530 const conns = 2
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400531 const msgLen = 512
Dmitriy Vyukovf8ca13c2013-08-14 21:53:27 +0400532 msgs := int(1e4)
533 if testing.Short() {
534 msgs = 1e2
535 }
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400536
537 sendMsg := func(c Conn, buf []byte) bool {
538 n, err := c.Write(buf)
539 if n != len(buf) || err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900540 t.Log(err)
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400541 return false
542 }
543 return true
544 }
545 recvMsg := func(c Conn, buf []byte) bool {
546 for read := 0; read != len(buf); {
547 n, err := c.Read(buf)
548 read += n
549 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900550 t.Log(err)
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400551 return false
552 }
553 }
554 return true
555 }
556
557 ln, err := Listen("tcp", "127.0.0.1:0")
558 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900559 t.Fatal(err)
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400560 }
Mikio Hara11ac72a2015-12-22 09:35:27 +0900561 done := make(chan bool)
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400562 // Acceptor.
563 go func() {
Mikio Hara11ac72a2015-12-22 09:35:27 +0900564 defer func() {
565 done <- true
566 }()
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400567 for {
568 c, err := ln.Accept()
569 if err != nil {
570 break
571 }
572 // Server connection.
573 go func(c Conn) {
574 defer c.Close()
575 var buf [msgLen]byte
576 for m := 0; m < msgs; m++ {
577 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
578 break
579 }
580 }
581 }(c)
582 }
583 }()
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400584 for i := 0; i < conns; i++ {
585 // Client connection.
586 go func() {
587 defer func() {
588 done <- true
589 }()
590 c, err := Dial("tcp", ln.Addr().String())
591 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900592 t.Log(err)
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400593 return
594 }
595 defer c.Close()
596 var buf [msgLen]byte
597 for m := 0; m < msgs; m++ {
598 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
599 break
600 }
601 }
602 }()
603 }
604 for i := 0; i < conns; i++ {
605 <-done
606 }
Mikio Hara11ac72a2015-12-22 09:35:27 +0900607 ln.Close()
608 <-done
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400609}
Mikio Hara2ae749c2016-04-04 18:48:06 +0900610
611func TestTCPSelfConnect(t *testing.T) {
612 if runtime.GOOS == "windows" {
613 // TODO(brainman): do not know why it hangs.
614 t.Skip("known-broken test on windows")
615 }
616
617 ln, err := newLocalListener("tcp")
618 if err != nil {
619 t.Fatal(err)
620 }
621 var d Dialer
622 c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
623 if err != nil {
624 ln.Close()
625 t.Fatal(err)
626 }
627 network := c.LocalAddr().Network()
628 laddr := *c.LocalAddr().(*TCPAddr)
629 c.Close()
630 ln.Close()
631
632 // Try to connect to that address repeatedly.
633 n := 100000
634 if testing.Short() {
635 n = 1000
636 }
637 switch runtime.GOOS {
638 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
639 // Non-Linux systems take a long time to figure
640 // out that there is nothing listening on localhost.
641 n = 100
642 }
643 for i := 0; i < n; i++ {
644 d.Timeout = time.Millisecond
645 c, err := d.Dial(network, laddr.String())
646 if err == nil {
647 addr := c.LocalAddr().(*TCPAddr)
648 if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) {
649 t.Errorf("Dial %v should fail", addr)
650 } else {
651 t.Logf("Dial %v succeeded - possibly racing with other listener", addr)
652 }
653 c.Close()
654 }
655 }
656}