blob: cb58ab571dbe4668e0e09cab4e518706a7484f21 [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 (
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +04008 "io"
Mikio Hara4f74bbd2012-11-28 06:36:05 +09009 "reflect"
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040010 "runtime"
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +040011 "sync"
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040012 "testing"
13 "time"
14)
15
Mikio Hara13393fb2013-03-03 11:25:49 +090016func BenchmarkTCP4OneShot(b *testing.B) {
17 benchmarkTCP(b, false, false, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040018}
19
Mikio Hara13393fb2013-03-03 11:25:49 +090020func BenchmarkTCP4OneShotTimeout(b *testing.B) {
21 benchmarkTCP(b, false, true, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040022}
23
Mikio Hara13393fb2013-03-03 11:25:49 +090024func BenchmarkTCP4Persistent(b *testing.B) {
25 benchmarkTCP(b, true, false, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040026}
27
Mikio Hara13393fb2013-03-03 11:25:49 +090028func BenchmarkTCP4PersistentTimeout(b *testing.B) {
29 benchmarkTCP(b, true, true, "127.0.0.1:0")
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040030}
31
Mikio Hara13393fb2013-03-03 11:25:49 +090032func BenchmarkTCP6OneShot(b *testing.B) {
33 if !supportsIPv6 {
34 b.Skip("ipv6 is not supported")
35 }
36 benchmarkTCP(b, false, false, "[::1]:0")
37}
38
39func BenchmarkTCP6OneShotTimeout(b *testing.B) {
40 if !supportsIPv6 {
41 b.Skip("ipv6 is not supported")
42 }
43 benchmarkTCP(b, false, true, "[::1]:0")
44}
45
46func BenchmarkTCP6Persistent(b *testing.B) {
47 if !supportsIPv6 {
48 b.Skip("ipv6 is not supported")
49 }
50 benchmarkTCP(b, true, false, "[::1]:0")
51}
52
53func BenchmarkTCP6PersistentTimeout(b *testing.B) {
54 if !supportsIPv6 {
55 b.Skip("ipv6 is not supported")
56 }
57 benchmarkTCP(b, true, true, "[::1]:0")
58}
59
60func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
Mikio Hara93553dd2015-04-01 12:21:15 +090061 testHookUninstaller.Do(func() { uninstallTestHooks() })
Mikio Hara29d1f3b2015-03-01 12:27:01 +090062
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040063 const msgLen = 512
64 conns := b.N
Dmitriy Vyukov905f2962013-08-06 21:29:35 +040065 numConcurrent := runtime.GOMAXPROCS(-1) * 2
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040066 msgs := 1
67 if persistent {
68 conns = numConcurrent
69 msgs = b.N / conns
70 if msgs == 0 {
71 msgs = 1
72 }
73 if conns > b.N {
74 conns = b.N
75 }
76 }
77 sendMsg := func(c Conn, buf []byte) bool {
78 n, err := c.Write(buf)
79 if n != len(buf) || err != nil {
80 b.Logf("Write failed: %v", err)
81 return false
82 }
83 return true
84 }
85 recvMsg := func(c Conn, buf []byte) bool {
86 for read := 0; read != len(buf); {
87 n, err := c.Read(buf)
88 read += n
89 if err != nil {
90 b.Logf("Read failed: %v", err)
91 return false
92 }
93 }
94 return true
95 }
Mikio Hara13393fb2013-03-03 11:25:49 +090096 ln, err := Listen("tcp", laddr)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +040097 if err != nil {
98 b.Fatalf("Listen failed: %v", err)
99 }
100 defer ln.Close()
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400101 serverSem := make(chan bool, numConcurrent)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400102 // Acceptor.
103 go func() {
104 for {
105 c, err := ln.Accept()
106 if err != nil {
107 break
108 }
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400109 serverSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400110 // Server connection.
111 go func(c Conn) {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400112 defer func() {
113 c.Close()
114 <-serverSem
115 }()
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400116 if timeout {
117 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
118 }
119 var buf [msgLen]byte
120 for m := 0; m < msgs; m++ {
121 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
122 break
123 }
124 }
125 }(c)
126 }
127 }()
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400128 clientSem := make(chan bool, numConcurrent)
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400129 for i := 0; i < conns; i++ {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400130 clientSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400131 // Client connection.
132 go func() {
133 defer func() {
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400134 <-clientSem
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400135 }()
136 c, err := Dial("tcp", ln.Addr().String())
137 if err != nil {
138 b.Logf("Dial failed: %v", err)
139 return
140 }
141 defer c.Close()
142 if timeout {
143 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
144 }
145 var buf [msgLen]byte
146 for m := 0; m < msgs; m++ {
147 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
148 break
149 }
150 }
151 }()
152 }
Dmitriy Vyukov8076f212014-04-07 11:00:07 +0400153 for i := 0; i < numConcurrent; i++ {
154 clientSem <- true
155 serverSem <- true
Dmitriy Vyukov922056d2012-08-20 21:27:52 +0400156 }
157}
Mikio Hara677c6e62012-11-13 12:56:28 +0900158
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400159func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
160 benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
161}
162
163func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
164 if !supportsIPv6 {
165 b.Skip("ipv6 is not supported")
166 }
167 benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
168}
169
170func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
Mikio Hara93553dd2015-04-01 12:21:15 +0900171 testHookUninstaller.Do(func() { uninstallTestHooks() })
172
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400173 // The benchmark creates GOMAXPROCS client/server pairs.
174 // Each pair creates 4 goroutines: client reader/writer and server reader/writer.
175 // The benchmark stresses concurrent reading and writing to the same connection.
176 // Such pattern is used in net/http and net/rpc.
177
178 b.StopTimer()
179
180 P := runtime.GOMAXPROCS(0)
181 N := b.N / P
182 W := 1000
183
184 // Setup P client/server connections.
185 clients := make([]Conn, P)
186 servers := make([]Conn, P)
187 ln, err := Listen("tcp", laddr)
188 if err != nil {
189 b.Fatalf("Listen failed: %v", err)
190 }
191 defer ln.Close()
192 done := make(chan bool)
193 go func() {
194 for p := 0; p < P; p++ {
195 s, err := ln.Accept()
196 if err != nil {
Mikio Haraf0433e42014-03-15 13:43:02 +0900197 b.Errorf("Accept failed: %v", err)
198 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400199 }
200 servers[p] = s
201 }
202 done <- true
203 }()
204 for p := 0; p < P; p++ {
205 c, err := Dial("tcp", ln.Addr().String())
206 if err != nil {
207 b.Fatalf("Dial failed: %v", err)
208 }
209 clients[p] = c
210 }
211 <-done
212
213 b.StartTimer()
214
215 var wg sync.WaitGroup
216 wg.Add(4 * P)
217 for p := 0; p < P; p++ {
218 // Client writer.
219 go func(c Conn) {
220 defer wg.Done()
221 var buf [1]byte
222 for i := 0; i < N; i++ {
223 v := byte(i)
224 for w := 0; w < W; w++ {
225 v *= v
226 }
227 buf[0] = v
228 _, err := c.Write(buf[:])
229 if err != nil {
Mikio Haraf0433e42014-03-15 13:43:02 +0900230 b.Errorf("Write failed: %v", err)
231 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400232 }
233 }
234 }(clients[p])
235
236 // Pipe between server reader and server writer.
237 pipe := make(chan byte, 128)
238
239 // Server reader.
240 go func(s Conn) {
241 defer wg.Done()
242 var buf [1]byte
243 for i := 0; i < N; i++ {
244 _, err := s.Read(buf[:])
245 if err != nil {
Mikio Haraf0433e42014-03-15 13:43:02 +0900246 b.Errorf("Read failed: %v", err)
247 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400248 }
249 pipe <- buf[0]
250 }
251 }(servers[p])
252
253 // Server writer.
254 go func(s Conn) {
255 defer wg.Done()
256 var buf [1]byte
257 for i := 0; i < N; i++ {
258 v := <-pipe
259 for w := 0; w < W; w++ {
260 v *= v
261 }
262 buf[0] = v
263 _, err := s.Write(buf[:])
264 if err != nil {
Mikio Haraf0433e42014-03-15 13:43:02 +0900265 b.Errorf("Write failed: %v", err)
266 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400267 }
268 }
269 s.Close()
270 }(servers[p])
271
272 // Client reader.
273 go func(c Conn) {
274 defer wg.Done()
275 var buf [1]byte
276 for i := 0; i < N; i++ {
277 _, err := c.Read(buf[:])
278 if err != nil {
Mikio Haraf0433e42014-03-15 13:43:02 +0900279 b.Errorf("Read failed: %v", err)
280 return
Dmitriy Vyukov905f2962013-08-06 21:29:35 +0400281 }
282 }
283 c.Close()
284 }(clients[p])
285 }
286 wg.Wait()
287}
288
Mikio Hara9d97b552013-03-27 01:06:48 +0900289type resolveTCPAddrTest struct {
Mikio Hara5a83f062015-04-05 17:00:14 +0900290 network string
Mikio Hara7c59c8b2013-08-31 10:28:49 +0900291 litAddrOrName string
292 addr *TCPAddr
293 err error
Mikio Hara9d97b552013-03-27 01:06:48 +0900294}
295
296var resolveTCPAddrTests = []resolveTCPAddrTest{
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900297 {"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
298 {"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
299
Mikio Hara5a83f062015-04-05 17:00:14 +0900300 {"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
301 {"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900302
Mikio Haraaa0dda72013-03-23 09:57:40 +0900303 {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
304 {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
Mikio Haraaa0dda72013-03-23 09:57:40 +0900305
Mikio Harae3e885b2012-12-01 14:49:54 +0900306 {"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
307 {"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
308
Russ Coxe8bbbe02013-09-23 22:40:24 -0400309 {"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
310
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900311 {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
312}
313
314func TestResolveTCPAddr(t *testing.T) {
Mikio Hara5a83f062015-04-05 17:00:14 +0900315 origTestHookLookupIP := testHookLookupIP
316 defer func() { testHookLookupIP = origTestHookLookupIP }()
317 testHookLookupIP = lookupLocalhost
318
319 for i, tt := range resolveTCPAddrTests {
320 addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900321 if err != tt.err {
Mikio Hara5a83f062015-04-05 17:00:14 +0900322 t.Errorf("#%d: %v", i, err)
323 } else if !reflect.DeepEqual(addr, tt.addr) {
324 t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900325 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900326 if err != nil {
327 continue
Russ Coxe8bbbe02013-09-23 22:40:24 -0400328 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900329 rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
330 if err != nil {
331 t.Errorf("#%d: %v", i, err)
332 } else if !reflect.DeepEqual(rtaddr, addr) {
333 t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
Mikio Hara4f74bbd2012-11-28 06:36:05 +0900334 }
335 }
336}
337
Mikio Hara677c6e62012-11-13 12:56:28 +0900338var tcpListenerNameTests = []struct {
339 net string
340 laddr *TCPAddr
341}{
342 {"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
343 {"tcp4", &TCPAddr{}},
344 {"tcp4", nil},
345}
346
347func TestTCPListenerName(t *testing.T) {
348 if testing.Short() || !*testExternal {
Dave Cheney6a9e9562013-01-24 17:32:10 +1100349 t.Skip("skipping test to avoid external network")
Mikio Hara677c6e62012-11-13 12:56:28 +0900350 }
351
352 for _, tt := range tcpListenerNameTests {
353 ln, err := ListenTCP(tt.net, tt.laddr)
354 if err != nil {
Mikio Harabfb32dc2013-03-23 22:32:19 +0900355 t.Fatalf("ListenTCP failed: %v", err)
Mikio Hara677c6e62012-11-13 12:56:28 +0900356 }
357 defer ln.Close()
358 la := ln.Addr()
359 if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
Mikio Harabfb32dc2013-03-23 22:32:19 +0900360 t.Fatalf("got %v; expected a proper address with non-zero port number", la)
Mikio Hara677c6e62012-11-13 12:56:28 +0900361 }
362 }
363}
Mikio Haraaa0dda72013-03-23 09:57:40 +0900364
365func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
366 if testing.Short() || !*testExternal {
367 t.Skip("skipping test to avoid external network")
368 }
369 if !supportsIPv6 {
370 t.Skip("ipv6 is not supported")
371 }
372 ifi := loopbackInterface()
373 if ifi == nil {
374 t.Skip("loopback interface not found")
375 }
376 laddr := ipv6LinkLocalUnicastAddr(ifi)
377 if laddr == "" {
378 t.Skip("ipv6 unicast address on loopback not found")
379 }
380
381 type test struct {
382 net, addr string
383 nameLookup bool
384 }
385 var tests = []test{
386 {"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
387 {"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
388 }
389 switch runtime.GOOS {
Robert Hencke78fbe902014-04-27 17:39:13 -0700390 case "darwin", "freebsd", "openbsd", "netbsd":
Mikio Haraaa0dda72013-03-23 09:57:40 +0900391 tests = append(tests, []test{
392 {"tcp", "[localhost%" + ifi.Name + "]:0", true},
393 {"tcp6", "[localhost%" + ifi.Name + "]:0", true},
394 }...)
395 case "linux":
396 tests = append(tests, []test{
397 {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
398 {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
399 }...)
400 }
Mikio Hara832c5732015-04-19 23:42:11 +0900401 for i, tt := range tests {
Mikio Haraaa0dda72013-03-23 09:57:40 +0900402 ln, err := Listen(tt.net, tt.addr)
403 if err != nil {
404 // It might return "LookupHost returned no
405 // suitable address" error on some platforms.
406 t.Logf("Listen failed: %v", err)
407 continue
408 }
Mikio Haraf0775052015-04-02 23:11:39 +0900409 ls, err := (&streamListener{Listener: ln}).newLocalServer()
410 if err != nil {
411 t.Fatal(err)
412 }
413 defer ls.teardown()
Mikio Hara832c5732015-04-19 23:42:11 +0900414 ch := make(chan error, 1)
415 handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
Mikio Haraf0775052015-04-02 23:11:39 +0900416 if err := ls.buildup(handler); err != nil {
417 t.Fatal(err)
418 }
Mikio Haraaa0dda72013-03-23 09:57:40 +0900419 if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
420 t.Fatalf("got %v; expected a proper address with zone identifier", la)
421 }
422
Mikio Haraf0775052015-04-02 23:11:39 +0900423 c, err := Dial(tt.net, ls.Listener.Addr().String())
Mikio Haraaa0dda72013-03-23 09:57:40 +0900424 if err != nil {
425 t.Fatalf("Dial failed: %v", err)
426 }
427 defer c.Close()
428 if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
429 t.Fatalf("got %v; expected a proper address with zone identifier", la)
430 }
431 if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
432 t.Fatalf("got %v; expected a proper address with zone identifier", ra)
433 }
434
435 if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
436 t.Fatalf("Conn.Write failed: %v", err)
437 }
438 b := make([]byte, 32)
439 if _, err := c.Read(b); err != nil {
440 t.Fatalf("Conn.Read failed: %v", err)
441 }
Mikio Hara832c5732015-04-19 23:42:11 +0900442
443 for err := range ch {
444 t.Errorf("#%d: %v", i, err)
445 }
Mikio Haraaa0dda72013-03-23 09:57:40 +0900446 }
447}
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400448
449func TestTCPConcurrentAccept(t *testing.T) {
450 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
451 ln, err := Listen("tcp", "127.0.0.1:0")
452 if err != nil {
453 t.Fatalf("Listen failed: %v", err)
454 }
455 const N = 10
456 var wg sync.WaitGroup
457 wg.Add(N)
458 for i := 0; i < N; i++ {
459 go func() {
460 for {
461 c, err := ln.Accept()
462 if err != nil {
463 break
464 }
465 c.Close()
466 }
467 wg.Done()
468 }()
469 }
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900470 attempts := 10 * N
471 fails := 0
472 d := &Dialer{Timeout: 200 * time.Millisecond}
473 for i := 0; i < attempts; i++ {
474 c, err := d.Dial("tcp", ln.Addr().String())
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400475 if err != nil {
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900476 fails++
477 } else {
478 c.Close()
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400479 }
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400480 }
481 ln.Close()
482 wg.Wait()
Mikio Hara4f1aecf2014-03-25 02:56:37 +0900483 if fails > attempts/9 { // see issues 7400 and 7541
484 t.Fatalf("too many Dial failed: %v", fails)
485 }
486 if fails > 0 {
487 t.Logf("# of failed Dials: %v", fails)
488 }
Dmitriy Vyukov77f21ee2013-08-04 23:31:23 +0400489}
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400490
Mikio Hara3dd029a2015-02-24 14:13:47 +0900491func TestTCPReadWriteAllocs(t *testing.T) {
492 switch runtime.GOOS {
Brad Fitzpatrick80470932015-03-27 10:19:17 +0100493 case "nacl", "windows":
Mikio Hara3dd029a2015-02-24 14:13:47 +0900494 // NaCl needs to allocate pseudo file descriptor
495 // stuff. See syscall/fd_nacl.go.
496 // Windows uses closures and channels for IO
497 // completion port-based netpoll. See fd_windows.go.
498 t.Skipf("not supported on %s", runtime.GOOS)
Rob Pikef5787262013-08-21 14:00:45 +1000499 }
Mikio Hara3dd029a2015-02-24 14:13:47 +0900500
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400501 ln, err := Listen("tcp", "127.0.0.1:0")
502 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900503 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400504 }
505 defer ln.Close()
506 var server Conn
507 errc := make(chan error)
508 go func() {
509 var err error
510 server, err = ln.Accept()
511 errc <- err
512 }()
513 client, err := Dial("tcp", ln.Addr().String())
514 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900515 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400516 }
Mikio Hara3dd029a2015-02-24 14:13:47 +0900517 defer client.Close()
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400518 if err := <-errc; err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900519 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400520 }
521 defer server.Close()
522 var buf [128]byte
Mikio Hara3dd029a2015-02-24 14:13:47 +0900523 allocs := testing.AllocsPerRun(1000, func() {
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400524 _, err := server.Write(buf[:])
525 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900526 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400527 }
528 _, err = io.ReadFull(client, buf[:])
529 if err != nil {
Mikio Hara3dd029a2015-02-24 14:13:47 +0900530 t.Fatal(err)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400531 }
532 })
Mikio Hara3dd029a2015-02-24 14:13:47 +0900533 if allocs > 0 {
534 t.Fatalf("got %v; want 0", allocs)
Dmitriy Vyukov04b1cfa2013-08-06 14:40:10 +0400535 }
536}
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400537
538func TestTCPStress(t *testing.T) {
539 const conns = 2
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400540 const msgLen = 512
Dmitriy Vyukovf8ca13c2013-08-14 21:53:27 +0400541 msgs := int(1e4)
542 if testing.Short() {
543 msgs = 1e2
544 }
Dmitriy Vyukov1da10302013-08-13 22:07:42 +0400545
546 sendMsg := func(c Conn, buf []byte) bool {
547 n, err := c.Write(buf)
548 if n != len(buf) || err != nil {
549 t.Logf("Write failed: %v", err)
550 return false
551 }
552 return true
553 }
554 recvMsg := func(c Conn, buf []byte) bool {
555 for read := 0; read != len(buf); {
556 n, err := c.Read(buf)
557 read += n
558 if err != nil {
559 t.Logf("Read failed: %v", err)
560 return false
561 }
562 }
563 return true
564 }
565
566 ln, err := Listen("tcp", "127.0.0.1:0")
567 if err != nil {
568 t.Fatalf("Listen failed: %v", err)
569 }
570 defer ln.Close()
571 // Acceptor.
572 go func() {
573 for {
574 c, err := ln.Accept()
575 if err != nil {
576 break
577 }
578 // Server connection.
579 go func(c Conn) {
580 defer c.Close()
581 var buf [msgLen]byte
582 for m := 0; m < msgs; m++ {
583 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
584 break
585 }
586 }
587 }(c)
588 }
589 }()
590 done := make(chan bool)
591 for i := 0; i < conns; i++ {
592 // Client connection.
593 go func() {
594 defer func() {
595 done <- true
596 }()
597 c, err := Dial("tcp", ln.Addr().String())
598 if err != nil {
599 t.Logf("Dial failed: %v", err)
600 return
601 }
602 defer c.Close()
603 var buf [msgLen]byte
604 for m := 0; m < msgs; m++ {
605 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
606 break
607 }
608 }
609 }()
610 }
611 for i := 0; i < conns; i++ {
612 <-done
613 }
614}