gonet can write a empty data to a closed conn
lysShub opened this issue · comments
lysShub commented
Description
package main_test
import (
"context"
"io"
"net"
"testing"
// gvisor.dev/gvisor v0.0.0-20240216000150-e3cf008ab186
"github.com/stretchr/testify/require"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
)
func Test_Closed_TCP_Write_Empty(t *testing.T) {
t.Run("system", func(t *testing.T) {
var addr = &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 8080}
go func() {
l, err := net.ListenTCP("tcp", addr)
require.NoError(t, err)
defer l.Close()
conn, err := l.AcceptTCP()
require.NoError(t, err)
io.Copy(conn, conn)
}()
time.Sleep(time.Second)
conn, err := net.DialTCP("tcp", nil, addr)
require.NoError(t, err)
err = conn.Close()
require.NoError(t, err)
n, err := conn.Write([]byte{})
require.Error(t, err)
require.Zero(t, n)
})
t.Run("gvisor", func(t *testing.T) {
var addr = tcpip.AddrFromSlice([]byte{10, 0, 0, 1})
var st = stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
HandleLocal: true,
})
const nicid tcpip.NICID = 1234
e := st.CreateNIC(nicid, channel.New(4, 1536, ""))
require.Nil(t, e)
st.AddProtocolAddress(nicid, tcpip.ProtocolAddress{
Protocol: header.IPv4ProtocolNumber,
AddressWithPrefix: addr.WithPrefix(),
}, stack.AddressProperties{})
st.SetRouteTable([]tcpip.Route{{Destination: header.IPv4EmptySubnet, NIC: nicid}})
go func() {
l, err := gonet.ListenTCP(
st,
tcpip.FullAddress{Addr: addr, Port: 8080},
header.IPv4ProtocolNumber,
)
require.NoError(t, err)
defer l.Close()
conn, err := l.Accept()
require.NoError(t, err)
io.Copy(conn, conn)
}()
time.Sleep(time.Second)
conn, err := gonet.DialTCPWithBind(
context.Background(), st,
tcpip.FullAddress{Addr: addr, Port: 12345},
tcpip.FullAddress{Addr: addr, Port: 8080},
header.IPv4ProtocolNumber,
)
require.NoError(t, err)
err = conn.Close()
require.NoError(t, err)
n, err := conn.Write([]byte{})
require.Error(t, err)
require.Zero(t, n)
})
}
Steps to reproduce
No response
runsc version
No response
docker version (if using docker)
No response
uname
No response
kubectl (if using Kubernetes)
No response
repo state (if built from source)
No response
runsc debug logs (if available)
No response
lysShub commented
system test passed on windows and linux
Kevin Krakauer commented
Can you help describe the problem in more detail? Is this contradicted in a doc somewhere, or does this differ from other implementers of net.Conn
?
lysShub commented
Can you help describe the problem in more detail? Is this contradicted in a doc somewhere, or does this differ from other implementers of
net.Conn
?
In most operating systems, writing to a closed TCP connection will return an error, including conn.Write([]byte{})
,but gonet will return 0 and nil
Kevin Krakauer commented
We'd definitely accept a PR with this change!