...

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

View as plain text