Home | History | Annotate | Download | only in net
      1 // Copyright 2014 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 	"bufio"
      9 	"fmt"
     10 	"io"
     11 	"os"
     12 	"os/exec"
     13 	"syscall"
     14 	"testing"
     15 	"time"
     16 )
     17 
     18 func toErrno(err error) (syscall.Errno, bool) {
     19 	operr, ok := err.(*OpError)
     20 	if !ok {
     21 		return 0, false
     22 	}
     23 	syserr, ok := operr.Err.(*os.SyscallError)
     24 	if !ok {
     25 		return 0, false
     26 	}
     27 	errno, ok := syserr.Err.(syscall.Errno)
     28 	if !ok {
     29 		return 0, false
     30 	}
     31 	return errno, true
     32 }
     33 
     34 // TestAcceptIgnoreSomeErrors tests that windows TCPListener.AcceptTCP
     35 // handles broken connections. It verifies that broken connections do
     36 // not affect future connections.
     37 func TestAcceptIgnoreSomeErrors(t *testing.T) {
     38 	recv := func(ln Listener, ignoreSomeReadErrors bool) (string, error) {
     39 		c, err := ln.Accept()
     40 		if err != nil {
     41 			// Display windows errno in error message.
     42 			errno, ok := toErrno(err)
     43 			if !ok {
     44 				return "", err
     45 			}
     46 			return "", fmt.Errorf("%v (windows errno=%d)", err, errno)
     47 		}
     48 		defer c.Close()
     49 
     50 		b := make([]byte, 100)
     51 		n, err := c.Read(b)
     52 		if err == nil || err == io.EOF {
     53 			return string(b[:n]), nil
     54 		}
     55 		errno, ok := toErrno(err)
     56 		if ok && ignoreSomeReadErrors && (errno == syscall.ERROR_NETNAME_DELETED || errno == syscall.WSAECONNRESET) {
     57 			return "", nil
     58 		}
     59 		return "", err
     60 	}
     61 
     62 	send := func(addr string, data string) error {
     63 		c, err := Dial("tcp", addr)
     64 		if err != nil {
     65 			return err
     66 		}
     67 		defer c.Close()
     68 
     69 		b := []byte(data)
     70 		n, err := c.Write(b)
     71 		if err != nil {
     72 			return err
     73 		}
     74 		if n != len(b) {
     75 			return fmt.Errorf(`Only %d chars of string "%s" sent`, n, data)
     76 		}
     77 		return nil
     78 	}
     79 
     80 	if envaddr := os.Getenv("GOTEST_DIAL_ADDR"); envaddr != "" {
     81 		// In child process.
     82 		c, err := Dial("tcp", envaddr)
     83 		if err != nil {
     84 			t.Fatal(err)
     85 		}
     86 		fmt.Printf("sleeping\n")
     87 		time.Sleep(time.Minute) // process will be killed here
     88 		c.Close()
     89 	}
     90 
     91 	ln, err := Listen("tcp", "127.0.0.1:0")
     92 	if err != nil {
     93 		t.Fatal(err)
     94 	}
     95 	defer ln.Close()
     96 
     97 	// Start child process that connects to our listener.
     98 	cmd := exec.Command(os.Args[0], "-test.run=TestAcceptIgnoreSomeErrors")
     99 	cmd.Env = append(os.Environ(), "GOTEST_DIAL_ADDR="+ln.Addr().String())
    100 	stdout, err := cmd.StdoutPipe()
    101 	if err != nil {
    102 		t.Fatalf("cmd.StdoutPipe failed: %v", err)
    103 	}
    104 	err = cmd.Start()
    105 	if err != nil {
    106 		t.Fatalf("cmd.Start failed: %v\n", err)
    107 	}
    108 	outReader := bufio.NewReader(stdout)
    109 	for {
    110 		s, err := outReader.ReadString('\n')
    111 		if err != nil {
    112 			t.Fatalf("reading stdout failed: %v", err)
    113 		}
    114 		if s == "sleeping\n" {
    115 			break
    116 		}
    117 	}
    118 	defer cmd.Wait() // ignore error - we know it is getting killed
    119 
    120 	const alittle = 100 * time.Millisecond
    121 	time.Sleep(alittle)
    122 	cmd.Process.Kill() // the only way to trigger the errors
    123 	time.Sleep(alittle)
    124 
    125 	// Send second connection data (with delay in a separate goroutine).
    126 	result := make(chan error)
    127 	go func() {
    128 		time.Sleep(alittle)
    129 		err := send(ln.Addr().String(), "abc")
    130 		if err != nil {
    131 			result <- err
    132 		}
    133 		result <- nil
    134 	}()
    135 	defer func() {
    136 		err := <-result
    137 		if err != nil {
    138 			t.Fatalf("send failed: %v", err)
    139 		}
    140 	}()
    141 
    142 	// Receive first or second connection.
    143 	s, err := recv(ln, true)
    144 	if err != nil {
    145 		t.Fatalf("recv failed: %v", err)
    146 	}
    147 	switch s {
    148 	case "":
    149 		// First connection data is received, let's get second connection data.
    150 	case "abc":
    151 		// First connection is lost forever, but that is ok.
    152 		return
    153 	default:
    154 		t.Fatalf(`"%s" received from recv, but "" or "abc" expected`, s)
    155 	}
    156 
    157 	// Get second connection data.
    158 	s, err = recv(ln, false)
    159 	if err != nil {
    160 		t.Fatalf("recv failed: %v", err)
    161 	}
    162 	if s != "abc" {
    163 		t.Fatalf(`"%s" received from recv, but "abc" expected`, s)
    164 	}
    165 }
    166