rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 "fmt" 9 "net/internal/socktest" 10 "reflect" 11 "regexp" 12 "runtime" 13 "sync" 14 "testing" 15 "time" 16 ) 17 18 func TestSelfConnect(t *testing.T) { 19 if runtime.GOOS == "windows" { 20 // TODO(brainman): do not know why it hangs. 21 t.Skip("skipping known-broken test on windows") 22 } 23 24 // Test that Dial does not honor self-connects. 25 // See the comment in DialTCP. 26 27 // Find a port that would be used as a local address. 28 l, err := Listen("tcp", "127.0.0.1:0") 29 if err != nil { 30 t.Fatal(err) 31 } 32 c, err := Dial("tcp", l.Addr().String()) 33 if err != nil { 34 t.Fatal(err) 35 } 36 addr := c.LocalAddr().String() 37 c.Close() 38 l.Close() 39 40 // Try to connect to that address repeatedly. 41 n := 100000 42 if testing.Short() { 43 n = 1000 44 } 45 switch runtime.GOOS { 46 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows": 47 // Non-Linux systems take a long time to figure 48 // out that there is nothing listening on localhost. 49 n = 100 50 } 51 for i := 0; i < n; i++ { 52 c, err := DialTimeout("tcp", addr, time.Millisecond) 53 if err == nil { 54 if c.LocalAddr().String() == addr { 55 t.Errorf("#%d: Dial %q self-connect", i, addr) 56 } else { 57 t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr) 58 } 59 c.Close() 60 } 61 } 62 } 63 64 type DialErrorTest struct { 65 Net string 66 Raddr string 67 Pattern string 68 } 69 70 var dialErrorTests = []DialErrorTest{ 71 { 72 "datakit", "mh/astro/r70", 73 "dial datakit mh/astro/r70: unknown network datakit", 74 }, 75 { 76 "tcp", "127.0.0.1:☺", 77 "dial tcp 127.0.0.1:☺: unknown port tcp/☺", 78 }, 79 { 80 "tcp", "no-such-name.google.com.:80", 81 "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", 82 }, 83 { 84 "tcp", "no-such-name.no-such-top-level-domain.:80", 85 "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", 86 }, 87 { 88 "tcp", "no-such-name:80", 89 `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, 90 }, 91 { 92 "tcp", "mh/astro/r70:http", 93 "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", 94 }, 95 { 96 "unix", "/etc/file-not-found", 97 "dial unix /etc/file-not-found: no such file or directory", 98 }, 99 { 100 "unix", "/etc/", 101 "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)", 102 }, 103 { 104 "unixpacket", "/etc/file-not-found", 105 "dial unixpacket /etc/file-not-found: no such file or directory", 106 }, 107 { 108 "unixpacket", "/etc/", 109 "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", 110 }, 111 } 112 113 var duplicateErrorPattern = `dial (.*) dial (.*)` 114 115 func TestDialError(t *testing.T) { 116 if !*runErrorTest { 117 t.Logf("test disabled; use -run_error_test to enable") 118 return 119 } 120 for i, tt := range dialErrorTests { 121 c, err := Dial(tt.Net, tt.Raddr) 122 if c != nil { 123 c.Close() 124 } 125 if err == nil { 126 t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern) 127 continue 128 } 129 s := err.Error() 130 match, _ := regexp.MatchString(tt.Pattern, s) 131 if !match { 132 t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern) 133 } 134 match, _ = regexp.MatchString(duplicateErrorPattern, s) 135 if match { 136 t.Errorf("#%d: %q, duplicate error return from Dial", i, s) 137 } 138 } 139 } 140 141 var invalidDialAndListenArgTests = []struct { 142 net string 143 addr string 144 err error 145 }{ 146 {"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}}, 147 {"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}}, 148 {"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}}, 149 } 150 151 func TestInvalidDialAndListenArgs(t *testing.T) { 152 for _, tt := range invalidDialAndListenArgTests { 153 var err error 154 switch tt.err.(*OpError).Op { 155 case "dial": 156 _, err = Dial(tt.net, tt.addr) 157 case "listen": 158 _, err = Listen(tt.net, tt.addr) 159 } 160 if !reflect.DeepEqual(tt.err, err) { 161 t.Fatalf("got %#v; expected %#v", err, tt.err) 162 } 163 } 164 } 165 166 func TestDialTimeoutFDLeak(t *testing.T) { 167 switch runtime.GOOS { 168 case "plan9": 169 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 170 } 171 172 const T = 100 * time.Millisecond 173 174 switch runtime.GOOS { 175 case "plan9", "windows": 176 origTestHookDialChannel := testHookDialChannel 177 testHookDialChannel = func() { time.Sleep(2 * T) } 178 defer func() { testHookDialChannel = origTestHookDialChannel }() 179 if runtime.GOOS == "plan9" { 180 break 181 } 182 fallthrough 183 default: 184 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { 185 time.Sleep(2 * T) 186 return nil, errTimeout 187 }) 188 defer sw.Set(socktest.FilterConnect, nil) 189 } 190 191 before := sw.Sockets() 192 const N = 100 193 var wg sync.WaitGroup 194 wg.Add(N) 195 for i := 0; i < N; i++ { 196 go func() { 197 defer wg.Done() 198 // This dial never starts to send any SYN 199 // segment because of above socket filter and 200 // test hook. 201 c, err := DialTimeout("tcp", "127.0.0.1:0", T) 202 if err == nil { 203 t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr()) 204 c.Close() 205 } 206 }() 207 } 208 wg.Wait() 209 after := sw.Sockets() 210 if len(after) != len(before) { 211 t.Errorf("got %d; want %d", len(after), len(before)) 212 } 213 } 214 215 func TestDialerDualStackFDLeak(t *testing.T) { 216 switch runtime.GOOS { 217 case "plan9": 218 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 219 case "windows": 220 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) 221 } 222 if !supportsIPv4 || !supportsIPv6 { 223 t.Skip("ipv4 or ipv6 is not supported") 224 } 225 226 origTestHookLookupIP := testHookLookupIP 227 defer func() { testHookLookupIP = origTestHookLookupIP }() 228 testHookLookupIP = lookupLocalhost 229 handler := func(dss *dualStackServer, ln Listener) { 230 for { 231 c, err := ln.Accept() 232 if err != nil { 233 return 234 } 235 c.Close() 236 } 237 } 238 dss, err := newDualStackServer([]streamListener{ 239 {network: "tcp4", address: "127.0.0.1"}, 240 {network: "tcp6", address: "::1"}, 241 }) 242 if err != nil { 243 t.Fatal(err) 244 } 245 defer dss.teardown() 246 if err := dss.buildup(handler); err != nil { 247 t.Fatal(err) 248 } 249 250 before := sw.Sockets() 251 const T = 100 * time.Millisecond 252 const N = 10 253 var wg sync.WaitGroup 254 wg.Add(N) 255 d := &Dialer{DualStack: true, Timeout: T} 256 for i := 0; i < N; i++ { 257 go func() { 258 defer wg.Done() 259 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 260 if err != nil { 261 t.Error(err) 262 return 263 } 264 c.Close() 265 }() 266 } 267 wg.Wait() 268 time.Sleep(2 * T) // wait for the dial racers to stop 269 after := sw.Sockets() 270 if len(after) != len(before) { 271 t.Errorf("got %d; want %d", len(after), len(before)) 272 } 273 } 274 275 func TestDialerLocalAddr(t *testing.T) { 276 ch := make(chan error, 1) 277 handler := func(ls *localServer, ln Listener) { 278 c, err := ln.Accept() 279 if err != nil { 280 ch <- fmt.Errorf("Accept failed: %v", err) 281 return 282 } 283 defer c.Close() 284 ch <- nil 285 } 286 ls, err := newLocalServer("tcp") 287 if err != nil { 288 t.Fatal(err) 289 } 290 defer ls.teardown() 291 if err := ls.buildup(handler); err != nil { 292 t.Fatal(err) 293 } 294 295 laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) 296 if err != nil { 297 t.Fatalf("ResolveTCPAddr failed: %v", err) 298 } 299 laddr.Port = 0 300 d := &Dialer{LocalAddr: laddr} 301 c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String()) 302 if err != nil { 303 t.Fatalf("Dial failed: %v", err) 304 } 305 defer c.Close() 306 c.Read(make([]byte, 1)) 307 err = <-ch 308 if err != nil { 309 t.Error(err) 310 } 311 } 312 313 func TestDialerDualStack(t *testing.T) { 314 if !supportsIPv4 || !supportsIPv6 { 315 t.Skip("ipv4 or ipv6 is not supported") 316 } 317 318 origTestHookLookupIP := testHookLookupIP 319 defer func() { testHookLookupIP = origTestHookLookupIP }() 320 testHookLookupIP = lookupLocalhost 321 handler := func(dss *dualStackServer, ln Listener) { 322 for { 323 c, err := ln.Accept() 324 if err != nil { 325 return 326 } 327 c.Close() 328 } 329 } 330 dss, err := newDualStackServer([]streamListener{ 331 {network: "tcp4", address: "127.0.0.1"}, 332 {network: "tcp6", address: "::1"}, 333 }) 334 if err != nil { 335 t.Fatal(err) 336 } 337 defer dss.teardown() 338 if err := dss.buildup(handler); err != nil { 339 t.Fatal(err) 340 } 341 342 const T = 100 * time.Millisecond 343 d := &Dialer{DualStack: true, Timeout: T} 344 for range dss.lns { 345 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 346 if err != nil { 347 t.Error(err) 348 continue 349 } 350 switch addr := c.LocalAddr().(*TCPAddr); { 351 case addr.IP.To4() != nil: 352 dss.teardownNetwork("tcp4") 353 case addr.IP.To16() != nil && addr.IP.To4() == nil: 354 dss.teardownNetwork("tcp6") 355 } 356 c.Close() 357 } 358 time.Sleep(2 * T) // wait for the dial racers to stop 359 } 360 361 func TestDialerKeepAlive(t *testing.T) { 362 handler := func(ls *localServer, ln Listener) { 363 for { 364 c, err := ln.Accept() 365 if err != nil { 366 return 367 } 368 c.Close() 369 } 370 } 371 ls, err := newLocalServer("tcp") 372 if err != nil { 373 t.Fatal(err) 374 } 375 defer ls.teardown() 376 if err := ls.buildup(handler); err != nil { 377 t.Fatal(err) 378 } 379 defer func() { 380 testHookSetKeepAlive = func() {} 381 }() 382 383 for _, keepAlive := range []bool{false, true} { 384 got := false 385 testHookSetKeepAlive = func() { got = true } 386 var d Dialer 387 if keepAlive { 388 d.KeepAlive = 30 * time.Second 389 } 390 c, err := d.Dial("tcp", ls.Listener.Addr().String()) 391 if err != nil { 392 t.Fatal(err) 393 } 394 c.Close() 395 if got != keepAlive { 396 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got) 397 } 398 } 399 }