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.

Reply via email to