github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/net/dial_test.go (about) 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. 4 5 package net 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "io" 12 "os" 13 "os/exec" 14 "reflect" 15 "regexp" 16 "runtime" 17 "strconv" 18 "sync" 19 "testing" 20 "time" 21 ) 22 23 func newLocalListener(t *testing.T) Listener { 24 ln, err := Listen("tcp", "127.0.0.1:0") 25 if err != nil { 26 ln, err = Listen("tcp6", "[::1]:0") 27 } 28 if err != nil { 29 t.Fatal(err) 30 } 31 return ln 32 } 33 34 func TestDialTimeout(t *testing.T) { 35 origBacklog := listenerBacklog 36 defer func() { 37 listenerBacklog = origBacklog 38 }() 39 listenerBacklog = 1 40 41 ln := newLocalListener(t) 42 defer ln.Close() 43 44 errc := make(chan error) 45 46 numConns := listenerBacklog + 100 47 48 // TODO(bradfitz): It's hard to test this in a portable 49 // way. This is unfortunate, but works for now. 50 switch runtime.GOOS { 51 case "linux": 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++ { 56 go func() { 57 _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond) 58 errc <- err 59 }() 60 } 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. 65 // Same for windows. 66 // 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. 71 // 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> 74 go func() { 75 c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond) 76 if err == nil { 77 err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr()) 78 c.Close() 79 } 80 errc <- err 81 }() 82 default: 83 // TODO(bradfitz): 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. 86 // TODO(rsc): 87 // The timeout never happens on Windows. Why? Issue 3016. 88 t.Skipf("skipping test on %q; untested.", runtime.GOOS) 89 } 90 91 connected := 0 92 for { 93 select { 94 case <-time.After(15 * time.Second): 95 t.Fatal("too slow") 96 case err := <-errc: 97 if err == nil { 98 connected++ 99 if connected == numConns { 100 t.Fatal("all connections connected; expected some to time out") 101 } 102 } else { 103 terr, ok := err.(timeout) 104 if !ok { 105 t.Fatalf("got error %q; want error with timeout interface", err) 106 } 107 if !terr.Timeout() { 108 t.Fatalf("got error %q; not a timeout", err) 109 } 110 // Pass. We saw a timeout error. 111 return 112 } 113 } 114 } 115 } 116 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") 121 } 122 123 // Test that Dial does not honor self-connects. 124 // See the comment in DialTCP. 125 126 // Find a port that would be used as a local address. 127 l, err := Listen("tcp", "127.0.0.1:0") 128 if err != nil { 129 t.Fatal(err) 130 } 131 c, err := Dial("tcp", l.Addr().String()) 132 if err != nil { 133 t.Fatal(err) 134 } 135 addr := c.LocalAddr().String() 136 c.Close() 137 l.Close() 138 139 // Try to connect to that address repeatedly. 140 n := 100000 141 if testing.Short() { 142 n = 1000 143 } 144 switch runtime.GOOS { 145 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows": 146 // Non-Linux systems take a long time to figure 147 // out that there is nothing listening on localhost. 148 n = 100 149 } 150 for i := 0; i < n; i++ { 151 c, err := DialTimeout("tcp", addr, time.Millisecond) 152 if err == nil { 153 if c.LocalAddr().String() == addr { 154 t.Errorf("#%d: Dial %q self-connect", i, addr) 155 } else { 156 t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr) 157 } 158 c.Close() 159 } 160 } 161 } 162 163 var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors") 164 165 type DialErrorTest struct { 166 Net string 167 Raddr string 168 Pattern string 169 } 170 171 var dialErrorTests = []DialErrorTest{ 172 { 173 "datakit", "mh/astro/r70", 174 "dial datakit mh/astro/r70: unknown network datakit", 175 }, 176 { 177 "tcp", "127.0.0.1:☺", 178 "dial tcp 127.0.0.1:☺: unknown port tcp/☺", 179 }, 180 { 181 "tcp", "no-such-name.google.com.:80", 182 "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", 183 }, 184 { 185 "tcp", "no-such-name.no-such-top-level-domain.:80", 186 "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", 187 }, 188 { 189 "tcp", "no-such-name:80", 190 `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, 191 }, 192 { 193 "tcp", "mh/astro/r70:http", 194 "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", 195 }, 196 { 197 "unix", "/etc/file-not-found", 198 "dial unix /etc/file-not-found: no such file or directory", 199 }, 200 { 201 "unix", "/etc/", 202 "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)", 203 }, 204 { 205 "unixpacket", "/etc/file-not-found", 206 "dial unixpacket /etc/file-not-found: no such file or directory", 207 }, 208 { 209 "unixpacket", "/etc/", 210 "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", 211 }, 212 } 213 214 var duplicateErrorPattern = `dial (.*) dial (.*)` 215 216 func TestDialError(t *testing.T) { 217 if !*runErrorTest { 218 t.Logf("test disabled; use -run_error_test to enable") 219 return 220 } 221 for i, tt := range dialErrorTests { 222 c, err := Dial(tt.Net, tt.Raddr) 223 if c != nil { 224 c.Close() 225 } 226 if err == nil { 227 t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern) 228 continue 229 } 230 s := err.Error() 231 match, _ := regexp.MatchString(tt.Pattern, s) 232 if !match { 233 t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern) 234 } 235 match, _ = regexp.MatchString(duplicateErrorPattern, s) 236 if match { 237 t.Errorf("#%d: %q, duplicate error return from Dial", i, s) 238 } 239 } 240 } 241 242 var invalidDialAndListenArgTests = []struct { 243 net string 244 addr string 245 err error 246 }{ 247 {"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}}, 248 {"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}}, 249 {"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}}, 250 } 251 252 func TestInvalidDialAndListenArgs(t *testing.T) { 253 for _, tt := range invalidDialAndListenArgTests { 254 var err error 255 switch tt.err.(*OpError).Op { 256 case "dial": 257 _, err = Dial(tt.net, tt.addr) 258 case "listen": 259 _, err = Listen(tt.net, tt.addr) 260 } 261 if !reflect.DeepEqual(tt.err, err) { 262 t.Fatalf("got %#v; expected %#v", err, tt.err) 263 } 264 } 265 } 266 267 func TestDialTimeoutFDLeak(t *testing.T) { 268 if runtime.GOOS != "linux" { 269 // TODO(bradfitz): test on other platforms 270 t.Skipf("skipping test on %q", runtime.GOOS) 271 } 272 273 ln := newLocalListener(t) 274 defer ln.Close() 275 276 type connErr struct { 277 conn Conn 278 err error 279 } 280 dials := listenerBacklog + 100 281 // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384. 282 maxGoodConnect := listenerBacklog + runtime.NumCPU()*10 283 resc := make(chan connErr) 284 for i := 0; i < dials; i++ { 285 go func() { 286 conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond) 287 resc <- connErr{conn, err} 288 }() 289 } 290 291 var firstErr string 292 var ngood int 293 var toClose []io.Closer 294 for i := 0; i < dials; i++ { 295 ce := <-resc 296 if ce.err == nil { 297 ngood++ 298 if ngood > maxGoodConnect { 299 t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect) 300 } 301 toClose = append(toClose, ce.conn) 302 continue 303 } 304 err := ce.err 305 if firstErr == "" { 306 firstErr = err.Error() 307 } else if err.Error() != firstErr { 308 t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err) 309 } 310 } 311 for _, c := range toClose { 312 c.Close() 313 } 314 for i := 0; i < 100; i++ { 315 if got := numFD(); got < dials { 316 // Test passes. 317 return 318 } 319 time.Sleep(10 * time.Millisecond) 320 } 321 if got := numFD(); got >= dials { 322 t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials) 323 } 324 } 325 326 func numTCP() (ntcp, nopen, nclose int, err error) { 327 lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output() 328 if err != nil { 329 return 0, 0, 0, err 330 } 331 ntcp += bytes.Count(lsof, []byte("TCP")) 332 for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} { 333 nopen += bytes.Count(lsof, []byte(state)) 334 } 335 for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} { 336 nclose += bytes.Count(lsof, []byte(state)) 337 } 338 return ntcp, nopen, nclose, nil 339 } 340 341 func TestDialMultiFDLeak(t *testing.T) { 342 t.Skip("flaky test - golang.org/issue/8764") 343 344 if !supportsIPv4 || !supportsIPv6 { 345 t.Skip("neither ipv4 nor ipv6 is supported") 346 } 347 348 halfDeadServer := func(dss *dualStackServer, ln Listener) { 349 for { 350 if c, err := ln.Accept(); err != nil { 351 return 352 } else { 353 // It just keeps established 354 // connections like a half-dead server 355 // does. 356 dss.putConn(c) 357 } 358 } 359 } 360 dss, err := newDualStackServer([]streamListener{ 361 {net: "tcp4", addr: "127.0.0.1"}, 362 {net: "tcp6", addr: "[::1]"}, 363 }) 364 if err != nil { 365 t.Fatalf("newDualStackServer failed: %v", err) 366 } 367 defer dss.teardown() 368 if err := dss.buildup(halfDeadServer); err != nil { 369 t.Fatalf("dualStackServer.buildup failed: %v", err) 370 } 371 372 _, before, _, err := numTCP() 373 if err != nil { 374 t.Skipf("skipping test; error finding or running lsof: %v", err) 375 } 376 377 var wg sync.WaitGroup 378 portnum, _, _ := dtoi(dss.port, 0) 379 ras := addrList{ 380 // Losers that will fail to connect, see RFC 6890. 381 &TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum}, 382 &TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum}, 383 384 // Winner candidates of this race. 385 &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum}, 386 &TCPAddr{IP: IPv6loopback, Port: portnum}, 387 388 // Losers that will have established connections. 389 &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum}, 390 &TCPAddr{IP: IPv6loopback, Port: portnum}, 391 } 392 const T1 = 10 * time.Millisecond 393 const T2 = 2 * T1 394 const N = 10 395 for i := 0; i < N; i++ { 396 wg.Add(1) 397 go func() { 398 defer wg.Done() 399 if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil { 400 c.Close() 401 } 402 }() 403 } 404 wg.Wait() 405 time.Sleep(T2) 406 407 ntcp, after, nclose, err := numTCP() 408 if err != nil { 409 t.Skipf("skipping test; error finding or running lsof: %v", err) 410 } 411 t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose) 412 413 if after != before { 414 t.Fatalf("got %v open sessions; expected %v", after, before) 415 } 416 } 417 418 func numFD() int { 419 if runtime.GOOS == "linux" { 420 f, err := os.Open("/proc/self/fd") 421 if err != nil { 422 panic(err) 423 } 424 defer f.Close() 425 names, err := f.Readdirnames(0) 426 if err != nil { 427 panic(err) 428 } 429 return len(names) 430 } 431 // All tests using this should be skipped anyway, but: 432 panic("numFDs not implemented on " + runtime.GOOS) 433 } 434 435 func TestDialer(t *testing.T) { 436 ln, err := Listen("tcp4", "127.0.0.1:0") 437 if err != nil { 438 t.Fatalf("Listen failed: %v", err) 439 } 440 defer ln.Close() 441 ch := make(chan error, 1) 442 go func() { 443 c, err := ln.Accept() 444 if err != nil { 445 ch <- fmt.Errorf("Accept failed: %v", err) 446 return 447 } 448 defer c.Close() 449 ch <- nil 450 }() 451 452 laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0") 453 if err != nil { 454 t.Fatalf("ResolveTCPAddr failed: %v", err) 455 } 456 d := &Dialer{LocalAddr: laddr} 457 c, err := d.Dial("tcp4", ln.Addr().String()) 458 if err != nil { 459 t.Fatalf("Dial failed: %v", err) 460 } 461 defer c.Close() 462 c.Read(make([]byte, 1)) 463 err = <-ch 464 if err != nil { 465 t.Error(err) 466 } 467 } 468 469 func TestDialDualStackLocalhost(t *testing.T) { 470 switch runtime.GOOS { 471 case "nacl": 472 t.Skipf("skipping test on %q", runtime.GOOS) 473 } 474 475 if ips, err := LookupIP("localhost"); err != nil { 476 t.Fatalf("LookupIP failed: %v", err) 477 } else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 { 478 t.Skip("localhost doesn't have a pair of different address family IP addresses") 479 } 480 481 touchAndByeServer := func(dss *dualStackServer, ln Listener) { 482 for { 483 if c, err := ln.Accept(); err != nil { 484 return 485 } else { 486 c.Close() 487 } 488 } 489 } 490 dss, err := newDualStackServer([]streamListener{ 491 {net: "tcp4", addr: "127.0.0.1"}, 492 {net: "tcp6", addr: "[::1]"}, 493 }) 494 if err != nil { 495 t.Fatalf("newDualStackServer failed: %v", err) 496 } 497 defer dss.teardown() 498 if err := dss.buildup(touchAndByeServer); err != nil { 499 t.Fatalf("dualStackServer.buildup failed: %v", err) 500 } 501 502 d := &Dialer{DualStack: true} 503 for range dss.lns { 504 if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil { 505 t.Errorf("Dial failed: %v", err) 506 } else { 507 if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil { 508 dss.teardownNetwork("tcp4") 509 } else if addr.IP.To16() != nil && addr.IP.To4() == nil { 510 dss.teardownNetwork("tcp6") 511 } 512 c.Close() 513 } 514 } 515 } 516 517 func TestDialerKeepAlive(t *testing.T) { 518 ln := newLocalListener(t) 519 defer ln.Close() 520 defer func() { 521 testHookSetKeepAlive = func() {} 522 }() 523 go func() { 524 for { 525 c, err := ln.Accept() 526 if err != nil { 527 return 528 } 529 c.Close() 530 } 531 }() 532 for _, keepAlive := range []bool{false, true} { 533 got := false 534 testHookSetKeepAlive = func() { got = true } 535 var d Dialer 536 if keepAlive { 537 d.KeepAlive = 30 * time.Second 538 } 539 c, err := d.Dial("tcp", ln.Addr().String()) 540 if err != nil { 541 t.Fatal(err) 542 } 543 c.Close() 544 if got != keepAlive { 545 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got) 546 } 547 } 548 }