1// Copyright 2015 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// +build !js 6 7package net 8 9import ( 10 "context" 11 "fmt" 12 "internal/poll" 13 "io" 14 "io/ioutil" 15 "net/internal/socktest" 16 "os" 17 "runtime" 18 "strings" 19 "testing" 20 "time" 21) 22 23func (e *OpError) isValid() error { 24 if e.Op == "" { 25 return fmt.Errorf("OpError.Op is empty: %v", e) 26 } 27 if e.Net == "" { 28 return fmt.Errorf("OpError.Net is empty: %v", e) 29 } 30 for _, addr := range []Addr{e.Source, e.Addr} { 31 switch addr := addr.(type) { 32 case nil: 33 case *TCPAddr: 34 if addr == nil { 35 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 36 } 37 case *UDPAddr: 38 if addr == nil { 39 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 40 } 41 case *IPAddr: 42 if addr == nil { 43 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 44 } 45 case *IPNet: 46 if addr == nil { 47 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 48 } 49 case *UnixAddr: 50 if addr == nil { 51 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 52 } 53 case *pipeAddr: 54 if addr == nil { 55 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) 56 } 57 case fileAddr: 58 if addr == "" { 59 return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e) 60 } 61 default: 62 return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e) 63 } 64 } 65 if e.Err == nil { 66 return fmt.Errorf("OpError.Err is empty: %v", e) 67 } 68 return nil 69} 70 71// parseDialError parses nestedErr and reports whether it is a valid 72// error value from Dial, Listen functions. 73// It returns nil when nestedErr is valid. 74func parseDialError(nestedErr error) error { 75 if nestedErr == nil { 76 return nil 77 } 78 79 switch err := nestedErr.(type) { 80 case *OpError: 81 if err := err.isValid(); err != nil { 82 return err 83 } 84 nestedErr = err.Err 85 goto second 86 } 87 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 88 89second: 90 if isPlatformError(nestedErr) { 91 return nil 92 } 93 switch err := nestedErr.(type) { 94 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError: 95 return nil 96 case *os.SyscallError: 97 nestedErr = err.Err 98 goto third 99 case *os.PathError: // for Plan 9 100 nestedErr = err.Err 101 goto third 102 } 103 switch nestedErr { 104 case errCanceled, poll.ErrNetClosing, errMissingAddress, errNoSuitableAddress, 105 context.DeadlineExceeded, context.Canceled: 106 return nil 107 } 108 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 109 110third: 111 if isPlatformError(nestedErr) { 112 return nil 113 } 114 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 115} 116 117var dialErrorTests = []struct { 118 network, address string 119}{ 120 {"foo", ""}, 121 {"bar", "baz"}, 122 {"datakit", "mh/astro/r70"}, 123 {"tcp", ""}, 124 {"tcp", "127.0.0.1:☺"}, 125 {"tcp", "no-such-name:80"}, 126 {"tcp", "mh/astro/r70:http"}, 127 128 {"tcp", JoinHostPort("127.0.0.1", "-1")}, 129 {"tcp", JoinHostPort("127.0.0.1", "123456789")}, 130 {"udp", JoinHostPort("127.0.0.1", "-1")}, 131 {"udp", JoinHostPort("127.0.0.1", "123456789")}, 132 {"ip:icmp", "127.0.0.1"}, 133 134 {"unix", "/path/to/somewhere"}, 135 {"unixgram", "/path/to/somewhere"}, 136 {"unixpacket", "/path/to/somewhere"}, 137} 138 139func TestDialError(t *testing.T) { 140 switch runtime.GOOS { 141 case "plan9": 142 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 143 } 144 145 origTestHookLookupIP := testHookLookupIP 146 defer func() { testHookLookupIP = origTestHookLookupIP }() 147 testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 148 return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true} 149 } 150 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { 151 return nil, errOpNotSupported 152 }) 153 defer sw.Set(socktest.FilterConnect, nil) 154 155 d := Dialer{Timeout: someTimeout} 156 for i, tt := range dialErrorTests { 157 c, err := d.Dial(tt.network, tt.address) 158 if err == nil { 159 t.Errorf("#%d: should fail; %s:%s->%s", i, c.LocalAddr().Network(), c.LocalAddr(), c.RemoteAddr()) 160 c.Close() 161 continue 162 } 163 if tt.network == "tcp" || tt.network == "udp" { 164 nerr := err 165 if op, ok := nerr.(*OpError); ok { 166 nerr = op.Err 167 } 168 if sys, ok := nerr.(*os.SyscallError); ok { 169 nerr = sys.Err 170 } 171 if nerr == errOpNotSupported { 172 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address) 173 continue 174 } 175 } 176 if c != nil { 177 t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c) 178 } 179 if err = parseDialError(err); err != nil { 180 t.Errorf("#%d: %v", i, err) 181 continue 182 } 183 } 184} 185 186func TestProtocolDialError(t *testing.T) { 187 switch runtime.GOOS { 188 case "solaris", "illumos": 189 t.Skipf("not supported on %s", runtime.GOOS) 190 } 191 192 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { 193 var err error 194 switch network { 195 case "tcp": 196 _, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16}) 197 case "udp": 198 _, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16}) 199 case "ip:4294967296": 200 _, err = DialIP(network, nil, nil) 201 case "unix", "unixpacket", "unixgram": 202 _, err = DialUnix(network, nil, &UnixAddr{Name: "//"}) 203 } 204 if err == nil { 205 t.Errorf("%s: should fail", network) 206 continue 207 } 208 if err = parseDialError(err); err != nil { 209 t.Errorf("%s: %v", network, err) 210 continue 211 } 212 } 213} 214 215func TestDialAddrError(t *testing.T) { 216 switch runtime.GOOS { 217 case "plan9": 218 t.Skipf("not supported on %s", runtime.GOOS) 219 } 220 if !supportsIPv4() || !supportsIPv6() { 221 t.Skip("both IPv4 and IPv6 are required") 222 } 223 224 for _, tt := range []struct { 225 network string 226 lit string 227 addr *TCPAddr 228 }{ 229 {"tcp4", "::1", nil}, 230 {"tcp4", "", &TCPAddr{IP: IPv6loopback}}, 231 // We don't test the {"tcp6", "byte sequence", nil} 232 // case for now because there is no easy way to 233 // control name resolution. 234 {"tcp6", "", &TCPAddr{IP: IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}}, 235 } { 236 var err error 237 var c Conn 238 var op string 239 if tt.lit != "" { 240 c, err = Dial(tt.network, JoinHostPort(tt.lit, "0")) 241 op = fmt.Sprintf("Dial(%q, %q)", tt.network, JoinHostPort(tt.lit, "0")) 242 } else { 243 c, err = DialTCP(tt.network, nil, tt.addr) 244 op = fmt.Sprintf("DialTCP(%q, %q)", tt.network, tt.addr) 245 } 246 if err == nil { 247 c.Close() 248 t.Errorf("%s succeeded, want error", op) 249 continue 250 } 251 if perr := parseDialError(err); perr != nil { 252 t.Errorf("%s: %v", op, perr) 253 continue 254 } 255 operr := err.(*OpError).Err 256 aerr, ok := operr.(*AddrError) 257 if !ok { 258 t.Errorf("%s: %v is %T, want *AddrError", op, err, operr) 259 continue 260 } 261 want := tt.lit 262 if tt.lit == "" { 263 want = tt.addr.IP.String() 264 } 265 if aerr.Addr != want { 266 t.Errorf("%s: %v, error Addr=%q, want %q", op, err, aerr.Addr, want) 267 } 268 } 269} 270 271var listenErrorTests = []struct { 272 network, address string 273}{ 274 {"foo", ""}, 275 {"bar", "baz"}, 276 {"datakit", "mh/astro/r70"}, 277 {"tcp", "127.0.0.1:☺"}, 278 {"tcp", "no-such-name:80"}, 279 {"tcp", "mh/astro/r70:http"}, 280 281 {"tcp", JoinHostPort("127.0.0.1", "-1")}, 282 {"tcp", JoinHostPort("127.0.0.1", "123456789")}, 283 284 {"unix", "/path/to/somewhere"}, 285 {"unixpacket", "/path/to/somewhere"}, 286} 287 288func TestListenError(t *testing.T) { 289 switch runtime.GOOS { 290 case "plan9": 291 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 292 } 293 294 origTestHookLookupIP := testHookLookupIP 295 defer func() { testHookLookupIP = origTestHookLookupIP }() 296 testHookLookupIP = func(_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 297 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} 298 } 299 sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) { 300 return nil, errOpNotSupported 301 }) 302 defer sw.Set(socktest.FilterListen, nil) 303 304 for i, tt := range listenErrorTests { 305 ln, err := Listen(tt.network, tt.address) 306 if err == nil { 307 t.Errorf("#%d: should fail; %s:%s->", i, ln.Addr().Network(), ln.Addr()) 308 ln.Close() 309 continue 310 } 311 if tt.network == "tcp" { 312 nerr := err 313 if op, ok := nerr.(*OpError); ok { 314 nerr = op.Err 315 } 316 if sys, ok := nerr.(*os.SyscallError); ok { 317 nerr = sys.Err 318 } 319 if nerr == errOpNotSupported { 320 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address) 321 continue 322 } 323 } 324 if ln != nil { 325 t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln) 326 } 327 if err = parseDialError(err); err != nil { 328 t.Errorf("#%d: %v", i, err) 329 continue 330 } 331 } 332} 333 334var listenPacketErrorTests = []struct { 335 network, address string 336}{ 337 {"foo", ""}, 338 {"bar", "baz"}, 339 {"datakit", "mh/astro/r70"}, 340 {"udp", "127.0.0.1:☺"}, 341 {"udp", "no-such-name:80"}, 342 {"udp", "mh/astro/r70:http"}, 343 344 {"udp", JoinHostPort("127.0.0.1", "-1")}, 345 {"udp", JoinHostPort("127.0.0.1", "123456789")}, 346} 347 348func TestListenPacketError(t *testing.T) { 349 switch runtime.GOOS { 350 case "plan9": 351 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 352 } 353 354 origTestHookLookupIP := testHookLookupIP 355 defer func() { testHookLookupIP = origTestHookLookupIP }() 356 testHookLookupIP = func(_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 357 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} 358 } 359 360 for i, tt := range listenPacketErrorTests { 361 c, err := ListenPacket(tt.network, tt.address) 362 if err == nil { 363 t.Errorf("#%d: should fail; %s:%s->", i, c.LocalAddr().Network(), c.LocalAddr()) 364 c.Close() 365 continue 366 } 367 if c != nil { 368 t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c) 369 } 370 if err = parseDialError(err); err != nil { 371 t.Errorf("#%d: %v", i, err) 372 continue 373 } 374 } 375} 376 377func TestProtocolListenError(t *testing.T) { 378 switch runtime.GOOS { 379 case "plan9": 380 t.Skipf("not supported on %s", runtime.GOOS) 381 } 382 383 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { 384 var err error 385 switch network { 386 case "tcp": 387 _, err = ListenTCP(network, &TCPAddr{Port: 1 << 16}) 388 case "udp": 389 _, err = ListenUDP(network, &UDPAddr{Port: 1 << 16}) 390 case "ip:4294967296": 391 _, err = ListenIP(network, nil) 392 case "unix", "unixpacket": 393 _, err = ListenUnix(network, &UnixAddr{Name: "//"}) 394 case "unixgram": 395 _, err = ListenUnixgram(network, &UnixAddr{Name: "//"}) 396 } 397 if err == nil { 398 t.Errorf("%s: should fail", network) 399 continue 400 } 401 if err = parseDialError(err); err != nil { 402 t.Errorf("%s: %v", network, err) 403 continue 404 } 405 } 406} 407 408// parseReadError parses nestedErr and reports whether it is a valid 409// error value from Read functions. 410// It returns nil when nestedErr is valid. 411func parseReadError(nestedErr error) error { 412 if nestedErr == nil { 413 return nil 414 } 415 416 switch err := nestedErr.(type) { 417 case *OpError: 418 if err := err.isValid(); err != nil { 419 return err 420 } 421 nestedErr = err.Err 422 goto second 423 } 424 if nestedErr == io.EOF { 425 return nil 426 } 427 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 428 429second: 430 if isPlatformError(nestedErr) { 431 return nil 432 } 433 switch err := nestedErr.(type) { 434 case *os.SyscallError: 435 nestedErr = err.Err 436 goto third 437 } 438 switch nestedErr { 439 case poll.ErrNetClosing, poll.ErrTimeout, poll.ErrNotPollable: 440 return nil 441 } 442 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 443 444third: 445 if isPlatformError(nestedErr) { 446 return nil 447 } 448 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 449} 450 451// parseWriteError parses nestedErr and reports whether it is a valid 452// error value from Write functions. 453// It returns nil when nestedErr is valid. 454func parseWriteError(nestedErr error) error { 455 if nestedErr == nil { 456 return nil 457 } 458 459 switch err := nestedErr.(type) { 460 case *OpError: 461 if err := err.isValid(); err != nil { 462 return err 463 } 464 nestedErr = err.Err 465 goto second 466 } 467 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 468 469second: 470 if isPlatformError(nestedErr) { 471 return nil 472 } 473 switch err := nestedErr.(type) { 474 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError: 475 return nil 476 case *os.SyscallError: 477 nestedErr = err.Err 478 goto third 479 } 480 switch nestedErr { 481 case errCanceled, poll.ErrNetClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF: 482 return nil 483 } 484 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 485 486third: 487 if isPlatformError(nestedErr) { 488 return nil 489 } 490 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 491} 492 493// parseCloseError parses nestedErr and reports whether it is a valid 494// error value from Close functions. 495// It returns nil when nestedErr is valid. 496func parseCloseError(nestedErr error, isShutdown bool) error { 497 if nestedErr == nil { 498 return nil 499 } 500 501 // Because historically we have not exported the error that we 502 // return for an operation on a closed network connection, 503 // there are programs that test for the exact error string. 504 // Verify that string here so that we don't break those 505 // programs unexpectedly. See issues #4373 and #19252. 506 want := "use of closed network connection" 507 if !isShutdown && !strings.Contains(nestedErr.Error(), want) { 508 return fmt.Errorf("error string %q does not contain expected string %q", nestedErr, want) 509 } 510 511 switch err := nestedErr.(type) { 512 case *OpError: 513 if err := err.isValid(); err != nil { 514 return err 515 } 516 nestedErr = err.Err 517 goto second 518 } 519 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 520 521second: 522 if isPlatformError(nestedErr) { 523 return nil 524 } 525 switch err := nestedErr.(type) { 526 case *os.SyscallError: 527 nestedErr = err.Err 528 goto third 529 case *os.PathError: // for Plan 9 530 nestedErr = err.Err 531 goto third 532 } 533 switch nestedErr { 534 case poll.ErrNetClosing: 535 return nil 536 } 537 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 538 539third: 540 if isPlatformError(nestedErr) { 541 return nil 542 } 543 switch nestedErr { 544 case os.ErrClosed: // for Plan 9 545 return nil 546 } 547 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 548} 549 550func TestCloseError(t *testing.T) { 551 ln, err := newLocalListener("tcp") 552 if err != nil { 553 t.Fatal(err) 554 } 555 defer ln.Close() 556 c, err := Dial(ln.Addr().Network(), ln.Addr().String()) 557 if err != nil { 558 t.Fatal(err) 559 } 560 defer c.Close() 561 562 for i := 0; i < 3; i++ { 563 err = c.(*TCPConn).CloseRead() 564 if perr := parseCloseError(err, true); perr != nil { 565 t.Errorf("#%d: %v", i, perr) 566 } 567 } 568 for i := 0; i < 3; i++ { 569 err = c.(*TCPConn).CloseWrite() 570 if perr := parseCloseError(err, true); perr != nil { 571 t.Errorf("#%d: %v", i, perr) 572 } 573 } 574 for i := 0; i < 3; i++ { 575 err = c.Close() 576 if perr := parseCloseError(err, false); perr != nil { 577 t.Errorf("#%d: %v", i, perr) 578 } 579 err = ln.Close() 580 if perr := parseCloseError(err, false); perr != nil { 581 t.Errorf("#%d: %v", i, perr) 582 } 583 } 584 585 pc, err := ListenPacket("udp", "127.0.0.1:0") 586 if err != nil { 587 t.Fatal(err) 588 } 589 defer pc.Close() 590 591 for i := 0; i < 3; i++ { 592 err = pc.Close() 593 if perr := parseCloseError(err, false); perr != nil { 594 t.Errorf("#%d: %v", i, perr) 595 } 596 } 597} 598 599// parseAcceptError parses nestedErr and reports whether it is a valid 600// error value from Accept functions. 601// It returns nil when nestedErr is valid. 602func parseAcceptError(nestedErr error) error { 603 if nestedErr == nil { 604 return nil 605 } 606 607 switch err := nestedErr.(type) { 608 case *OpError: 609 if err := err.isValid(); err != nil { 610 return err 611 } 612 nestedErr = err.Err 613 goto second 614 } 615 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 616 617second: 618 if isPlatformError(nestedErr) { 619 return nil 620 } 621 switch err := nestedErr.(type) { 622 case *os.SyscallError: 623 nestedErr = err.Err 624 goto third 625 case *os.PathError: // for Plan 9 626 nestedErr = err.Err 627 goto third 628 } 629 switch nestedErr { 630 case poll.ErrNetClosing, poll.ErrTimeout, poll.ErrNotPollable: 631 return nil 632 } 633 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 634 635third: 636 if isPlatformError(nestedErr) { 637 return nil 638 } 639 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 640} 641 642func TestAcceptError(t *testing.T) { 643 handler := func(ls *localServer, ln Listener) { 644 for { 645 ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond)) 646 c, err := ln.Accept() 647 if perr := parseAcceptError(err); perr != nil { 648 t.Error(perr) 649 } 650 if err != nil { 651 if c != nil { 652 t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c) 653 } 654 if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) { 655 return 656 } 657 continue 658 } 659 c.Close() 660 } 661 } 662 ls, err := newLocalServer("tcp") 663 if err != nil { 664 t.Fatal(err) 665 } 666 if err := ls.buildup(handler); err != nil { 667 ls.teardown() 668 t.Fatal(err) 669 } 670 671 time.Sleep(100 * time.Millisecond) 672 ls.teardown() 673} 674 675// parseCommonError parses nestedErr and reports whether it is a valid 676// error value from miscellaneous functions. 677// It returns nil when nestedErr is valid. 678func parseCommonError(nestedErr error) error { 679 if nestedErr == nil { 680 return nil 681 } 682 683 switch err := nestedErr.(type) { 684 case *OpError: 685 if err := err.isValid(); err != nil { 686 return err 687 } 688 nestedErr = err.Err 689 goto second 690 } 691 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 692 693second: 694 if isPlatformError(nestedErr) { 695 return nil 696 } 697 switch err := nestedErr.(type) { 698 case *os.SyscallError: 699 nestedErr = err.Err 700 goto third 701 case *os.LinkError: 702 nestedErr = err.Err 703 goto third 704 case *os.PathError: 705 nestedErr = err.Err 706 goto third 707 } 708 switch nestedErr { 709 case poll.ErrNetClosing: 710 return nil 711 } 712 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) 713 714third: 715 if isPlatformError(nestedErr) { 716 return nil 717 } 718 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) 719} 720 721func TestFileError(t *testing.T) { 722 switch runtime.GOOS { 723 case "windows": 724 t.Skipf("not supported on %s", runtime.GOOS) 725 } 726 727 f, err := ioutil.TempFile("", "go-nettest") 728 if err != nil { 729 t.Fatal(err) 730 } 731 defer os.Remove(f.Name()) 732 defer f.Close() 733 734 c, err := FileConn(f) 735 if err != nil { 736 if c != nil { 737 t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c) 738 } 739 if perr := parseCommonError(err); perr != nil { 740 t.Error(perr) 741 } 742 } else { 743 c.Close() 744 t.Error("should fail") 745 } 746 ln, err := FileListener(f) 747 if err != nil { 748 if ln != nil { 749 t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln) 750 } 751 if perr := parseCommonError(err); perr != nil { 752 t.Error(perr) 753 } 754 } else { 755 ln.Close() 756 t.Error("should fail") 757 } 758 pc, err := FilePacketConn(f) 759 if err != nil { 760 if pc != nil { 761 t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc) 762 } 763 if perr := parseCommonError(err); perr != nil { 764 t.Error(perr) 765 } 766 } else { 767 pc.Close() 768 t.Error("should fail") 769 } 770 771 ln, err = newLocalListener("tcp") 772 if err != nil { 773 t.Fatal(err) 774 } 775 776 for i := 0; i < 3; i++ { 777 f, err := ln.(*TCPListener).File() 778 if err != nil { 779 if perr := parseCommonError(err); perr != nil { 780 t.Error(perr) 781 } 782 } else { 783 f.Close() 784 } 785 ln.Close() 786 } 787} 788 789func parseLookupPortError(nestedErr error) error { 790 if nestedErr == nil { 791 return nil 792 } 793 794 switch nestedErr.(type) { 795 case *AddrError, *DNSError: 796 return nil 797 case *os.PathError: // for Plan 9 798 return nil 799 } 800 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) 801} 802