-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlistener_windows.go
101 lines (84 loc) · 2 KB
/
listener_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package go_network_listener
import (
"github.com/jc-lab/go-network-listener/internal/iphlpapi"
"github.com/jc-lab/go-network-listener/internal/retainer"
"golang.org/x/sys/windows"
"sync"
"unsafe"
)
type windowsListener struct {
mutex sync.Mutex
closed bool
mibChangeNotify2Handle windows.Handle
events chan *Event
}
var notifyIpInterfaceChangeCallback = windows.NewCallback(func(callerContext uintptr, row *iphlpapi.MibIPInterfaceRow, notificationType iphlpapi.MibNotificationType) uintptr {
listener, ok := retainer.Get(callerContext).(*windowsListener)
if !ok {
return 0
}
event := &Event{}
switch notificationType {
case iphlpapi.MibParameterNotification:
event.Type = EventTypeModify
case iphlpapi.MibAddInstance:
event.Type = EventTypeAdd
case iphlpapi.MibDeleteInstance:
event.Type = EventTypeRemove
default:
return 0
}
listener.mutex.Lock()
defer listener.mutex.Unlock()
if listener.closed {
return 0
}
select {
case listener.events <- event:
default:
// Channel is full, skip event
}
return 0
})
func newListener(options *Options) (Listener, error) {
l := &windowsListener{
events: make(chan *Event, 10),
}
ptr := retainer.Retain(uintptr(unsafe.Pointer(l)), l)
err := iphlpapi.NotifyIpInterfaceChange(
options.AfSpec.toWindows(), // Both IPv4 and IPv6
notifyIpInterfaceChangeCallback,
ptr,
false,
&l.mibChangeNotify2Handle,
)
if err != nil {
return nil, err
}
return l, nil
}
func (l *windowsListener) Chan() chan *Event {
return l.events
}
func (l *windowsListener) Close() error {
l.mutex.Lock()
defer l.mutex.Unlock()
l.closed = true
close(l.events)
if l.mibChangeNotify2Handle != 0 {
_ = windows.CancelMibChangeNotify2(l.mibChangeNotify2Handle)
l.mibChangeNotify2Handle = 0
}
retainer.Release(uintptr(unsafe.Pointer(l)))
return nil
}
func (v AfSpec) toWindows() uint16 {
switch v {
case AfInet4:
return windows.AF_INET
case AfInet6:
return windows.AF_INET6
default:
return windows.AF_UNSPEC
}
}