blob: 16b726311534ed7409502f90e354060ebc327a58 [file] [log] [blame]
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
"runtime"
"testing"
"time"
)
func newLocalListener(t *testing.T) Listener {
ln, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
ln, err = Listen("tcp6", "[::1]:0")
}
if err != nil {
t.Fatal(err)
}
return ln
}
func TestDialTimeout(t *testing.T) {
ln := newLocalListener(t)
defer ln.Close()
errc := make(chan error)
const SOMAXCONN = 0x80 // copied from syscall, but not always available
const numConns = SOMAXCONN + 10
// TODO(bradfitz): It's hard to test this in a portable
// way. This is unforunate, but works for now.
switch runtime.GOOS {
case "linux":
// The kernel will start accepting TCP connections before userspace
// gets a chance to not accept them, so fire off a bunch to fill up
// the kernel's backlog. Then we test we get a failure after that.
for i := 0; i < numConns; i++ {
go func() {
_, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
errc <- err
}()
}
case "darwin":
// At least OS X 10.7 seems to accept any number of
// connections, ignoring listen's backlog, so resort
// to connecting to a hopefully-dead 127/8 address.
go func() {
_, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
errc <- err
}()
default:
// TODO(bradfitz): this probably doesn't work on
// Windows? SOMAXCONN is huge there. I'm not sure how
// listen works there.
// OpenBSD may have a reject route to 10/8.
// FreeBSD likely works, but is untested.
t.Logf("skipping test on %q; untested.", runtime.GOOS)
return
}
connected := 0
for {
select {
case <-time.After(15 * time.Second):
t.Fatal("too slow")
case err := <-errc:
if err == nil {
connected++
if connected == numConns {
t.Fatal("all connections connected; expected some to time out")
}
} else {
terr, ok := err.(timeout)
if !ok {
t.Fatalf("got error %q; want error with timeout interface", err)
}
if !terr.Timeout() {
t.Fatalf("got error %q; not a timeout", err)
}
// Pass. We saw a timeout error.
return
}
}
}
}