windows: Migrate to mkwinsyscall

This commit is contained in:
世界 2024-08-09 11:08:34 +08:00
parent 08e8c02fb1
commit 6c19e0736d
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
15 changed files with 299 additions and 250 deletions

View file

@ -5,7 +5,6 @@ import (
"net/netip"
"os"
"syscall"
"unsafe"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
@ -15,49 +14,6 @@ import (
"golang.org/x/sys/windows"
)
var modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
var procrecv = modws2_32.NewProc("recv")
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
func recv(s windows.Handle, buf []byte, flags int32) (n int32, err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
}
r0, _, e1 := syscall.SyscallN(procrecv.Addr(), uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags))
n = int32(r0)
if n == -1 {
err = errnoErr(e1)
}
return
}
var _ N.ReadWaiter = (*syscallReadWaiter)(nil)
type syscallReadWaiter struct {

View file

@ -0,0 +1,5 @@
package bufio
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
//sys recv(s windows.Handle, buf []byte, flags int32) (n int32, err error) [failretval == -1] = ws2_32.recv

View file

@ -0,0 +1,57 @@
// Code generated by 'go generate'; DO NOT EDIT.
package bufio
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
procrecv = modws2_32.NewProc("recv")
)
func recv(s windows.Handle, buf []byte, flags int32) (n int32, err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
}
r0, _, e1 := syscall.Syscall6(procrecv.Addr(), 4, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), 0, 0)
n = int32(r0)
if n == -1 {
err = errnoErr(e1)
}
return
}

View file

@ -0,0 +1,6 @@
package ntp
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setsystemtime
//sys setSystemTime(lpSystemTime *windows.Systemtime) (err error) = kernel32.SetSystemTime

View file

@ -2,7 +2,6 @@ package ntp
import (
"time"
"unsafe"
"golang.org/x/sys/windows"
)
@ -16,17 +15,5 @@ func SetSystemTime(nowTime time.Time) error {
systemTime.Minute = uint16(nowTime.Minute())
systemTime.Second = uint16(nowTime.Second())
systemTime.Milliseconds = uint16(nowTime.UnixMilli() - nowTime.Unix()*1000)
dllKernel32 := windows.NewLazySystemDLL("kernel32.dll")
proc := dllKernel32.NewProc("SetSystemTime")
_, _, err := proc.Call(
uintptr(unsafe.Pointer(&systemTime)),
)
if err != nil && err.Error() != "The operation completed successfully." {
return err
}
return nil
return setSystemTime(&systemTime)
}

View file

@ -0,0 +1,52 @@
// Code generated by 'go generate'; DO NOT EDIT.
package ntp
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procSetSystemTime = modkernel32.NewProc("SetSystemTime")
)
func setSystemTime(lpSystemTime *windows.Systemtime) (err error) {
r1, _, e1 := syscall.Syscall(procSetSystemTime.Addr(), 1, uintptr(unsafe.Pointer(lpSystemTime)), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}

View file

@ -1,17 +0,0 @@
//go:build go1.21
package common
import "sync"
func OnceFunc(f func()) func() {
return sync.OnceFunc(f)
}
func OnceValue[T any](f func() T) func() T {
return sync.OnceValue(f)
}
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
return sync.OnceValues(f)
}

View file

@ -1,106 +0,0 @@
//go:build !go1.21
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// copied from go1.22.5
package common
import "sync"
// OnceFunc returns a function that invokes f only once. The returned function
// may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceFunc(f func()) func() {
var (
once sync.Once
valid bool
p any
)
// Construct the inner closure just once to reduce costs on the fast path.
g := func() {
defer func() {
p = recover()
if !valid {
// Re-panic immediately so on the first call the user gets a
// complete stack trace into f.
panic(p)
}
}()
f()
f = nil // Do not keep f alive after invoking it.
valid = true // Set only if f does not panic.
}
return func() {
once.Do(g)
if !valid {
panic(p)
}
}
}
// OnceValue returns a function that invokes f only once and returns the value
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValue[T any](f func() T) func() T {
var (
once sync.Once
valid bool
p any
result T
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
result = f()
f = nil
valid = true
}
return func() T {
once.Do(g)
if !valid {
panic(p)
}
return result
}
}
// OnceValues returns a function that invokes f only once and returns the values
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
var (
once sync.Once
valid bool
p any
r1 T1
r2 T2
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
r1, r2 = f()
f = nil
valid = true
}
return func() (T1, T2) {
once.Do(g)
if !valid {
panic(p)
}
return r1, r2
}
}

View file

@ -1,21 +0,0 @@
package windnsapi
import (
"os"
"syscall"
"golang.org/x/sys/windows"
)
var (
moddnsapi = windows.NewLazySystemDLL("dnsapi.dll")
procDnsFlushResolverCache = moddnsapi.NewProc("DnsFlushResolverCache")
)
func FlushResolverCache() error {
r0, _, err := syscall.SyscallN(procDnsFlushResolverCache.Addr())
if r0 == 0 {
return os.NewSyscallError("DnsFlushResolverCache", err)
}
return nil
}

View file

@ -0,0 +1,9 @@
//go:build !windows
package windnsapi
import "os"
func FlushResolverCache() error {
return os.ErrInvalid
}

View file

@ -0,0 +1,6 @@
package windnsapi
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
// dnsapi.DnsFlushResolverCache is an undocumented function
//sys FlushResolverCache() (ret error) = dnsapi.DnsFlushResolverCache

View file

@ -0,0 +1,52 @@
// Code generated by 'go generate'; DO NOT EDIT.
package windnsapi
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
moddnsapi = windows.NewLazySystemDLL("dnsapi.dll")
procDnsFlushResolverCache = moddnsapi.NewProc("DnsFlushResolverCache")
)
func FlushResolverCache() (ret error) {
r0, _, _ := syscall.Syscall(procDnsFlushResolverCache.Addr(), 0, 0, 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}

View file

@ -3,44 +3,11 @@ package winpowrprof
// modify from https://github.com/golang/go/blob/b634f6fdcbebee23b7da709a243f3db217b64776/src/runtime/os_windows.go#L257
import (
"syscall"
"unsafe"
"github.com/sagernet/sing/common"
"golang.org/x/sys/windows"
)
var (
modpowerprof = windows.NewLazySystemDLL("powrprof.dll")
procPowerRegisterSuspendResumeNotification = modpowerprof.NewProc("PowerRegisterSuspendResumeNotification")
procPowerUnregisterSuspendResumeNotification = modpowerprof.NewProc("PowerUnregisterSuspendResumeNotification")
)
var suspendResumeNotificationCallback = common.OnceValue(func() uintptr {
return windows.NewCallback(func(context *EventCallback, changeType uint32, setting uintptr) uintptr {
callback := *context
const (
PBT_APMSUSPEND uint32 = 4
PBT_APMRESUMESUSPEND uint32 = 7
PBT_APMRESUMEAUTOMATIC uint32 = 18
)
var event int
switch changeType {
case PBT_APMSUSPEND:
event = EVENT_SUSPEND
case PBT_APMRESUMESUSPEND:
event = EVENT_RESUME
case PBT_APMRESUMEAUTOMATIC:
event = EVENT_RESUME_AUTOMATIC
default:
return 0
}
callback(event)
return 0
})
})
type powerEventListener struct {
pinner myPinner
callback EventCallback
@ -63,24 +30,18 @@ func NewEventListener(callback EventCallback) (EventListener, error) {
func (l *powerEventListener) Start() error {
l.pinner.Pin(&l.callback)
type DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
callback uintptr
context unsafe.Pointer
}
const DEVICE_NOTIFY_CALLBACK = 2
params := DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
callback: suspendResumeNotificationCallback(),
callback: windows.NewCallback(suspendResumeNotificationCallback),
context: unsafe.Pointer(&l.callback),
}
_, _, errno := syscall.SyscallN(
procPowerRegisterSuspendResumeNotification.Addr(),
err := PowerRegisterSuspendResumeNotification(
DEVICE_NOTIFY_CALLBACK,
uintptr(unsafe.Pointer(&params)),
uintptr(unsafe.Pointer(&l.handle)),
&params,
&l.handle,
)
if errno != 0 {
if err != nil {
l.pinner.Unpin()
return errno
return err
}
return nil
}
@ -90,10 +51,27 @@ func (l *powerEventListener) Close() error {
return nil
}
defer l.pinner.Unpin()
r0, _, _ := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), l.handle)
if r0 != windows.NO_ERROR {
return syscall.Errno(r0)
err := PowerUnregisterSuspendResumeNotification(l.handle)
if err != nil {
return err
}
l.handle = 0
return nil
}
func suspendResumeNotificationCallback(context *EventCallback, changeType uint32, setting uintptr) uintptr {
callback := *context
var event int
switch changeType {
case PBT_APMSUSPEND:
event = EVENT_SUSPEND
case PBT_APMRESUMESUSPEND:
event = EVENT_RESUME
case PBT_APMRESUMEAUTOMATIC:
event = EVENT_RESUME_AUTOMATIC
default:
return 0
}
callback(event)
return 0
}

View file

@ -0,0 +1,24 @@
package winpowrprof
import "unsafe"
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
const DEVICE_NOTIFY_CALLBACK = 2
type DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
callback uintptr
context unsafe.Pointer
}
// https://learn.microsoft.com/en-us/windows/win32/api/powerbase/nf-powerbase-powerregistersuspendresumenotification
//sys PowerRegisterSuspendResumeNotification(flags uint32, recipient *DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, registrationHandle *uintptr) (ret error) = powrprof.PowerRegisterSuspendResumeNotification
// https://learn.microsoft.com/en-us/windows/win32/api/powerbase/nf-powerbase-powerunregistersuspendresumenotification
//sys PowerUnregisterSuspendResumeNotification(handle uintptr) (ret error) = powrprof.PowerUnregisterSuspendResumeNotification
const (
PBT_APMSUSPEND uint32 = 4
PBT_APMRESUMESUSPEND uint32 = 7
PBT_APMRESUMEAUTOMATIC uint32 = 18
)

View file

@ -0,0 +1,61 @@
// Code generated by 'go generate'; DO NOT EDIT.
package winpowrprof
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modpowrprof = windows.NewLazySystemDLL("powrprof.dll")
procPowerRegisterSuspendResumeNotification = modpowrprof.NewProc("PowerRegisterSuspendResumeNotification")
procPowerUnregisterSuspendResumeNotification = modpowrprof.NewProc("PowerUnregisterSuspendResumeNotification")
)
func PowerRegisterSuspendResumeNotification(flags uint32, recipient *DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, registrationHandle *uintptr) (ret error) {
r0, _, _ := syscall.Syscall(procPowerRegisterSuspendResumeNotification.Addr(), 3, uintptr(flags), uintptr(unsafe.Pointer(recipient)), uintptr(unsafe.Pointer(registrationHandle)))
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func PowerUnregisterSuspendResumeNotification(handle uintptr) (ret error) {
r0, _, _ := syscall.Syscall(procPowerUnregisterSuspendResumeNotification.Addr(), 1, uintptr(handle), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}