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.
16 "net/internal/socktest"
24 func (e
*OpError
) isValid() error
{
26 return fmt
.Errorf("OpError.Op is empty: %v", e
)
29 return fmt
.Errorf("OpError.Net is empty: %v", e
)
31 for _
, addr
:= range []Addr
{e
.Source
, e
.Addr
} {
32 switch addr
:= addr
.(type) {
36 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
40 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
44 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
48 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
52 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
56 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
60 return fmt
.Errorf("OpError.Source or Addr is empty: %#v, %v", addr
, e
)
63 return fmt
.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr
, e
)
67 return fmt
.Errorf("OpError.Err is empty: %v", e
)
72 // parseDialError parses nestedErr and reports whether it is a valid
73 // error value from Dial, Listen functions.
74 // It returns nil when nestedErr is valid.
75 func parseDialError(nestedErr error
) error
{
80 switch err
:= nestedErr
.(type) {
82 if err
:= err
.isValid(); err
!= nil {
88 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
91 if isPlatformError(nestedErr
) {
94 switch err
:= nestedErr
.(type) {
95 case *AddrError
, addrinfoErrno
, *timeoutError
, *DNSError
, InvalidAddrError
, *ParseError
, *poll
.DeadlineExceededError
, UnknownNetworkError
:
97 case *os
.SyscallError
:
100 case *fs
.PathError
: // for Plan 9
105 case errCanceled
, ErrClosed
, errMissingAddress
, errNoSuitableAddress
,
106 context
.DeadlineExceeded
, context
.Canceled
:
109 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
112 if isPlatformError(nestedErr
) {
115 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
118 var dialErrorTests
= []struct {
119 network
, address
string
123 {"datakit", "mh/astro/r70"},
125 {"tcp", "127.0.0.1:☺"},
126 {"tcp", "no-such-name:80"},
127 {"tcp", "mh/astro/r70:http"},
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"},
135 {"unix", "/path/to/somewhere"},
136 {"unixgram", "/path/to/somewhere"},
137 {"unixpacket", "/path/to/somewhere"},
140 func TestDialError(t
*testing
.T
) {
141 switch runtime
.GOOS
{
143 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
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}
151 sw
.Set(socktest
.FilterConnect
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
152 return nil, errOpNotSupported
154 defer sw
.Set(socktest
.FilterConnect
, nil)
156 d
:= Dialer
{Timeout
: someTimeout
}
157 for i
, tt
:= range dialErrorTests
{
158 c
, err
:= d
.Dial(tt
.network
, tt
.address
)
160 t
.Errorf("#%d: should fail; %s:%s->%s", i
, c
.LocalAddr().Network(), c
.LocalAddr(), c
.RemoteAddr())
164 if tt
.network
== "tcp" || tt
.network
== "udp" {
166 if op
, ok
:= nerr
.(*OpError
); ok
{
169 if sys
, ok
:= nerr
.(*os
.SyscallError
); ok
{
172 if nerr
== errOpNotSupported
{
173 t
.Errorf("#%d: should fail without %v; %s:%s->", i
, nerr
, tt
.network
, tt
.address
)
178 t
.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c
, c
)
180 if err
= parseDialError(err
); err
!= nil {
181 t
.Errorf("#%d: %v", i
, err
)
187 func TestProtocolDialError(t
*testing
.T
) {
188 switch runtime
.GOOS
{
189 case "solaris", "illumos":
190 t
.Skipf("not supported on %s", runtime
.GOOS
)
193 for _
, network
:= range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
197 _
, err
= DialTCP(network
, nil, &TCPAddr
{Port
: 1 << 16})
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
: "//"})
206 t
.Errorf("%s: should fail", network
)
209 if err
= parseDialError(err
); err
!= nil {
210 t
.Errorf("%s: %v", network
, err
)
216 func TestDialAddrError(t
*testing
.T
) {
217 switch runtime
.GOOS
{
219 t
.Skipf("not supported on %s", runtime
.GOOS
)
221 if !supportsIPv4() ||
!supportsIPv6() {
222 t
.Skip("both IPv4 and IPv6 are required")
225 for _
, tt
:= range []struct {
230 {"tcp4", "::1", nil},
231 {"tcp4", "", &TCPAddr
{IP
: IPv6loopback
}},
232 // We don't test the {"tcp6", "byte sequence", nil}
233 // case for now because there is no easy way to
234 // control name resolution.
235 {"tcp6", "", &TCPAddr
{IP
: IP
{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}},
241 c
, err
= Dial(tt
.network
, JoinHostPort(tt
.lit
, "0"))
242 op
= fmt
.Sprintf("Dial(%q, %q)", tt
.network
, JoinHostPort(tt
.lit
, "0"))
244 c
, err
= DialTCP(tt
.network
, nil, tt
.addr
)
245 op
= fmt
.Sprintf("DialTCP(%q, %q)", tt
.network
, tt
.addr
)
249 t
.Errorf("%s succeeded, want error", op
)
252 if perr
:= parseDialError(err
); perr
!= nil {
253 t
.Errorf("%s: %v", op
, perr
)
256 operr
:= err
.(*OpError
).Err
257 aerr
, ok
:= operr
.(*AddrError
)
259 t
.Errorf("%s: %v is %T, want *AddrError", op
, err
, operr
)
264 want
= tt
.addr
.IP
.String()
266 if aerr
.Addr
!= want
{
267 t
.Errorf("%s: %v, error Addr=%q, want %q", op
, err
, aerr
.Addr
, want
)
272 var listenErrorTests
= []struct {
273 network
, address
string
277 {"datakit", "mh/astro/r70"},
278 {"tcp", "127.0.0.1:☺"},
279 {"tcp", "no-such-name:80"},
280 {"tcp", "mh/astro/r70:http"},
282 {"tcp", JoinHostPort("127.0.0.1", "-1")},
283 {"tcp", JoinHostPort("127.0.0.1", "123456789")},
285 {"unix", "/path/to/somewhere"},
286 {"unixpacket", "/path/to/somewhere"},
289 func TestListenError(t
*testing
.T
) {
290 switch runtime
.GOOS
{
292 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
295 origTestHookLookupIP
:= testHookLookupIP
296 defer func() { testHookLookupIP
= origTestHookLookupIP
}()
297 testHookLookupIP
= func(_ context
.Context
, fn
func(context
.Context
, string, string) ([]IPAddr
, error
), network
, host
string) ([]IPAddr
, error
) {
298 return nil, &DNSError
{Err
: "listen error test", Name
: "name", Server
: "server", IsTimeout
: true}
300 sw
.Set(socktest
.FilterListen
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
301 return nil, errOpNotSupported
303 defer sw
.Set(socktest
.FilterListen
, nil)
305 for i
, tt
:= range listenErrorTests
{
306 ln
, err
:= Listen(tt
.network
, tt
.address
)
308 t
.Errorf("#%d: should fail; %s:%s->", i
, ln
.Addr().Network(), ln
.Addr())
312 if tt
.network
== "tcp" {
314 if op
, ok
:= nerr
.(*OpError
); ok
{
317 if sys
, ok
:= nerr
.(*os
.SyscallError
); ok
{
320 if nerr
== errOpNotSupported
{
321 t
.Errorf("#%d: should fail without %v; %s:%s->", i
, nerr
, tt
.network
, tt
.address
)
326 t
.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln
, ln
)
328 if err
= parseDialError(err
); err
!= nil {
329 t
.Errorf("#%d: %v", i
, err
)
335 var listenPacketErrorTests
= []struct {
336 network
, address
string
340 {"datakit", "mh/astro/r70"},
341 {"udp", "127.0.0.1:☺"},
342 {"udp", "no-such-name:80"},
343 {"udp", "mh/astro/r70:http"},
345 {"udp", JoinHostPort("127.0.0.1", "-1")},
346 {"udp", JoinHostPort("127.0.0.1", "123456789")},
349 func TestListenPacketError(t
*testing
.T
) {
350 switch runtime
.GOOS
{
352 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
355 origTestHookLookupIP
:= testHookLookupIP
356 defer func() { testHookLookupIP
= origTestHookLookupIP
}()
357 testHookLookupIP
= func(_ context
.Context
, fn
func(context
.Context
, string, string) ([]IPAddr
, error
), network
, host
string) ([]IPAddr
, error
) {
358 return nil, &DNSError
{Err
: "listen error test", Name
: "name", Server
: "server", IsTimeout
: true}
361 for i
, tt
:= range listenPacketErrorTests
{
362 c
, err
:= ListenPacket(tt
.network
, tt
.address
)
364 t
.Errorf("#%d: should fail; %s:%s->", i
, c
.LocalAddr().Network(), c
.LocalAddr())
369 t
.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c
, c
)
371 if err
= parseDialError(err
); err
!= nil {
372 t
.Errorf("#%d: %v", i
, err
)
378 func TestProtocolListenError(t
*testing
.T
) {
379 switch runtime
.GOOS
{
381 t
.Skipf("not supported on %s", runtime
.GOOS
)
384 for _
, network
:= range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
388 _
, err
= ListenTCP(network
, &TCPAddr
{Port
: 1 << 16})
390 _
, err
= ListenUDP(network
, &UDPAddr
{Port
: 1 << 16})
391 case "ip:4294967296":
392 _
, err
= ListenIP(network
, nil)
393 case "unix", "unixpacket":
394 _
, err
= ListenUnix(network
, &UnixAddr
{Name
: "//"})
396 _
, err
= ListenUnixgram(network
, &UnixAddr
{Name
: "//"})
399 t
.Errorf("%s: should fail", network
)
402 if err
= parseDialError(err
); err
!= nil {
403 t
.Errorf("%s: %v", network
, err
)
409 // parseReadError parses nestedErr and reports whether it is a valid
410 // error value from Read functions.
411 // It returns nil when nestedErr is valid.
412 func parseReadError(nestedErr error
) error
{
413 if nestedErr
== nil {
417 switch err
:= nestedErr
.(type) {
419 if err
:= err
.isValid(); err
!= nil {
425 if nestedErr
== io
.EOF
{
428 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
431 if isPlatformError(nestedErr
) {
434 switch err
:= nestedErr
.(type) {
435 case *os
.SyscallError
:
440 case ErrClosed
, errTimeout
, poll
.ErrNotPollable
, os
.ErrDeadlineExceeded
:
443 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
446 if isPlatformError(nestedErr
) {
449 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
452 // parseWriteError parses nestedErr and reports whether it is a valid
453 // error value from Write functions.
454 // It returns nil when nestedErr is valid.
455 func parseWriteError(nestedErr error
) error
{
456 if nestedErr
== nil {
460 switch err
:= nestedErr
.(type) {
462 if err
:= err
.isValid(); err
!= nil {
468 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
471 if isPlatformError(nestedErr
) {
474 switch err
:= nestedErr
.(type) {
475 case *AddrError
, addrinfoErrno
, *timeoutError
, *DNSError
, InvalidAddrError
, *ParseError
, *poll
.DeadlineExceededError
, UnknownNetworkError
:
477 case *os
.SyscallError
:
482 case errCanceled
, ErrClosed
, errMissingAddress
, errTimeout
, os
.ErrDeadlineExceeded
, ErrWriteToConnected
, io
.ErrUnexpectedEOF
:
485 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
488 if isPlatformError(nestedErr
) {
491 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
494 // parseCloseError parses nestedErr and reports whether it is a valid
495 // error value from Close functions.
496 // It returns nil when nestedErr is valid.
497 func parseCloseError(nestedErr error
, isShutdown
bool) error
{
498 if nestedErr
== nil {
502 // Because historically we have not exported the error that we
503 // return for an operation on a closed network connection,
504 // there are programs that test for the exact error string.
505 // Verify that string here so that we don't break those
506 // programs unexpectedly. See issues #4373 and #19252.
507 want
:= "use of closed network connection"
508 if !isShutdown
&& !strings
.Contains(nestedErr
.Error(), want
) {
509 return fmt
.Errorf("error string %q does not contain expected string %q", nestedErr
, want
)
512 if !isShutdown
&& !errors
.Is(nestedErr
, ErrClosed
) {
513 return fmt
.Errorf("errors.Is(%v, errClosed) returns false, want true", nestedErr
)
516 switch err
:= nestedErr
.(type) {
518 if err
:= err
.isValid(); err
!= nil {
524 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
527 if isPlatformError(nestedErr
) {
530 switch err
:= nestedErr
.(type) {
531 case *os
.SyscallError
:
534 case *fs
.PathError
: // for Plan 9
542 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
545 if isPlatformError(nestedErr
) {
549 case fs
.ErrClosed
: // for Plan 9
552 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
555 func TestCloseError(t
*testing
.T
) {
556 ln
:= newLocalListener(t
, "tcp")
558 c
, err
:= Dial(ln
.Addr().Network(), ln
.Addr().String())
564 for i
:= 0; i
< 3; i
++ {
565 err
= c
.(*TCPConn
).CloseRead()
566 if perr
:= parseCloseError(err
, true); perr
!= nil {
567 t
.Errorf("#%d: %v", i
, perr
)
570 for i
:= 0; i
< 3; i
++ {
571 err
= c
.(*TCPConn
).CloseWrite()
572 if perr
:= parseCloseError(err
, true); perr
!= nil {
573 t
.Errorf("#%d: %v", i
, perr
)
576 for i
:= 0; i
< 3; i
++ {
578 if perr
:= parseCloseError(err
, false); perr
!= nil {
579 t
.Errorf("#%d: %v", i
, perr
)
582 if perr
:= parseCloseError(err
, false); perr
!= nil {
583 t
.Errorf("#%d: %v", i
, perr
)
587 pc
, err
:= ListenPacket("udp", "127.0.0.1:0")
593 for i
:= 0; i
< 3; i
++ {
595 if perr
:= parseCloseError(err
, false); perr
!= nil {
596 t
.Errorf("#%d: %v", i
, perr
)
601 // parseAcceptError parses nestedErr and reports whether it is a valid
602 // error value from Accept functions.
603 // It returns nil when nestedErr is valid.
604 func parseAcceptError(nestedErr error
) error
{
605 if nestedErr
== nil {
609 switch err
:= nestedErr
.(type) {
611 if err
:= err
.isValid(); err
!= nil {
617 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
620 if isPlatformError(nestedErr
) {
623 switch err
:= nestedErr
.(type) {
624 case *os
.SyscallError
:
627 case *fs
.PathError
: // for Plan 9
632 case ErrClosed
, errTimeout
, poll
.ErrNotPollable
, os
.ErrDeadlineExceeded
:
635 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
638 if isPlatformError(nestedErr
) {
641 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
644 func TestAcceptError(t
*testing
.T
) {
645 handler
:= func(ls
*localServer
, ln Listener
) {
647 ln
.(*TCPListener
).SetDeadline(time
.Now().Add(5 * time
.Millisecond
))
648 c
, err
:= ln
.Accept()
649 if perr
:= parseAcceptError(err
); perr
!= nil {
654 t
.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c
, c
)
656 if nerr
, ok
:= err
.(Error
); !ok ||
(!nerr
.Timeout() && !nerr
.Temporary()) {
664 ls
:= newLocalServer(t
, "tcp")
665 if err
:= ls
.buildup(handler
); err
!= nil {
670 time
.Sleep(100 * time
.Millisecond
)
674 // parseCommonError parses nestedErr and reports whether it is a valid
675 // error value from miscellaneous functions.
676 // It returns nil when nestedErr is valid.
677 func parseCommonError(nestedErr error
) error
{
678 if nestedErr
== nil {
682 switch err
:= nestedErr
.(type) {
684 if err
:= err
.isValid(); err
!= nil {
690 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
693 if isPlatformError(nestedErr
) {
696 switch err
:= nestedErr
.(type) {
697 case *os
.SyscallError
:
711 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
714 if isPlatformError(nestedErr
) {
717 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
720 func TestFileError(t
*testing
.T
) {
721 switch runtime
.GOOS
{
723 t
.Skipf("not supported on %s", runtime
.GOOS
)
726 f
, err
:= os
.CreateTemp("", "go-nettest")
730 defer os
.Remove(f
.Name())
733 c
, err
:= FileConn(f
)
736 t
.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c
, c
)
738 if perr
:= parseCommonError(err
); perr
!= nil {
743 t
.Error("should fail")
745 ln
, err
:= FileListener(f
)
748 t
.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln
, ln
)
750 if perr
:= parseCommonError(err
); perr
!= nil {
755 t
.Error("should fail")
757 pc
, err
:= FilePacketConn(f
)
760 t
.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc
, pc
)
762 if perr
:= parseCommonError(err
); perr
!= nil {
767 t
.Error("should fail")
770 ln
= newLocalListener(t
, "tcp")
772 for i
:= 0; i
< 3; i
++ {
773 f
, err
:= ln
.(*TCPListener
).File()
775 if perr
:= parseCommonError(err
); perr
!= nil {
785 func parseLookupPortError(nestedErr error
) error
{
786 if nestedErr
== nil {
790 switch nestedErr
.(type) {
791 case *AddrError
, *DNSError
:
793 case *fs
.PathError
: // for Plan 9
796 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)