/* Tries several IP addresses to connect (IPv4 and IPv6) but with a short timeout, to keep the eyeballs happy. Author unknown. Retrieved from http://www.pastie.org/1528545 */ package main import ( "net" "time" "flag" "fmt" "strconv" ) func multiHomeConnect(host string, port int, nsTimeout int64) net.Conn { r := make(chan net.Conn, 1) // non-blocking chan timeout := make(chan bool, 1) // idem var fd net.Conn listAddr, err := net.LookupHost(host) if err != nil { return nil } connect := func(host, port string) { c, err := net.Dial("tcp", host+":"+port) if err != nil { return } r <- c } launchTimeout := func(ns int64) { time.Sleep(ns) timeout <- true } fmt.Println("Connecting to ", host) done: for _, h := range listAddr { fmt.Println("try to connect to ", h) go connect(host, strconv.Itoa(port)) go launchTimeout(nsTimeout) select { case fd = <-r: break done case <-timeout: nsTimeout >>= 1 } } return fd } func main() { host := flag.String("host", "www.bortzmeyer.org", "host") port := flag.Int("port", 80, "port") timeout := flag.Int64("timeout", 100, "timeout in ms") flag.Parse() start := time.Nanoseconds() ok := multiHomeConnect(*host, *port, *timeout*1e6) stop := time.Nanoseconds() if ok != nil { fmt.Println("Connected to ", *host, " in ", (stop-start)/1e6, "ms") return } fmt.Println("*** Timeout ***") }