...
Run Format

Source file src/net/error_test.go

Documentation: net

     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  
     7  package net
     8  
     9  import (
    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  
    23  func (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.
    74  func 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  
    89  second:
    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  
   110  third:
   111  	if isPlatformError(nestedErr) {
   112  		return nil
   113  	}
   114  	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
   115  }
   116  
   117  var 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  
   139  func 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) ([]IPAddr, error), 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  
   186  func TestProtocolDialError(t *testing.T) {
   187  	switch runtime.GOOS {
   188  	case "nacl", "solaris":
   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  
   215  func TestDialAddrError(t *testing.T) {
   216  	switch runtime.GOOS {
   217  	case "nacl", "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  
   271  var 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  
   288  func 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) ([]IPAddr, error), 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  
   334  var 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  
   348  func 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) ([]IPAddr, error), 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  
   377  func TestProtocolListenError(t *testing.T) {
   378  	switch runtime.GOOS {
   379  	case "nacl", "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.
   411  func 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  
   429  second:
   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:
   440  		return nil
   441  	}
   442  	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
   443  
   444  third:
   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.
   454  func 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  
   469  second:
   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  
   486  third:
   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.
   496  func 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  
   521  second:
   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  
   539  third:
   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  
   550  func 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.
   602  func 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  
   617  second:
   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:
   631  		return nil
   632  	}
   633  	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
   634  
   635  third:
   636  	if isPlatformError(nestedErr) {
   637  		return nil
   638  	}
   639  	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
   640  }
   641  
   642  func 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.
   678  func 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  
   693  second:
   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  
   714  third:
   715  	if isPlatformError(nestedErr) {
   716  		return nil
   717  	}
   718  	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
   719  }
   720  
   721  func 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  
   789  func 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  

View as plain text