So I believe I have found the source of this problem. A method Temporary is defined on syscall.Errno, for a reason that is unclear to me ECONNRESET and ECONNABORTED are considered temporary. I would definitely consider those errors permanent.
func (e Errno) Temporary() bool { return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout() } Link to function in source - https://github.com/golang/go/blob/master/src/syscall/syscall_unix.go#L123 Can anyone explain why these errors are considered temporary? On Wednesday, April 11, 2018 at 2:43:21 PM UTC+1, Piers Powlesland wrote: > > Hi Alex > > Thanks for your suggestion, I have implemented it, but something is still > not quite right, the first iteration of the loop to write to the conn still > encounters a temporary error, even though the internal error is a > syscall.ECONNRESET. > > Please see the updated code below > > func TestRemotelyClosedConnectionDetectedOnWrite(t *testing.T) { > listener, err := net.Listen("tcp", ":0") > if err != nil { > t.Fatal(err) > } > > wait := make(chan struct{}) > go func() { > conn, err := listener.Accept() > if err != nil { > panic(err) > } > err = conn.(*net.TCPConn).SetLinger(0) > if err != nil { > panic(err) > } > err = conn.Close() > if err != nil { > panic(err) > } > > wait <- struct{}{} > }() > conn, err := net.Dial("tcp", listener.Addr().String()) > if err != nil { > t.Fatal(err) > } > err = conn.(*net.TCPConn).SetLinger(0) > if err != nil { > t.Fatal(err) > } > > <-wait > // Allow ample time for any network communication to complete > time.Sleep(time.Second) > for i := 0; i < 10; i++ { > println(i) > _, err = conn.Write([]byte("b")) > if neterr, ok := err.(*net.OpError); ok { > if e, ok := neterr.Err.(*os.SyscallError); ok { > if e.Err == syscall.ECONNRESET && neterr.Temporary() { > // ECONNRESET should not be a temporary error > println("ECONNRESET is not permanent?") > t.Fail() > } > } > } > if neterr, ok := err.(*net.OpError); ok && !neterr.Temporary() { > break > } > } > if err == nil { > t.Fatal("expecting error to be returned when writing") > } > if neterr, ok := err.(net.Error); ok && !neterr.Temporary() { > return > } > t.Fatal("expecting error to be a permanent net.OpError", err) > } > > > > > On Tuesday, April 10, 2018 at 5:16:09 PM UTC+1, Alex Efros wrote: >> >> Hi! >> >> On Tue, Apr 10, 2018 at 07:58:29AM -0700, pierspo...@gmail.com wrote: >> > I'm trying to understand what is going on under the hood here. >> >> SO_LINGER (see socket(7)) delay happens. Add this after Accept(): >> >> conn, err := listener.Accept() >> if err == nil { >> err = conn.(*net.TCPConn).SetLinger(0) >> } >> >> > I would expect a net.Conn after being closed from the far side, to >> issue an >> > error if the near side then tries to write to it. On my local machine >> an >> > error is returned on the second write, on the go playground all writes >> > succeed. >> >> Playground doesn't support TCP, and there is write buffering which >> postpone returning related error. >> >> https://play.golang.org/p/JTAetL9no2y >> >> This example correctly output error in playground: >> 0 >> 2009/11/10 23:00:00 set tcp 0.0.0.0:2->127.0.0.1:3: Protocol not >> available >> and correctly works outside of playground: >> 0 >> 1 >> 2 >> 3 >> 4 >> write tcp 127.0.0.1:38900->127.0.0.1:33199: write: connection reset >> by peer >> (on very slow system it may output few more numbers because time.Sleep is >> not really suitable for synchronization). >> >> -- >> WBR, Alex. >> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.