take 2 (doesn't work)

bradfitz/wgengine_monitor_windows_take2
Brad Fitzpatrick 2020-11-18 13:11:10 -08:00
parent c9ff4162c6
commit 339475c98b
1 changed files with 29 additions and 22 deletions

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"log"
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@ -138,28 +139,25 @@ func (m *winMon) getIPOrRouteChangeMessage() (message, error) {
return nil, errClosed return nil, errClosed
} }
oaddr := new(windows.Overlapped) addrHandle, cancel, err := notifyAddrChange()
oroute := new(windows.Overlapped)
err := notifyAddrChange(&oaddr.HEvent, oaddr)
if err != nil { if err != nil {
m.logf("notifyAddrChange: %v", err) m.logf("notifyAddrChange: %v", err)
return nil, err return nil, err
} }
defer cancelIPChangeNotifyProc.Call(uintptr(unsafe.Pointer(oaddr))) defer cancel()
err = notifyRouteChange(&oroute.HEvent, oroute) routeHandle, cancel, err := notifyRouteChange()
if err != nil { if err != nil {
m.logf("notifyRouteChange: %v", err) m.logf("notifyRouteChange: %v", err)
return nil, err return nil, err
} }
defer cancelIPChangeNotifyProc.Call(uintptr(unsafe.Pointer(oroute))) defer cancel()
t0 := time.Now() t0 := time.Now()
eventNum, err := windows.WaitForMultipleObjects([]windows.Handle{ eventNum, err := windows.WaitForMultipleObjects([]windows.Handle{
m.closeHandle, // eventNum 0 m.closeHandle, // eventNum 0
oaddr.HEvent, // eventNum 1 addrHandle, // eventNum 1
oroute.HEvent, // eventNum 2 routeHandle, // eventNum 2
}, false, windows.INFINITE) }, false, windows.INFINITE)
if m.ctx.Err() != nil || (err == nil && eventNum == 0) { if m.ctx.Err() != nil || (err == nil && eventNum == 0) {
return nil, errClosed return nil, errClosed
@ -197,12 +195,12 @@ func (m *winMon) getIPOrRouteChangeMessage() (message, error) {
return unspecifiedMessage{}, nil return unspecifiedMessage{}, nil
} }
func notifyAddrChange(h *windows.Handle, o *windows.Overlapped) error { func notifyAddrChange() (h windows.Handle, cancel func(), err error) {
return callNotifyProc(notifyAddrChangeProc, h, o) return callNotifyProc(notifyAddrChangeProc)
} }
func notifyRouteChange(h *windows.Handle, o *windows.Overlapped) error { func notifyRouteChange() (h windows.Handle, cancel func(), err error) {
return callNotifyProc(notifyRouteChangeProc, h, o) return callNotifyProc(notifyRouteChangeProc)
} }
// forceOverlapEscape exists purely so we can assign to it // forceOverlapEscape exists purely so we can assign to it
@ -210,16 +208,25 @@ func notifyRouteChange(h *windows.Handle, o *windows.Overlapped) error {
// stay stack allocated. // stay stack allocated.
var forceOverlapEscape atomic.Value // of *windows.Overlapped var forceOverlapEscape atomic.Value // of *windows.Overlapped
func callNotifyProc(p *syscall.LazyProc, h *windows.Handle, o *windows.Overlapped) error { func callNotifyProc(p *syscall.LazyProc) (h windows.Handle, cancel func(), err error) {
evt, err := windows.CreateEvent(nil, 1 /* manual reset */, 0 /* unsignaled */, nil /* no name */)
if err != nil {
return
}
o := new(windows.Overlapped)
o.HEvent = evt
forceOverlapEscape.Store(o) forceOverlapEscape.Store(o)
r1, _, e1 := syscall.Syscall(p.Addr(), 2, uintptr(unsafe.Pointer(h)), uintptr(unsafe.Pointer(o)), 0)
expect := uintptr(0) cancel = func() {
if h != nil || o != nil { cancelIPChangeNotifyProc.Call(uintptr(unsafe.Pointer(o)))
const ERROR_IO_PENDING = 997
expect = ERROR_IO_PENDING
} }
if r1 == expect {
return nil r1, _, e1 := syscall.Syscall(p.Addr(), 2, uintptr(unsafe.Pointer(&h)), uintptr(unsafe.Pointer(o)), 0)
log.Printf("pa=%x h=%v, r1=%v", p.Addr(), h, syscall.Errno(r1))
if syscall.Errno(r1) == windows.ERROR_IO_PENDING {
// Our expected result
return h, cancel, nil
} }
return e1 return 0, nil, e1
} }