github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/net/net_windows_test.go (about)

     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  }