wt *wintun.Adapter
handle windows.Handle
close bool
+ closing sync.RWMutex
events chan Event
- errors chan error
forcedMTU int
rate rateJuggler
session wintun.Session
wt: wt,
handle: windows.InvalidHandle,
events: make(chan Event, 10),
- errors: make(chan error, 1),
forcedMTU: forcedMTU,
}
}
func (tun *NativeTun) Name() (string, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
+ if tun.close {
+ return "", os.ErrClosed
+ }
return tun.wt.Name()
}
func (tun *NativeTun) Close() error {
var err error
tun.closeOnce.Do(func() {
+ tun.closing.Lock()
+ defer tun.closing.Unlock()
tun.close = true
tun.session.End()
if tun.wt != nil {
// Note: Read() and Write() assume the caller comes only from a single thread; there's no locking.
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
retry:
- select {
- case err := <-tun.errors:
- return 0, err
- default:
+ if tun.close {
+ return 0, os.ErrClosed
}
start := nanotime()
shouldSpin := atomic.LoadUint64(&tun.rate.current) >= spinloopRateThreshold && uint64(start-atomic.LoadInt64(&tun.rate.nextStartTime)) <= rateMeasurementGranularity*2
}
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
if tun.close {
return 0, os.ErrClosed
}
// LUID returns Windows interface instance ID.
func (tun *NativeTun) LUID() uint64 {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
+ if tun.close {
+ return 0
+ }
return tun.wt.LUID()
}