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.
15 "net/internal/socktest"
23 func (e
*OpError
) isValid() error
{
25 return fmt
.Errorf("OpError.Op is empty: %v", e
)
28 return fmt
.Errorf("OpError.Net is empty: %v", e
)
30 for _
, addr
:= range []Addr
{e
.Source
, e
.Addr
} {
31 switch addr
:= addr
.(type) {
35 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
39 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
43 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
47 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
51 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
55 return fmt
.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr
, e
)
59 return fmt
.Errorf("OpError.Source or Addr is empty: %#v, %v", addr
, e
)
62 return fmt
.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr
, e
)
66 return fmt
.Errorf("OpError.Err is empty: %v", e
)
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
{
79 switch err
:= nestedErr
.(type) {
81 if err
:= err
.isValid(); err
!= nil {
87 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
90 if isPlatformError(nestedErr
) {
93 switch err
:= nestedErr
.(type) {
94 case *AddrError
, addrinfoErrno
, *DNSError
, InvalidAddrError
, *ParseError
, *poll
.TimeoutError
, UnknownNetworkError
:
96 case *os
.SyscallError
:
99 case *os
.PathError
: // for Plan 9
104 case errCanceled
, poll
.ErrNetClosing
, errMissingAddress
, errNoSuitableAddress
,
105 context
.DeadlineExceeded
, context
.Canceled
:
108 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
111 if isPlatformError(nestedErr
) {
114 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
117 var dialErrorTests
= []struct {
118 network
, address
string
122 {"datakit", "mh/astro/r70"},
124 {"tcp", "127.0.0.1:☺"},
125 {"tcp", "no-such-name:80"},
126 {"tcp", "mh/astro/r70:http"},
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"},
134 {"unix", "/path/to/somewhere"},
135 {"unixgram", "/path/to/somewhere"},
136 {"unixpacket", "/path/to/somewhere"},
139 func TestDialError(t
*testing
.T
) {
140 switch runtime
.GOOS
{
142 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
145 origTestHookLookupIP
:= testHookLookupIP
146 defer func() { testHookLookupIP
= origTestHookLookupIP
}()
147 testHookLookupIP
= func(ctx context
.Context
, fn
func(context
.Context
, string, string) ([]IPAddr
, error
), network
, host
string) ([]IPAddr
, error
) {
148 return nil, &DNSError
{Err
: "dial error test", Name
: "name", Server
: "server", IsTimeout
: true}
150 sw
.Set(socktest
.FilterConnect
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
151 return nil, errOpNotSupported
153 defer sw
.Set(socktest
.FilterConnect
, nil)
155 d
:= Dialer
{Timeout
: someTimeout
}
156 for i
, tt
:= range dialErrorTests
{
157 c
, err
:= d
.Dial(tt
.network
, tt
.address
)
159 t
.Errorf("#%d: should fail; %s:%s->%s", i
, c
.LocalAddr().Network(), c
.LocalAddr(), c
.RemoteAddr())
163 if tt
.network
== "tcp" || tt
.network
== "udp" {
165 if op
, ok
:= nerr
.(*OpError
); ok
{
168 if sys
, ok
:= nerr
.(*os
.SyscallError
); ok
{
171 if nerr
== errOpNotSupported
{
172 t
.Errorf("#%d: should fail without %v; %s:%s->", i
, nerr
, tt
.network
, tt
.address
)
177 t
.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c
, c
)
179 if err
= parseDialError(err
); err
!= nil {
180 t
.Errorf("#%d: %v", i
, err
)
186 func TestProtocolDialError(t
*testing
.T
) {
187 switch runtime
.GOOS
{
188 case "solaris", "illumos":
189 t
.Skipf("not supported on %s", runtime
.GOOS
)
192 for _
, network
:= range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
196 _
, err
= DialTCP(network
, nil, &TCPAddr
{Port
: 1 << 16})
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
: "//"})
205 t
.Errorf("%s: should fail", network
)
208 if err
= parseDialError(err
); err
!= nil {
209 t
.Errorf("%s: %v", network
, err
)
215 func TestDialAddrError(t
*testing
.T
) {
216 switch runtime
.GOOS
{
218 t
.Skipf("not supported on %s", runtime
.GOOS
)
220 if !supportsIPv4() ||
!supportsIPv6() {
221 t
.Skip("both IPv4 and IPv6 are required")
224 for _
, tt
:= range []struct {
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}}},
240 c
, err
= Dial(tt
.network
, JoinHostPort(tt
.lit
, "0"))
241 op
= fmt
.Sprintf("Dial(%q, %q)", tt
.network
, JoinHostPort(tt
.lit
, "0"))
243 c
, err
= DialTCP(tt
.network
, nil, tt
.addr
)
244 op
= fmt
.Sprintf("DialTCP(%q, %q)", tt
.network
, tt
.addr
)
248 t
.Errorf("%s succeeded, want error", op
)
251 if perr
:= parseDialError(err
); perr
!= nil {
252 t
.Errorf("%s: %v", op
, perr
)
255 operr
:= err
.(*OpError
).Err
256 aerr
, ok
:= operr
.(*AddrError
)
258 t
.Errorf("%s: %v is %T, want *AddrError", op
, err
, operr
)
263 want
= tt
.addr
.IP
.String()
265 if aerr
.Addr
!= want
{
266 t
.Errorf("%s: %v, error Addr=%q, want %q", op
, err
, aerr
.Addr
, want
)
271 var listenErrorTests
= []struct {
272 network
, address
string
276 {"datakit", "mh/astro/r70"},
277 {"tcp", "127.0.0.1:☺"},
278 {"tcp", "no-such-name:80"},
279 {"tcp", "mh/astro/r70:http"},
281 {"tcp", JoinHostPort("127.0.0.1", "-1")},
282 {"tcp", JoinHostPort("127.0.0.1", "123456789")},
284 {"unix", "/path/to/somewhere"},
285 {"unixpacket", "/path/to/somewhere"},
288 func TestListenError(t
*testing
.T
) {
289 switch runtime
.GOOS
{
291 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
294 origTestHookLookupIP
:= testHookLookupIP
295 defer func() { testHookLookupIP
= origTestHookLookupIP
}()
296 testHookLookupIP
= func(_ context
.Context
, fn
func(context
.Context
, string, string) ([]IPAddr
, error
), network
, host
string) ([]IPAddr
, error
) {
297 return nil, &DNSError
{Err
: "listen error test", Name
: "name", Server
: "server", IsTimeout
: true}
299 sw
.Set(socktest
.FilterListen
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
300 return nil, errOpNotSupported
302 defer sw
.Set(socktest
.FilterListen
, nil)
304 for i
, tt
:= range listenErrorTests
{
305 ln
, err
:= Listen(tt
.network
, tt
.address
)
307 t
.Errorf("#%d: should fail; %s:%s->", i
, ln
.Addr().Network(), ln
.Addr())
311 if tt
.network
== "tcp" {
313 if op
, ok
:= nerr
.(*OpError
); ok
{
316 if sys
, ok
:= nerr
.(*os
.SyscallError
); ok
{
319 if nerr
== errOpNotSupported
{
320 t
.Errorf("#%d: should fail without %v; %s:%s->", i
, nerr
, tt
.network
, tt
.address
)
325 t
.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln
, ln
)
327 if err
= parseDialError(err
); err
!= nil {
328 t
.Errorf("#%d: %v", i
, err
)
334 var listenPacketErrorTests
= []struct {
335 network
, address
string
339 {"datakit", "mh/astro/r70"},
340 {"udp", "127.0.0.1:☺"},
341 {"udp", "no-such-name:80"},
342 {"udp", "mh/astro/r70:http"},
344 {"udp", JoinHostPort("127.0.0.1", "-1")},
345 {"udp", JoinHostPort("127.0.0.1", "123456789")},
348 func TestListenPacketError(t
*testing
.T
) {
349 switch runtime
.GOOS
{
351 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
354 origTestHookLookupIP
:= testHookLookupIP
355 defer func() { testHookLookupIP
= origTestHookLookupIP
}()
356 testHookLookupIP
= func(_ context
.Context
, fn
func(context
.Context
, string, string) ([]IPAddr
, error
), network
, host
string) ([]IPAddr
, error
) {
357 return nil, &DNSError
{Err
: "listen error test", Name
: "name", Server
: "server", IsTimeout
: true}
360 for i
, tt
:= range listenPacketErrorTests
{
361 c
, err
:= ListenPacket(tt
.network
, tt
.address
)
363 t
.Errorf("#%d: should fail; %s:%s->", i
, c
.LocalAddr().Network(), c
.LocalAddr())
368 t
.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c
, c
)
370 if err
= parseDialError(err
); err
!= nil {
371 t
.Errorf("#%d: %v", i
, err
)
377 func TestProtocolListenError(t
*testing
.T
) {
378 switch runtime
.GOOS
{
380 t
.Skipf("not supported on %s", runtime
.GOOS
)
383 for _
, network
:= range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
387 _
, err
= ListenTCP(network
, &TCPAddr
{Port
: 1 << 16})
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
: "//"})
395 _
, err
= ListenUnixgram(network
, &UnixAddr
{Name
: "//"})
398 t
.Errorf("%s: should fail", network
)
401 if err
= parseDialError(err
); err
!= nil {
402 t
.Errorf("%s: %v", network
, err
)
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 {
416 switch err
:= nestedErr
.(type) {
418 if err
:= err
.isValid(); err
!= nil {
424 if nestedErr
== io
.EOF
{
427 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
430 if isPlatformError(nestedErr
) {
433 switch err
:= nestedErr
.(type) {
434 case *os
.SyscallError
:
439 case poll
.ErrNetClosing
, poll
.ErrTimeout
, poll
.ErrNotPollable
:
442 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
445 if isPlatformError(nestedErr
) {
448 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
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 {
459 switch err
:= nestedErr
.(type) {
461 if err
:= err
.isValid(); err
!= nil {
467 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
470 if isPlatformError(nestedErr
) {
473 switch err
:= nestedErr
.(type) {
474 case *AddrError
, addrinfoErrno
, *DNSError
, InvalidAddrError
, *ParseError
, *poll
.TimeoutError
, UnknownNetworkError
:
476 case *os
.SyscallError
:
481 case errCanceled
, poll
.ErrNetClosing
, errMissingAddress
, poll
.ErrTimeout
, ErrWriteToConnected
, io
.ErrUnexpectedEOF
:
484 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
487 if isPlatformError(nestedErr
) {
490 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
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 {
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
)
511 switch err
:= nestedErr
.(type) {
513 if err
:= err
.isValid(); err
!= nil {
519 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
522 if isPlatformError(nestedErr
) {
525 switch err
:= nestedErr
.(type) {
526 case *os
.SyscallError
:
529 case *os
.PathError
: // for Plan 9
534 case poll
.ErrNetClosing
:
537 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
540 if isPlatformError(nestedErr
) {
544 case os
.ErrClosed
: // for Plan 9
547 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
550 func TestCloseError(t
*testing
.T
) {
551 ln
, err
:= newLocalListener("tcp")
556 c
, err
:= Dial(ln
.Addr().Network(), ln
.Addr().String())
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
)
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
)
574 for i
:= 0; i
< 3; i
++ {
576 if perr
:= parseCloseError(err
, false); perr
!= nil {
577 t
.Errorf("#%d: %v", i
, perr
)
580 if perr
:= parseCloseError(err
, false); perr
!= nil {
581 t
.Errorf("#%d: %v", i
, perr
)
585 pc
, err
:= ListenPacket("udp", "127.0.0.1:0")
591 for i
:= 0; i
< 3; i
++ {
593 if perr
:= parseCloseError(err
, false); perr
!= nil {
594 t
.Errorf("#%d: %v", i
, perr
)
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 {
607 switch err
:= nestedErr
.(type) {
609 if err
:= err
.isValid(); err
!= nil {
615 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
618 if isPlatformError(nestedErr
) {
621 switch err
:= nestedErr
.(type) {
622 case *os
.SyscallError
:
625 case *os
.PathError
: // for Plan 9
630 case poll
.ErrNetClosing
, poll
.ErrTimeout
, poll
.ErrNotPollable
:
633 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
636 if isPlatformError(nestedErr
) {
639 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
642 func TestAcceptError(t
*testing
.T
) {
643 handler
:= func(ls
*localServer
, ln Listener
) {
645 ln
.(*TCPListener
).SetDeadline(time
.Now().Add(5 * time
.Millisecond
))
646 c
, err
:= ln
.Accept()
647 if perr
:= parseAcceptError(err
); perr
!= nil {
652 t
.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c
, c
)
654 if nerr
, ok
:= err
.(Error
); !ok ||
(!nerr
.Timeout() && !nerr
.Temporary()) {
662 ls
, err
:= newLocalServer("tcp")
666 if err
:= ls
.buildup(handler
); err
!= nil {
671 time
.Sleep(100 * time
.Millisecond
)
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 {
683 switch err
:= nestedErr
.(type) {
685 if err
:= err
.isValid(); err
!= nil {
691 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)
694 if isPlatformError(nestedErr
) {
697 switch err
:= nestedErr
.(type) {
698 case *os
.SyscallError
:
709 case poll
.ErrNetClosing
:
712 return fmt
.Errorf("unexpected type on 2nd nested level: %T", nestedErr
)
715 if isPlatformError(nestedErr
) {
718 return fmt
.Errorf("unexpected type on 3rd nested level: %T", nestedErr
)
721 func TestFileError(t
*testing
.T
) {
722 switch runtime
.GOOS
{
724 t
.Skipf("not supported on %s", runtime
.GOOS
)
727 f
, err
:= ioutil
.TempFile("", "go-nettest")
731 defer os
.Remove(f
.Name())
734 c
, err
:= FileConn(f
)
737 t
.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c
, c
)
739 if perr
:= parseCommonError(err
); perr
!= nil {
744 t
.Error("should fail")
746 ln
, err
:= FileListener(f
)
749 t
.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln
, ln
)
751 if perr
:= parseCommonError(err
); perr
!= nil {
756 t
.Error("should fail")
758 pc
, err
:= FilePacketConn(f
)
761 t
.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc
, pc
)
763 if perr
:= parseCommonError(err
); perr
!= nil {
768 t
.Error("should fail")
771 ln
, err
= newLocalListener("tcp")
776 for i
:= 0; i
< 3; i
++ {
777 f
, err
:= ln
.(*TCPListener
).File()
779 if perr
:= parseCommonError(err
); perr
!= nil {
789 func parseLookupPortError(nestedErr error
) error
{
790 if nestedErr
== nil {
794 switch nestedErr
.(type) {
795 case *AddrError
, *DNSError
:
797 case *os
.PathError
: // for Plan 9
800 return fmt
.Errorf("unexpected type on 1st nested level: %T", nestedErr
)