Source file src/net/error_test.go

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

View as plain text