Skip to content

Commit

Permalink
🦤 windows: adapt to upcoming changes in Go 1.23+
Browse files Browse the repository at this point in the history
Upstream made changes to netpoll code related to Windows in golang/go@d0dc93c
  • Loading branch information
database64128 committed Feb 1, 2024
1 parent 97ac4b8 commit 6290681
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 159 deletions.
140 changes: 140 additions & 0 deletions netpoll_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package tfo

import (
"net"
"sync"
"syscall"
_ "unsafe"

"golang.org/x/sys/windows"
)

//go:linkname sockaddrToTCP net.sockaddrToTCP
func sockaddrToTCP(sa syscall.Sockaddr) net.Addr

//go:linkname runtime_pollServerInit internal/poll.runtime_pollServerInit
func runtime_pollServerInit()

//go:linkname runtime_pollOpen internal/poll.runtime_pollOpen
func runtime_pollOpen(fd uintptr) (uintptr, int)

// Copied from src/internal/poll/fd_poll_runtime.go
var serverInit sync.Once

//go:linkname execIO internal/poll.execIO
func execIO(o *operation, submit func(o *operation) error) (int, error)

// pFD is a file descriptor. The net and os packages embed this type in
// a larger type representing a network connection or OS file.
//
// Stay in sync with FD in src/internal/poll/fd_windows.go
type pFD struct {
fdmuS uint64
fdmuR uint32
fdmuW uint32

// System file descriptor. Immutable until Close.
Sysfd syscall.Handle

// Read operation.
rop operation
// Write operation.
wop operation

// I/O poller.
pd uintptr

// Used to implement pread/pwrite.
l sync.Mutex

// For console I/O.
lastbits []byte // first few bytes of the last incomplete rune in last write
readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole
readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8
readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read

// Semaphore signaled when file is closed.
csema uint32

skipSyncNotif bool

// Whether this is a streaming descriptor, as opposed to a
// packet-based descriptor like a UDP socket.
IsStream bool

// Whether a zero byte read indicates EOF. This is false for a
// message based socket connection.
ZeroReadIsEOF bool

// Whether this is a file rather than a network socket.
isFile bool

// The kind of this file.
kind byte
}

func (fd *pFD) init() error {
serverInit.Do(runtime_pollServerInit)
ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
if errno != 0 {
return syscall.Errno(errno)
}
fd.pd = ctx
fd.rop.mode = 'r'
fd.wop.mode = 'w'
fd.rop.fd = fd
fd.wop.fd = fd
fd.rop.runtimeCtx = fd.pd
fd.wop.runtimeCtx = fd.pd
return nil
}

func (fd *pFD) ConnectEx(ra syscall.Sockaddr, b []byte) (n int, err error) {
fd.wop.sa = ra
n, err = execIO(&fd.wop, func(o *operation) error {
return syscall.ConnectEx(o.fd.Sysfd, o.sa, &b[0], uint32(len(b)), &o.qty, &o.o)
})
return
}

// Network file descriptor.
//
// Copied from src/net/fd_posix.go
type netFD struct {
pfd pFD

// immutable until Close
family int
sotype int
isConnected bool // handshake completed or use of association with peer
net string
laddr net.Addr
raddr net.Addr
}

func (fd *netFD) ctrlNetwork() string {
if fd.net == "tcp4" || fd.family == windows.AF_INET {
return "tcp4"
}
return "tcp6"
}

//go:linkname newFD net.newFD
func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)

type rawConn netFD

func (c *rawConn) Control(f func(uintptr)) error {
f(uintptr(c.pfd.Sysfd))
return nil
}

func (c *rawConn) Read(f func(uintptr) bool) error {
f(uintptr(c.pfd.Sysfd))
return syscall.EWINDOWS
}

func (c *rawConn) Write(f func(uintptr) bool) error {
f(uintptr(c.pfd.Sysfd))
return syscall.EWINDOWS
}
35 changes: 35 additions & 0 deletions netpoll_windows_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//go:build windows && !go1.23

package tfo

import (
"syscall"

"golang.org/x/sys/windows"
)

// operation contains superset of data necessary to perform all async IO.
//
// Copied from src/internal/poll/fd_windows.go
type operation struct {
// Used by IOCP interface, it must be first field
// of the struct, as our code rely on it.
o syscall.Overlapped

// fields used by runtime.netpoll
runtimeCtx uintptr
mode int32
errno int32
qty uint32

// fields used only by net package
fd *pFD
buf syscall.WSABuf
msg windows.WSAMsg
sa syscall.Sockaddr
rsa *syscall.RawSockaddrAny
rsan int32
handle syscall.Handle
flags uint32
bufs []syscall.WSABuf
}
34 changes: 34 additions & 0 deletions netpoll_windows_go123.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build windows && go1.23

package tfo

import (
"syscall"

"golang.org/x/sys/windows"
)

// operation contains superset of data necessary to perform all async IO.
//
// Copied from src/internal/poll/fd_windows.go
type operation struct {
// Used by IOCP interface, it must be first field
// of the struct, as our code rely on it.
o syscall.Overlapped

// fields used by runtime.netpoll
runtimeCtx uintptr
mode int32

// fields used only by net package
fd *pFD
buf syscall.WSABuf
msg windows.WSAMsg
sa syscall.Sockaddr
rsa *syscall.RawSockaddrAny
rsan int32
handle syscall.Handle
flags uint32
qty uint32
bufs []syscall.WSABuf
}
159 changes: 0 additions & 159 deletions tfo_windows.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
//lint:file-ignore U1000 linkname magic brings a lot of unused unexported fields.

package tfo

import (
"context"
"errors"
"net"
"os"
"sync"
"syscall"
"unsafe"

Expand All @@ -32,162 +29,6 @@ func setUpdateConnectContext(fd windows.Handle) error {
return windows.Setsockopt(fd, windows.SOL_SOCKET, windows.SO_UPDATE_CONNECT_CONTEXT, nil, 0)
}

//go:linkname sockaddrToTCP net.sockaddrToTCP
func sockaddrToTCP(sa syscall.Sockaddr) net.Addr

//go:linkname runtime_pollServerInit internal/poll.runtime_pollServerInit
func runtime_pollServerInit()

//go:linkname runtime_pollOpen internal/poll.runtime_pollOpen
func runtime_pollOpen(fd uintptr) (uintptr, int)

// Copied from src/internal/pool/fd_poll_runtime.go
var serverInit sync.Once

// operation contains superset of data necessary to perform all async IO.
//
// Copied from src/internal/pool/fd_windows.go
type operation struct {
// Used by IOCP interface, it must be first field
// of the struct, as our code rely on it.
o syscall.Overlapped

// fields used by runtime.netpoll
runtimeCtx uintptr
mode int32
errno int32
qty uint32

// fields used only by net package
fd *pFD
buf syscall.WSABuf
msg windows.WSAMsg
sa syscall.Sockaddr
rsa *syscall.RawSockaddrAny
rsan int32
handle syscall.Handle
flags uint32
bufs []syscall.WSABuf
}

//go:linkname execIO internal/poll.execIO
func execIO(o *operation, submit func(o *operation) error) (int, error)

// pFD is a file descriptor. The net and os packages embed this type in
// a larger type representing a network connection or OS file.
//
// Copied from src/internal/pool/fd_windows.go
type pFD struct {
fdmuS uint64
fdmuR uint32
fdmuW uint32

// System file descriptor. Immutable until Close.
Sysfd syscall.Handle

// Read operation.
rop operation
// Write operation.
wop operation

// I/O poller.
pd uintptr

// Used to implement pread/pwrite.
l sync.Mutex

// For console I/O.
lastbits []byte // first few bytes of the last incomplete rune in last write
readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole
readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8
readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read

// Semaphore signaled when file is closed.
csema uint32

skipSyncNotif bool

// Whether this is a streaming descriptor, as opposed to a
// packet-based descriptor like a UDP socket.
IsStream bool

// Whether a zero byte read indicates EOF. This is false for a
// message based socket connection.
ZeroReadIsEOF bool

// Whether this is a file rather than a network socket.
isFile bool

// The kind of this file.
kind byte
}

func (fd *pFD) init() error {
serverInit.Do(runtime_pollServerInit)
ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
if errno != 0 {
return syscall.Errno(errno)
}
fd.pd = ctx
fd.rop.mode = 'r'
fd.wop.mode = 'w'
fd.rop.fd = fd
fd.wop.fd = fd
fd.rop.runtimeCtx = fd.pd
fd.wop.runtimeCtx = fd.pd
return nil
}

func (fd *pFD) ConnectEx(ra syscall.Sockaddr, b []byte) (n int, err error) {
fd.wop.sa = ra
n, err = execIO(&fd.wop, func(o *operation) error {
return syscall.ConnectEx(o.fd.Sysfd, o.sa, &b[0], uint32(len(b)), &o.qty, &o.o)
})
return
}

// Network file descriptor.
//
// Copied from src/net/fd_posix.go
type netFD struct {
pfd pFD

// immutable until Close
family int
sotype int
isConnected bool // handshake completed or use of association with peer
net string
laddr net.Addr
raddr net.Addr
}

func (fd *netFD) ctrlNetwork() string {
if fd.net == "tcp4" || fd.family == windows.AF_INET {
return "tcp4"
}
return "tcp6"
}

//go:linkname newFD net.newFD
func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)

type rawConn netFD

func (c *rawConn) Control(f func(uintptr)) error {
f(uintptr(c.pfd.Sysfd))
return nil
}

func (c *rawConn) Read(f func(uintptr) bool) error {
f(uintptr(c.pfd.Sysfd))
return syscall.EWINDOWS
}

func (c *rawConn) Write(f func(uintptr) bool) error {
f(uintptr(c.pfd.Sysfd))
return syscall.EWINDOWS
}

func (d *Dialer) dialSingle(ctx context.Context, network string, laddr, raddr *net.TCPAddr, b []byte, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (*net.TCPConn, error) {
ltsa := (*tcpSockaddr)(laddr)
rtsa := (*tcpSockaddr)(raddr)
Expand Down

0 comments on commit 6290681

Please sign in to comment.