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