Home | History | Annotate | Download | only in 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 package net
      6 
      7 import (
      8 	"fmt"
      9 	"io"
     10 	"io/ioutil"
     11 	"net/internal/socktest"
     12 	"os"
     13 	"runtime"
     14 	"testing"
     15 	"time"
     16 )
     17 
     18 func (e *OpError) isValid() error {
     19 	if e.Op == "" {
     20 		return fmt.Errorf("OpError.Op is empty: %v", e)
     21 	}
     22 	if e.Net == "" {
     23 		return fmt.Errorf("OpError.Net is empty: %v", e)
     24 	}
     25 	for _, addr := range []Addr{e.Source, e.Addr} {
     26 		switch addr := addr.(type) {
     27 		case nil:
     28 		case *TCPAddr:
     29 			if addr == nil {
     30 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     31 			}
     32 		case *UDPAddr:
     33 			if addr == nil {
     34 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     35 			}
     36 		case *IPAddr:
     37 			if addr == nil {
     38 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     39 			}
     40 		case *IPNet:
     41 			if addr == nil {
     42 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     43 			}
     44 		case *UnixAddr:
     45 			if addr == nil {
     46 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     47 			}
     48 		case *pipeAddr:
     49 			if addr == nil {
     50 				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
     51 			}
     52 		case fileAddr:
     53 			if addr == "" {
     54 				return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e)
     55 			}
     56 		default:
     57 			return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
     58 		}
     59 	}
     60 	if e.Err == nil {
     61 		return fmt.Errorf("OpError.Err is empty: %v", e)
     62 	}
     63 	return nil
     64 }
     65 
     66 // parseDialError parses nestedErr and reports whether it is a valid
     67 // error value from Dial, Listen functions.
     68 // It returns nil when nestedErr is valid.
     69 func parseDialError(nestedErr error) error {
     70 	if nestedErr == nil {
     71 		return nil
     72 	}
     73 
     74 	switch err := nestedErr.(type) {
     75 	case *OpError:
     76 		if err := err.isValid(); err != nil {
     77 			return err
     78 		}
     79 		nestedErr = err.Err
     80 		goto second
     81 	}
     82 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
     83 
     84 second:
     85 	if isPlatformError(nestedErr) {
     86 		return nil
     87 	}
     88 	switch err := nestedErr.(type) {
     89 	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
     90 		return nil
     91 	case *os.SyscallError:
     92 		nestedErr = err.Err
     93 		goto third
     94 	}
     95 	switch nestedErr {
     96 	case errClosing, errMissingAddress:
     97 		return nil
     98 	}
     99 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    100 
    101 third:
    102 	if isPlatformError(nestedErr) {
    103 		return nil
    104 	}
    105 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    106 }
    107 
    108 var dialErrorTests = []struct {
    109 	network, address string
    110 }{
    111 	{"foo", ""},
    112 	{"bar", "baz"},
    113 	{"datakit", "mh/astro/r70"},
    114 	{"tcp", ""},
    115 	{"tcp", "127.0.0.1:"},
    116 	{"tcp", "no-such-name:80"},
    117 	{"tcp", "mh/astro/r70:http"},
    118 
    119 	{"tcp", "127.0.0.1:0"},
    120 	{"udp", "127.0.0.1:0"},
    121 	{"ip:icmp", "127.0.0.1"},
    122 
    123 	{"unix", "/path/to/somewhere"},
    124 	{"unixgram", "/path/to/somewhere"},
    125 	{"unixpacket", "/path/to/somewhere"},
    126 }
    127 
    128 func TestDialError(t *testing.T) {
    129 	switch runtime.GOOS {
    130 	case "plan9":
    131 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
    132 	}
    133 
    134 	origTestHookLookupIP := testHookLookupIP
    135 	defer func() { testHookLookupIP = origTestHookLookupIP }()
    136 	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
    137 		return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
    138 	}
    139 	sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
    140 		return nil, errOpNotSupported
    141 	})
    142 	defer sw.Set(socktest.FilterConnect, nil)
    143 
    144 	d := Dialer{Timeout: someTimeout}
    145 	for i, tt := range dialErrorTests {
    146 		c, err := d.Dial(tt.network, tt.address)
    147 		if err == nil {
    148 			t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
    149 			c.Close()
    150 			continue
    151 		}
    152 		if c != nil {
    153 			t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
    154 		}
    155 		if err = parseDialError(err); err != nil {
    156 			t.Errorf("#%d: %v", i, err)
    157 			continue
    158 		}
    159 	}
    160 }
    161 
    162 func TestProtocolDialError(t *testing.T) {
    163 	switch runtime.GOOS {
    164 	case "nacl", "solaris":
    165 		t.Skipf("not supported on %s", runtime.GOOS)
    166 	}
    167 
    168 	for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
    169 		var err error
    170 		switch network {
    171 		case "tcp":
    172 			_, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16})
    173 		case "udp":
    174 			_, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16})
    175 		case "ip:4294967296":
    176 			_, err = DialIP(network, nil, nil)
    177 		case "unix", "unixpacket", "unixgram":
    178 			_, err = DialUnix(network, nil, &UnixAddr{Name: "//"})
    179 		}
    180 		if err == nil {
    181 			t.Errorf("%s: should fail", network)
    182 			continue
    183 		}
    184 		if err = parseDialError(err); err != nil {
    185 			t.Errorf("%s: %v", network, err)
    186 			continue
    187 		}
    188 	}
    189 }
    190 
    191 var listenErrorTests = []struct {
    192 	network, address string
    193 }{
    194 	{"foo", ""},
    195 	{"bar", "baz"},
    196 	{"datakit", "mh/astro/r70"},
    197 	{"tcp", "127.0.0.1:"},
    198 	{"tcp", "no-such-name:80"},
    199 	{"tcp", "mh/astro/r70:http"},
    200 
    201 	{"tcp", "127.0.0.1:0"},
    202 
    203 	{"unix", "/path/to/somewhere"},
    204 	{"unixpacket", "/path/to/somewhere"},
    205 }
    206 
    207 func TestListenError(t *testing.T) {
    208 	switch runtime.GOOS {
    209 	case "plan9":
    210 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
    211 	}
    212 
    213 	origTestHookLookupIP := testHookLookupIP
    214 	defer func() { testHookLookupIP = origTestHookLookupIP }()
    215 	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
    216 		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
    217 	}
    218 	sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
    219 		return nil, errOpNotSupported
    220 	})
    221 	defer sw.Set(socktest.FilterListen, nil)
    222 
    223 	for i, tt := range listenErrorTests {
    224 		ln, err := Listen(tt.network, tt.address)
    225 		if err == nil {
    226 			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
    227 			ln.Close()
    228 			continue
    229 		}
    230 		if ln != nil {
    231 			t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
    232 		}
    233 		if err = parseDialError(err); err != nil {
    234 			t.Errorf("#%d: %v", i, err)
    235 			continue
    236 		}
    237 	}
    238 }
    239 
    240 var listenPacketErrorTests = []struct {
    241 	network, address string
    242 }{
    243 	{"foo", ""},
    244 	{"bar", "baz"},
    245 	{"datakit", "mh/astro/r70"},
    246 	{"udp", "127.0.0.1:"},
    247 	{"udp", "no-such-name:80"},
    248 	{"udp", "mh/astro/r70:http"},
    249 }
    250 
    251 func TestListenPacketError(t *testing.T) {
    252 	switch runtime.GOOS {
    253 	case "plan9":
    254 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
    255 	}
    256 
    257 	origTestHookLookupIP := testHookLookupIP
    258 	defer func() { testHookLookupIP = origTestHookLookupIP }()
    259 	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
    260 		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
    261 	}
    262 
    263 	for i, tt := range listenPacketErrorTests {
    264 		c, err := ListenPacket(tt.network, tt.address)
    265 		if err == nil {
    266 			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
    267 			c.Close()
    268 			continue
    269 		}
    270 		if c != nil {
    271 			t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c)
    272 		}
    273 		if err = parseDialError(err); err != nil {
    274 			t.Errorf("#%d: %v", i, err)
    275 			continue
    276 		}
    277 	}
    278 }
    279 
    280 func TestProtocolListenError(t *testing.T) {
    281 	switch runtime.GOOS {
    282 	case "nacl", "plan9":
    283 		t.Skipf("not supported on %s", runtime.GOOS)
    284 	}
    285 
    286 	for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
    287 		var err error
    288 		switch network {
    289 		case "tcp":
    290 			_, err = ListenTCP(network, &TCPAddr{Port: 1 << 16})
    291 		case "udp":
    292 			_, err = ListenUDP(network, &UDPAddr{Port: 1 << 16})
    293 		case "ip:4294967296":
    294 			_, err = ListenIP(network, nil)
    295 		case "unix", "unixpacket":
    296 			_, err = ListenUnix(network, &UnixAddr{Name: "//"})
    297 		case "unixgram":
    298 			_, err = ListenUnixgram(network, &UnixAddr{Name: "//"})
    299 		}
    300 		if err == nil {
    301 			t.Errorf("%s: should fail", network)
    302 			continue
    303 		}
    304 		if err = parseDialError(err); err != nil {
    305 			t.Errorf("%s: %v", network, err)
    306 			continue
    307 		}
    308 	}
    309 }
    310 
    311 // parseReadError parses nestedErr and reports whether it is a valid
    312 // error value from Read functions.
    313 // It returns nil when nestedErr is valid.
    314 func parseReadError(nestedErr error) error {
    315 	if nestedErr == nil {
    316 		return nil
    317 	}
    318 
    319 	switch err := nestedErr.(type) {
    320 	case *OpError:
    321 		if err := err.isValid(); err != nil {
    322 			return err
    323 		}
    324 		nestedErr = err.Err
    325 		goto second
    326 	}
    327 	if nestedErr == io.EOF {
    328 		return nil
    329 	}
    330 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
    331 
    332 second:
    333 	if isPlatformError(nestedErr) {
    334 		return nil
    335 	}
    336 	switch err := nestedErr.(type) {
    337 	case *os.SyscallError:
    338 		nestedErr = err.Err
    339 		goto third
    340 	}
    341 	switch nestedErr {
    342 	case errClosing, errTimeout:
    343 		return nil
    344 	}
    345 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    346 
    347 third:
    348 	if isPlatformError(nestedErr) {
    349 		return nil
    350 	}
    351 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    352 }
    353 
    354 // parseWriteError parses nestedErr and reports whether it is a valid
    355 // error value from Write functions.
    356 // It returns nil when nestedErr is valid.
    357 func parseWriteError(nestedErr error) error {
    358 	if nestedErr == nil {
    359 		return nil
    360 	}
    361 
    362 	switch err := nestedErr.(type) {
    363 	case *OpError:
    364 		if err := err.isValid(); err != nil {
    365 			return err
    366 		}
    367 		nestedErr = err.Err
    368 		goto second
    369 	}
    370 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
    371 
    372 second:
    373 	if isPlatformError(nestedErr) {
    374 		return nil
    375 	}
    376 	switch err := nestedErr.(type) {
    377 	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
    378 		return nil
    379 	case *os.SyscallError:
    380 		nestedErr = err.Err
    381 		goto third
    382 	}
    383 	switch nestedErr {
    384 	case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
    385 		return nil
    386 	}
    387 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    388 
    389 third:
    390 	if isPlatformError(nestedErr) {
    391 		return nil
    392 	}
    393 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    394 }
    395 
    396 // parseCloseError parses nestedErr and reports whether it is a valid
    397 // error value from Close functions.
    398 // It returns nil when nestedErr is valid.
    399 func parseCloseError(nestedErr error) error {
    400 	if nestedErr == nil {
    401 		return nil
    402 	}
    403 
    404 	switch err := nestedErr.(type) {
    405 	case *OpError:
    406 		if err := err.isValid(); err != nil {
    407 			return err
    408 		}
    409 		nestedErr = err.Err
    410 		goto second
    411 	}
    412 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
    413 
    414 second:
    415 	if isPlatformError(nestedErr) {
    416 		return nil
    417 	}
    418 	switch err := nestedErr.(type) {
    419 	case *os.SyscallError:
    420 		nestedErr = err.Err
    421 		goto third
    422 	case *os.PathError: // for Plan 9
    423 		nestedErr = err.Err
    424 		goto third
    425 	}
    426 	switch nestedErr {
    427 	case errClosing:
    428 		return nil
    429 	}
    430 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    431 
    432 third:
    433 	if isPlatformError(nestedErr) {
    434 		return nil
    435 	}
    436 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    437 }
    438 
    439 func TestCloseError(t *testing.T) {
    440 	ln, err := newLocalListener("tcp")
    441 	if err != nil {
    442 		t.Fatal(err)
    443 	}
    444 	defer ln.Close()
    445 	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
    446 	if err != nil {
    447 		t.Fatal(err)
    448 	}
    449 	defer c.Close()
    450 
    451 	for i := 0; i < 3; i++ {
    452 		err = c.(*TCPConn).CloseRead()
    453 		if perr := parseCloseError(err); perr != nil {
    454 			t.Errorf("#%d: %v", i, perr)
    455 		}
    456 	}
    457 	for i := 0; i < 3; i++ {
    458 		err = c.(*TCPConn).CloseWrite()
    459 		if perr := parseCloseError(err); perr != nil {
    460 			t.Errorf("#%d: %v", i, perr)
    461 		}
    462 	}
    463 	for i := 0; i < 3; i++ {
    464 		err = c.Close()
    465 		if perr := parseCloseError(err); perr != nil {
    466 			t.Errorf("#%d: %v", i, perr)
    467 		}
    468 		err = ln.Close()
    469 		if perr := parseCloseError(err); perr != nil {
    470 			t.Errorf("#%d: %v", i, perr)
    471 		}
    472 	}
    473 
    474 	pc, err := ListenPacket("udp", "127.0.0.1:0")
    475 	if err != nil {
    476 		t.Fatal(err)
    477 	}
    478 	defer pc.Close()
    479 
    480 	for i := 0; i < 3; i++ {
    481 		err = pc.Close()
    482 		if perr := parseCloseError(err); perr != nil {
    483 			t.Errorf("#%d: %v", i, perr)
    484 		}
    485 	}
    486 }
    487 
    488 // parseAcceptError parses nestedErr and reports whether it is a valid
    489 // error value from Accept functions.
    490 // It returns nil when nestedErr is valid.
    491 func parseAcceptError(nestedErr error) error {
    492 	if nestedErr == nil {
    493 		return nil
    494 	}
    495 
    496 	switch err := nestedErr.(type) {
    497 	case *OpError:
    498 		if err := err.isValid(); err != nil {
    499 			return err
    500 		}
    501 		nestedErr = err.Err
    502 		goto second
    503 	}
    504 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
    505 
    506 second:
    507 	if isPlatformError(nestedErr) {
    508 		return nil
    509 	}
    510 	switch err := nestedErr.(type) {
    511 	case *os.SyscallError:
    512 		nestedErr = err.Err
    513 		goto third
    514 	}
    515 	switch nestedErr {
    516 	case errClosing, errTimeout:
    517 		return nil
    518 	}
    519 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    520 
    521 third:
    522 	if isPlatformError(nestedErr) {
    523 		return nil
    524 	}
    525 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    526 }
    527 
    528 func TestAcceptError(t *testing.T) {
    529 	handler := func(ls *localServer, ln Listener) {
    530 		for {
    531 			ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
    532 			c, err := ln.Accept()
    533 			if perr := parseAcceptError(err); perr != nil {
    534 				t.Error(perr)
    535 			}
    536 			if err != nil {
    537 				if c != nil {
    538 					t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c)
    539 				}
    540 				if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) {
    541 					return
    542 				}
    543 				continue
    544 			}
    545 			c.Close()
    546 		}
    547 	}
    548 	ls, err := newLocalServer("tcp")
    549 	if err != nil {
    550 		t.Fatal(err)
    551 	}
    552 	if err := ls.buildup(handler); err != nil {
    553 		ls.teardown()
    554 		t.Fatal(err)
    555 	}
    556 
    557 	time.Sleep(100 * time.Millisecond)
    558 	ls.teardown()
    559 }
    560 
    561 // parseCommonError parses nestedErr and reports whether it is a valid
    562 // error value from miscellaneous functions.
    563 // It returns nil when nestedErr is valid.
    564 func parseCommonError(nestedErr error) error {
    565 	if nestedErr == nil {
    566 		return nil
    567 	}
    568 
    569 	switch err := nestedErr.(type) {
    570 	case *OpError:
    571 		if err := err.isValid(); err != nil {
    572 			return err
    573 		}
    574 		nestedErr = err.Err
    575 		goto second
    576 	}
    577 	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
    578 
    579 second:
    580 	if isPlatformError(nestedErr) {
    581 		return nil
    582 	}
    583 	switch err := nestedErr.(type) {
    584 	case *os.SyscallError:
    585 		nestedErr = err.Err
    586 		goto third
    587 	case *os.LinkError:
    588 		nestedErr = err.Err
    589 		goto third
    590 	case *os.PathError:
    591 		nestedErr = err.Err
    592 		goto third
    593 	}
    594 	switch nestedErr {
    595 	case errClosing:
    596 		return nil
    597 	}
    598 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
    599 
    600 third:
    601 	if isPlatformError(nestedErr) {
    602 		return nil
    603 	}
    604 	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
    605 }
    606 
    607 func TestFileError(t *testing.T) {
    608 	switch runtime.GOOS {
    609 	case "windows":
    610 		t.Skipf("not supported on %s", runtime.GOOS)
    611 	}
    612 
    613 	f, err := ioutil.TempFile("", "go-nettest")
    614 	if err != nil {
    615 		t.Fatal(err)
    616 	}
    617 	defer os.Remove(f.Name())
    618 	defer f.Close()
    619 
    620 	c, err := FileConn(f)
    621 	if err != nil {
    622 		if c != nil {
    623 			t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
    624 		}
    625 		if perr := parseCommonError(err); perr != nil {
    626 			t.Error(perr)
    627 		}
    628 	} else {
    629 		c.Close()
    630 		t.Error("should fail")
    631 	}
    632 	ln, err := FileListener(f)
    633 	if err != nil {
    634 		if ln != nil {
    635 			t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
    636 		}
    637 		if perr := parseCommonError(err); perr != nil {
    638 			t.Error(perr)
    639 		}
    640 	} else {
    641 		ln.Close()
    642 		t.Error("should fail")
    643 	}
    644 	pc, err := FilePacketConn(f)
    645 	if err != nil {
    646 		if pc != nil {
    647 			t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
    648 		}
    649 		if perr := parseCommonError(err); perr != nil {
    650 			t.Error(perr)
    651 		}
    652 	} else {
    653 		pc.Close()
    654 		t.Error("should fail")
    655 	}
    656 
    657 	ln, err = newLocalListener("tcp")
    658 	if err != nil {
    659 		t.Fatal(err)
    660 	}
    661 
    662 	for i := 0; i < 3; i++ {
    663 		f, err := ln.(*TCPListener).File()
    664 		if err != nil {
    665 			if perr := parseCommonError(err); perr != nil {
    666 				t.Error(perr)
    667 			}
    668 		} else {
    669 			f.Close()
    670 		}
    671 		ln.Close()
    672 	}
    673 }
    674