Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread Alex Efros
Hi!

On Wed, Apr 11, 2018 at 10:19:21AM -0700, Ian Lance Taylor wrote:
> You might want to open an issue about this.

Done: https://github.com/golang/go/issues/24808

-- 
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread Ian Lance Taylor
On Wed, Apr 11, 2018 at 7:35 AM,  wrote:
>
> 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?

See https://golang.org/issue/6163.

You might want to open an issue about this.

Ian

-- 
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread Alex Efros
Hi!

On Wed, Apr 11, 2018 at 07:35:50AM -0700, pierspowlesl...@gmail.com wrote:
> 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.

ECONNABORTED may happens on ln.Accept() in case connection was reset
right after connecting and before ln.Accept() returned it - so, in this
case this error is really temporary, you should ignore it and call
ln.Accept() again.

As for ECONNRESET I'm not sure. Usually on Write() you should get EPIPE,
not ECONNRESET. But check this: https://stackoverflow.com/a/2979806/113120

-- 
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread pierspowlesland
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread pierspowlesland
Hi Janne

I don't think that is the problem since the problem persists even after 
inserting a 4 second wait between closing the connection from the far side 
and writing to the near side.

On Tuesday, April 10, 2018 at 5:02:32 PM UTC+1, Janne Snabb wrote:
>
> Your TCP FIN is still in transit or not yet processed by the other TCP 
> stack when you issue the first write. 
>
> TCP is not synchronous even if running on same host. 
>
>
> Janne Snabb 
> sn...@epipe.com  
>
> On 2018-04-10 17:58, pierspo...@gmail.com  wrote: 
> > Hi 
> > 
> > I'm trying to understand what is going on under the hood here. 
> > 
> > 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. 
> > 
> > The test is shown below and is also here 
> > - https://play.golang.org/p/EFYX_ZehMKs  
> > 
> > Thanks for any insight, 
> > 
> > Piers 
> > 
> > | 
> > func TestDetectClosedConnectionWhenWriting(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 { 
> > t.Fatal(err) 
> > } 
> > err = conn.Close() 
> > if err != nil { 
> > t.Fatal(err) 
> > } 
> > wait <- struct{}{} 
> > }() 
> > 
> > conn, err := net.Dial("tcp", listener.Addr().String()) 
> > if err != nil { 
> > t.Fatal(err) 
> > } 
> > <-wait 
> > for i := 0; i < 100; i++ { 
> > println(i) 
> > _, err = conn.Write([]byte("b")) 
> > if err != nil { 
> > break 
> > } 
> > } 
> > if err == nil { 
> > t.Fatal("expecting error to be returned when writing") 
> > } 
> > t.Fatal("expecting error to be a permanent net.OpError") 
> > } 
> > 
> > | 
> > 
> > 
> > 
> > -- 
> > 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...@googlegroups.com  
> > . 
> > For more options, visit https://groups.google.com/d/optout. 
>

-- 
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-11 Thread pierspowlesland
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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-10 Thread Alex Efros
Hi!

On Tue, Apr 10, 2018 at 07:58:29AM -0700, pierspowlesl...@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.


Re: [go-nuts] net.Conn not returning error upon Write after being closed from far side.

2018-04-10 Thread Janne Snabb
Your TCP FIN is still in transit or not yet processed by the other TCP
stack when you issue the first write.

TCP is not synchronous even if running on same host.


Janne Snabb
sn...@epipe.com

On 2018-04-10 17:58, pierspowlesl...@gmail.com wrote:
> Hi
> 
> I'm trying to understand what is going on under the hood here.
> 
> 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.
> 
> The test is shown below and is also here
> - https://play.golang.org/p/EFYX_ZehMKs 
> 
> Thanks for any insight,
> 
> Piers
> 
> |
> func TestDetectClosedConnectionWhenWriting(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 {
> t.Fatal(err)
> }
> err = conn.Close()
> if err != nil {
> t.Fatal(err)
> }
> wait <- struct{}{}
> }()
> 
> conn, err := net.Dial("tcp", listener.Addr().String())
> if err != nil {
> t.Fatal(err)
> }
> <-wait
> for i := 0; i < 100; i++ {
> println(i)
> _, err = conn.Write([]byte("b"))
> if err != nil {
> break
> }
> }
> if err == nil {
> t.Fatal("expecting error to be returned when writing")
> }
> t.Fatal("expecting error to be a permanent net.OpError")
> }
> 
> |
> 
> 
> 
> -- 
> 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.

-- 
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.