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