mirror of
https://github.com/fumiama/water.git
synced 2026-06-23 12:40:40 +08:00
use wg wintun op
This commit is contained in:
@@ -7,7 +7,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
@@ -286,11 +288,47 @@ func openTap(config Config) (ifce *Interface, err error) {
|
|||||||
return nil, errIfceNameNotFound
|
return nil, errIfceNameNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/WireGuard/wireguard-go/blob/master/tun/tun_windows.go
|
||||||
|
const (
|
||||||
|
rateMeasurementGranularity = uint64((time.Second / 2) / time.Nanosecond)
|
||||||
|
spinloopRateThreshold = 800000000 / 8 // 800mbps
|
||||||
|
spinloopDuration = uint64(time.Millisecond / 80 / time.Nanosecond) // ~1gbit/s
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname procyield runtime.procyield
|
||||||
|
func procyield(cycles uint32)
|
||||||
|
|
||||||
|
//go:linkname nanotime runtime.nanotime
|
||||||
|
func nanotime() int64
|
||||||
|
|
||||||
|
type rateJuggler struct {
|
||||||
|
current uint64
|
||||||
|
nextByteCount uint64
|
||||||
|
nextStartTime int64
|
||||||
|
changing int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rate *rateJuggler) update(packetLen uint64) {
|
||||||
|
now := nanotime()
|
||||||
|
total := atomic.AddUint64(&rate.nextByteCount, packetLen)
|
||||||
|
period := uint64(now - atomic.LoadInt64(&rate.nextStartTime))
|
||||||
|
if period >= rateMeasurementGranularity {
|
||||||
|
if !atomic.CompareAndSwapInt32(&rate.changing, 0, 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
atomic.StoreInt64(&rate.nextStartTime, now)
|
||||||
|
atomic.StoreUint64(&rate.current, total*uint64(time.Second/time.Nanosecond)/period)
|
||||||
|
atomic.StoreUint64(&rate.nextByteCount, 0)
|
||||||
|
atomic.StoreInt32(&rate.changing, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type wintunRWC struct {
|
type wintunRWC struct {
|
||||||
ad wintun.Adapter
|
ad wintun.Adapter
|
||||||
s wintun.Session
|
s wintun.Session
|
||||||
readwait windows.Handle
|
readwait windows.Handle
|
||||||
readbuf []byte
|
readbuf []byte
|
||||||
|
rate rateJuggler
|
||||||
isclosed bool
|
isclosed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +339,7 @@ func (w *wintunRWC) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *wintunRWC) Write(b []byte) (int, error) {
|
func (w *wintunRWC) Write(b []byte) (int, error) {
|
||||||
|
w.rate.update(uint64(len(b)))
|
||||||
packet, err := w.s.AllocateSendPacket(len(b))
|
packet, err := w.s.AllocateSendPacket(len(b))
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
@@ -336,20 +375,30 @@ RETRY:
|
|||||||
if w.isclosed {
|
if w.isclosed {
|
||||||
return 0, errors.New("wintun is closed")
|
return 0, errors.New("wintun is closed")
|
||||||
}
|
}
|
||||||
packet, err := w.s.ReceivePacket()
|
start := nanotime()
|
||||||
switch err {
|
shouldSpin := atomic.LoadUint64(&w.rate.current) >= spinloopRateThreshold && uint64(start-atomic.LoadInt64(&w.rate.nextStartTime)) <= rateMeasurementGranularity*2
|
||||||
case nil:
|
for {
|
||||||
n += copy(b, packet)
|
packet, err := w.s.ReceivePacket()
|
||||||
if len(packet) > len(b) {
|
switch err {
|
||||||
w.readbuf = make([]byte, len(packet)-len(b))
|
case nil:
|
||||||
copy(w.readbuf, packet[len(b):])
|
packetSize := len(packet)
|
||||||
|
n += copy(b, packet)
|
||||||
|
if len(packet) > len(b) {
|
||||||
|
w.readbuf = make([]byte, len(packet)-len(b))
|
||||||
|
copy(w.readbuf, packet[len(b):])
|
||||||
|
}
|
||||||
|
w.s.ReleaseReceivePacket(packet)
|
||||||
|
w.rate.update(uint64(packetSize))
|
||||||
|
case windows.ERROR_NO_MORE_ITEMS:
|
||||||
|
if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration {
|
||||||
|
windows.WaitForSingleObject(w.readwait, windows.INFINITE)
|
||||||
|
goto RETRY
|
||||||
|
}
|
||||||
|
procyield(1)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
w.s.ReleaseReceivePacket(packet)
|
return n, err
|
||||||
case windows.ERROR_NO_MORE_ITEMS:
|
|
||||||
windows.WaitForSingleObject(w.readwait, windows.INFINITE)
|
|
||||||
goto RETRY
|
|
||||||
}
|
}
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// openDev find and open an interface.
|
// openDev find and open an interface.
|
||||||
|
|||||||
Reference in New Issue
Block a user