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  }