1 // Copyright 2011 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.
23 func newLocalListener(t
*testing
.T
) Listener
{
24 ln
, err
:= Listen("tcp", "127.0.0.1:0")
26 ln
, err
= Listen("tcp6", "[::1]:0")
34 func TestDialTimeout(t
*testing
.T
) {
35 origBacklog
:= listenerBacklog
37 listenerBacklog
= origBacklog
41 ln
:= newLocalListener(t
)
44 errc
:= make(chan error
)
46 numConns
:= listenerBacklog
+ 100
48 // TODO(bradfitz): It's hard to test this in a portable
49 // way. This is unfortunate, but works for now.
52 // The kernel will start accepting TCP connections before userspace
53 // gets a chance to not accept them, so fire off a bunch to fill up
54 // the kernel's backlog. Then we test we get a failure after that.
55 for i
:= 0; i
< numConns
; i
++ {
57 _
, err
:= DialTimeout("tcp", ln
.Addr().String(), 200*time
.Millisecond
)
61 case "darwin", "plan9", "windows":
62 // At least OS X 10.7 seems to accept any number of
63 // connections, ignoring listen's backlog, so resort
64 // to connecting to a hopefully-dead 127/8 address.
67 // Use an IANA reserved port (49151) instead of 80, because
68 // on our 386 builder, this Dial succeeds, connecting
69 // to an IIS web server somewhere. The data center
70 // or VM or firewall must be stealing the TCP connection.
72 // IANA Service Name and Transport Protocol Port Number Registry
73 // <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
75 c
, err
:= DialTimeout("tcp", "127.0.71.111:49151", 200*time
.Millisecond
)
77 err
= fmt
.Errorf("unexpected: connected to %s!", c
.RemoteAddr())
84 // OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
85 // by default. FreeBSD likely works, but is untested.
87 // The timeout never happens on Windows. Why? Issue 3016.
88 t
.Skipf("skipping test on %q; untested.", runtime
.GOOS
)
94 case <-time
.After(15 * time
.Second
):
99 if connected
== numConns
{
100 t
.Fatal("all connections connected; expected some to time out")
103 terr
, ok
:= err
.(timeout
)
105 t
.Fatalf("got error %q; want error with timeout interface", err
)
108 t
.Fatalf("got error %q; not a timeout", err
)
110 // Pass. We saw a timeout error.
117 func TestSelfConnect(t
*testing
.T
) {
118 if runtime
.GOOS
== "windows" {
119 // TODO(brainman): do not know why it hangs.
120 t
.Skip("skipping known-broken test on windows")
122 // Test that Dial does not honor self-connects.
123 // See the comment in DialTCP.
125 // Find a port that would be used as a local address.
126 l
, err
:= Listen("tcp", "127.0.0.1:0")
130 c
, err
:= Dial("tcp", l
.Addr().String())
134 addr
:= c
.LocalAddr().String()
138 // Try to connect to that address repeatedly.
143 switch runtime
.GOOS
{
144 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
145 // Non-Linux systems take a long time to figure
146 // out that there is nothing listening on localhost.
149 for i
:= 0; i
< n
; i
++ {
150 c
, err
:= DialTimeout("tcp", addr
, time
.Millisecond
)
153 t
.Errorf("#%d: Dial %q succeeded", i
, addr
)
158 var runErrorTest
= flag
.Bool("run_error_test", false, "let TestDialError check for dns errors")
160 type DialErrorTest
struct {
166 var dialErrorTests
= []DialErrorTest
{
168 "datakit", "mh/astro/r70",
169 "dial datakit mh/astro/r70: unknown network datakit",
172 "tcp", "127.0.0.1:☺",
173 "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
176 "tcp", "no-such-name.google.com.:80",
177 "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
180 "tcp", "no-such-name.no-such-top-level-domain.:80",
181 "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
184 "tcp", "no-such-name:80",
185 `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
188 "tcp", "mh/astro/r70:http",
189 "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
192 "unix", "/etc/file-not-found",
193 "dial unix /etc/file-not-found: no such file or directory",
197 "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
200 "unixpacket", "/etc/file-not-found",
201 "dial unixpacket /etc/file-not-found: no such file or directory",
204 "unixpacket", "/etc/",
205 "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
209 var duplicateErrorPattern
= `dial (.*) dial (.*)`
211 func TestDialError(t
*testing
.T
) {
213 t
.Logf("test disabled; use -run_error_test to enable")
216 for i
, tt
:= range dialErrorTests
{
217 c
, err
:= Dial(tt
.Net
, tt
.Raddr
)
222 t
.Errorf("#%d: nil error, want match for %#q", i
, tt
.Pattern
)
226 match
, _
:= regexp
.MatchString(tt
.Pattern
, s
)
228 t
.Errorf("#%d: %q, want match for %#q", i
, s
, tt
.Pattern
)
230 match
, _
= regexp
.MatchString(duplicateErrorPattern
, s
)
232 t
.Errorf("#%d: %q, duplicate error return from Dial", i
, s
)
237 var invalidDialAndListenArgTests
= []struct {
242 {"foo", "bar", &OpError
{Op
: "dial", Net
: "foo", Addr
: nil, Err
: UnknownNetworkError("foo")}},
243 {"baz", "", &OpError
{Op
: "listen", Net
: "baz", Addr
: nil, Err
: UnknownNetworkError("baz")}},
244 {"tcp", "", &OpError
{Op
: "dial", Net
: "tcp", Addr
: nil, Err
: errMissingAddress
}},
247 func TestInvalidDialAndListenArgs(t
*testing
.T
) {
248 for _
, tt
:= range invalidDialAndListenArgTests
{
250 switch tt
.err
.(*OpError
).Op
{
252 _
, err
= Dial(tt
.net
, tt
.addr
)
254 _
, err
= Listen(tt
.net
, tt
.addr
)
256 if !reflect
.DeepEqual(tt
.err
, err
) {
257 t
.Fatalf("got %#v; expected %#v", err
, tt
.err
)
262 func TestDialTimeoutFDLeak(t
*testing
.T
) {
263 if runtime
.GOOS
!= "linux" {
264 // TODO(bradfitz): test on other platforms
265 t
.Skipf("skipping test on %q", runtime
.GOOS
)
268 ln
:= newLocalListener(t
)
271 type connErr
struct {
275 dials
:= listenerBacklog
+ 100
276 // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
277 maxGoodConnect
:= listenerBacklog
+ runtime
.NumCPU()*10
278 resc
:= make(chan connErr
)
279 for i
:= 0; i
< dials
; i
++ {
281 conn
, err
:= DialTimeout("tcp", ln
.Addr().String(), 500*time
.Millisecond
)
282 resc
<- connErr
{conn
, err
}
288 var toClose
[]io
.Closer
289 for i
:= 0; i
< dials
; i
++ {
293 if ngood
> maxGoodConnect
{
294 t
.Errorf("%d good connects; expected at most %d", ngood
, maxGoodConnect
)
296 toClose
= append(toClose
, ce
.conn
)
301 firstErr
= err
.Error()
302 } else if err
.Error() != firstErr
{
303 t
.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr
, err
)
306 for _
, c
:= range toClose
{
309 for i
:= 0; i
< 100; i
++ {
310 if got
:= numFD(); got
< dials
{
314 time
.Sleep(10 * time
.Millisecond
)
316 if got
:= numFD(); got
>= dials
{
317 t
.Errorf("num fds after %d timeouts = %d; want <%d", dials
, got
, dials
)
321 func numTCP() (ntcp
, nopen
, nclose
int, err error
) {
322 lsof
, err
:= exec
.Command("lsof", "-n", "-p", strconv
.Itoa(os
.Getpid())).Output()
326 ntcp
+= bytes
.Count(lsof
, []byte("TCP"))
327 for _
, state
:= range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} {
328 nopen
+= bytes
.Count(lsof
, []byte(state
))
330 for _
, state
:= range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} {
331 nclose
+= bytes
.Count(lsof
, []byte(state
))
333 return ntcp
, nopen
, nclose
, nil
336 func TestDialMultiFDLeak(t
*testing
.T
) {
337 if !supportsIPv4 ||
!supportsIPv6
{
338 t
.Skip("neither ipv4 nor ipv6 is supported")
341 halfDeadServer
:= func(dss
*dualStackServer
, ln Listener
) {
343 if c
, err
:= ln
.Accept(); err
!= nil {
346 // It just keeps established
347 // connections like a half-dead server
353 dss
, err
:= newDualStackServer([]streamListener
{
354 {net
: "tcp4", addr
: "127.0.0.1"},
355 {net
: "tcp6", addr
: "[::1]"},
358 t
.Fatalf("newDualStackServer failed: %v", err
)
361 if err
:= dss
.buildup(halfDeadServer
); err
!= nil {
362 t
.Fatalf("dualStackServer.buildup failed: %v", err
)
365 _
, before
, _
, err
:= numTCP()
367 t
.Skipf("skipping test; error finding or running lsof: %v", err
)
370 var wg sync
.WaitGroup
371 portnum
, _
, _
:= dtoi(dss
.port
, 0)
373 // Losers that will fail to connect, see RFC 6890.
374 &TCPAddr
{IP
: IPv4(198, 18, 0, 254), Port
: portnum
},
375 &TCPAddr
{IP
: ParseIP("2001:2::254"), Port
: portnum
},
377 // Winner candidates of this race.
378 &TCPAddr
{IP
: IPv4(127, 0, 0, 1), Port
: portnum
},
379 &TCPAddr
{IP
: IPv6loopback
, Port
: portnum
},
381 // Losers that will have established connections.
382 &TCPAddr
{IP
: IPv4(127, 0, 0, 1), Port
: portnum
},
383 &TCPAddr
{IP
: IPv6loopback
, Port
: portnum
},
385 const T1
= 10 * time
.Millisecond
388 for i
:= 0; i
< N
; i
++ {
392 if c
, err
:= dialMulti("tcp", "fast failover test", nil, ras
, time
.Now().Add(T1
)); err
== nil {
400 ntcp
, after
, nclose
, err
:= numTCP()
402 t
.Skipf("skipping test; error finding or running lsof: %v", err
)
404 t
.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp
, after
, nclose
)
407 t
.Fatalf("got %v open sessions; expected %v", after
, before
)
412 if runtime
.GOOS
== "linux" {
413 f
, err
:= os
.Open("/proc/self/fd")
418 names
, err
:= f
.Readdirnames(0)
424 // All tests using this should be skipped anyway, but:
425 panic("numFDs not implemented on " + runtime
.GOOS
)
428 // Assert that a failed Dial attempt does not leak
429 // runtime.PollDesc structures
430 func TestDialFailPDLeak(t
*testing
.T
) {
432 t
.Skip("skipping test in short mode")
434 if runtime
.GOOS
== "windows" && runtime
.GOARCH
== "386" {
435 // Just skip the test because it takes too long.
436 t
.Skipf("skipping test on %q/%q", runtime
.GOOS
, runtime
.GOARCH
)
439 maxprocs
:= runtime
.GOMAXPROCS(0)
440 loops
:= 10 + maxprocs
441 // 500 is enough to turn over the chunk of pollcache.
442 // See allocPollDesc in runtime/netpoll.goc.
444 var old runtime
.MemStats
// used by sysdelta
445 runtime
.ReadMemStats(&old
)
446 sysdelta
:= func() uint64 {
447 var new runtime
.MemStats
448 runtime
.ReadMemStats(&new)
449 delta
:= old
.Sys
- new.Sys
453 d
:= &Dialer
{Timeout
: time
.Nanosecond
} // don't bother TCP with handshaking
455 for i
:= 0; i
< loops
; i
++ {
456 var wg sync
.WaitGroup
457 for i
:= 0; i
< count
; i
++ {
461 if c
, err
:= d
.Dial("tcp", "127.0.0.1:1"); err
== nil {
462 t
.Error("dial should not succeed")
471 if delta
:= sysdelta(); delta
> 0 {
474 // there are always some allocations on the first loop
475 if failcount
> maxprocs
+2 {
476 t
.Error("detected possible memory leak in runtime")
482 func TestDialer(t
*testing
.T
) {
483 ln
, err
:= Listen("tcp4", "127.0.0.1:0")
485 t
.Fatalf("Listen failed: %v", err
)
488 ch
:= make(chan error
, 1)
490 c
, err
:= ln
.Accept()
492 ch
<- fmt
.Errorf("Accept failed: %v", err
)
499 laddr
, err
:= ResolveTCPAddr("tcp4", "127.0.0.1:0")
501 t
.Fatalf("ResolveTCPAddr failed: %v", err
)
503 d
:= &Dialer
{LocalAddr
: laddr
}
504 c
, err
:= d
.Dial("tcp4", ln
.Addr().String())
506 t
.Fatalf("Dial failed: %v", err
)
509 c
.Read(make([]byte, 1))
516 func TestDialDualStackLocalhost(t
*testing
.T
) {
517 if ips
, err
:= LookupIP("localhost"); err
!= nil {
518 t
.Fatalf("LookupIP failed: %v", err
)
519 } else if len(ips
) < 2 ||
!supportsIPv4 ||
!supportsIPv6
{
520 t
.Skip("localhost doesn't have a pair of different address family IP addresses")
523 touchAndByeServer
:= func(dss
*dualStackServer
, ln Listener
) {
525 if c
, err
:= ln
.Accept(); err
!= nil {
532 dss
, err
:= newDualStackServer([]streamListener
{
533 {net
: "tcp4", addr
: "127.0.0.1"},
534 {net
: "tcp6", addr
: "[::1]"},
537 t
.Fatalf("newDualStackServer failed: %v", err
)
540 if err
:= dss
.buildup(touchAndByeServer
); err
!= nil {
541 t
.Fatalf("dualStackServer.buildup failed: %v", err
)
544 d
:= &Dialer
{DualStack
: true}
545 for _
= range dss
.lns
{
546 if c
, err
:= d
.Dial("tcp", "localhost:"+dss
.port
); err
!= nil {
547 t
.Errorf("Dial failed: %v", err
)
549 if addr
:= c
.LocalAddr().(*TCPAddr
); addr
.IP
.To4() != nil {
550 dss
.teardownNetwork("tcp4")
551 } else if addr
.IP
.To16() != nil && addr
.IP
.To4() == nil {
552 dss
.teardownNetwork("tcp6")