internal/poll,net: set SIO_UDP_CONNRESET in net

Setting the SIO_UDP_CONNRESET option in internal/poll.FD.Init
adds unnecessary complexity to the FD.Init signature and
implementation. Better to set it in the net package when initializing
the UDP connection, which is where conceptually it belongs.

While here, update an outdated comment in FD.Init that said the runtime
poller doesn't support I/O operations initialized by the user
outside the internal/poll package. It does support those operations
since CL 561895.

For #19098.
Updates #21172.

Change-Id: I9a70b0deafdb4619830abe2147e2d366b4c2b890
Reviewed-on: https://go-review.googlesource.com/c/go/+/660496
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
qmuntal 2025-03-25 10:29:22 +01:00 committed by Gopher Robot
parent 35c9864897
commit 936bb82ddb
3 changed files with 28 additions and 35 deletions

View File

@ -281,9 +281,9 @@ var logInitFD func(net string, fd *FD, err error)
// The net argument is a network name from the net package (e.g., "tcp"),
// or "file" or "console" or "dir".
// Set pollable to true if fd should be managed by runtime netpoll.
func (fd *FD) Init(net string, pollable bool) (string, error) {
func (fd *FD) Init(net string, pollable bool) error {
if initErr != nil {
return "", initErr
return initErr
}
switch net {
@ -299,32 +299,27 @@ func (fd *FD) Init(net string, pollable bool) (string, error) {
"unix", "unixgram", "unixpacket":
fd.kind = kindNet
default:
return "", errors.New("internal error: unknown network type " + net)
return errors.New("internal error: unknown network type " + net)
}
fd.isFile = fd.kind != kindNet
var err error
if pollable {
// Only call init for a network socket.
// This means that we don't add files to the runtime poller.
// Adding files to the runtime poller can confuse matters
// if the user is doing their own overlapped I/O.
// See issue #21172.
// Note that the runtime poller will ignore I/O completion
// notifications not initiated by this package,
// so it is safe to add handles owned by the caller.
//
// In general the code below avoids calling the execIO
// function for non-network sockets. If some method does
// somehow call execIO, then execIO, and therefore the
// calling method, will return an error, because
// fd.pd.runtimeCtx will be 0.
// If we could not add the handle to the runtime poller,
// assume the handle hasn't been opened for overlapped I/O.
err = fd.pd.init(fd)
}
if logInitFD != nil {
logInitFD(net, fd, err)
}
if err != nil {
return "", err
if !pollable || err != nil {
return err
}
if pollable && (fd.kind != kindNet || socketCanUseSetFileCompletionNotificationModes) {
if fd.kind != kindNet || socketCanUseSetFileCompletionNotificationModes {
// Non-socket handles can use SetFileCompletionNotificationModes without problems.
err := syscall.SetFileCompletionNotificationModes(fd.Sysfd,
syscall.FILE_SKIP_SET_EVENT_ON_HANDLE|syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS,
@ -333,25 +328,13 @@ func (fd *FD) Init(net string, pollable bool) (string, error) {
fd.skipSyncNotif = true
}
}
// Disable SIO_UDP_CONNRESET behavior.
// http://support.microsoft.com/kb/263823
switch net {
case "udp", "udp4", "udp6":
ret := uint32(0)
flag := uint32(0)
size := uint32(unsafe.Sizeof(flag))
err := syscall.WSAIoctl(fd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
if err != nil {
return "wsaioctl", err
}
}
fd.rop.mode = 'r'
fd.wop.mode = 'w'
fd.rop.fd = fd
fd.wop.fd = fd
fd.rop.runtimeCtx = fd.pd.runtimeCtx
fd.wop.runtimeCtx = fd.pd.runtimeCtx
return "", nil
return nil
}
func (fd *FD) destroy() error {

View File

@ -121,8 +121,7 @@ func TestWSASocketConflict(t *testing.T) {
t.Fatal(err)
}
fd := poll.FD{Sysfd: s, IsStream: true, ZeroReadIsEOF: true}
_, err = fd.Init("tcp", true)
if err != nil {
if err = fd.Init("tcp", true); err != nil {
syscall.CloseHandle(s)
t.Fatal(err)
}

View File

@ -53,11 +53,22 @@ func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)
}
func (fd *netFD) init() error {
errcall, err := fd.pfd.Init(fd.net, true)
if errcall != "" {
err = wrapSyscallError(errcall, err)
if err := fd.pfd.Init(fd.net, true); err != nil {
return err
}
return err
switch fd.net {
case "udp", "udp4", "udp6":
// Disable reporting of PORT_UNREACHABLE errors.
// See https://go.dev/issue/5834.
ret := uint32(0)
flag := uint32(0)
size := uint32(unsafe.Sizeof(flag))
err := syscall.WSAIoctl(fd.pfd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
if err != nil {
return wrapSyscallError("wsaioctl", err)
}
}
return nil
}
// Always returns nil for connected peer address result.