tun: windows: mitigate infinite loop in Flush()
It's possible that for whatever reason, we keep returning EOF, resulting in repeated close/open/write operations, except with empty packets.
This commit is contained in:
parent
d9f995209c
commit
da61947ec3
|
@ -8,6 +8,7 @@ package tun
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -230,6 +231,7 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retries := 1000
|
||||||
for {
|
for {
|
||||||
if tun.rdBuff.offset+packetExchangeAlignment <= tun.rdBuff.avail {
|
if tun.rdBuff.offset+packetExchangeAlignment <= tun.rdBuff.avail {
|
||||||
// Get packet from the exchange buffer.
|
// Get packet from the exchange buffer.
|
||||||
|
@ -255,31 +257,31 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill queue.
|
n, err := file.Read(tun.rdBuff.data[:])
|
||||||
retries := 1000
|
if err != nil {
|
||||||
for {
|
|
||||||
n, err := file.Read(tun.rdBuff.data[:])
|
|
||||||
if err != nil {
|
|
||||||
tun.rdBuff.offset = 0
|
|
||||||
tun.rdBuff.avail = 0
|
|
||||||
pe, ok := err.(*os.PathError)
|
|
||||||
if tun.close {
|
|
||||||
return 0, os.ErrClosed
|
|
||||||
}
|
|
||||||
if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
|
|
||||||
retries--
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok && pe.Err == windows.ERROR_HANDLE_EOF {
|
|
||||||
tun.closeTUN()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
tun.rdBuff.offset = 0
|
tun.rdBuff.offset = 0
|
||||||
tun.rdBuff.avail = uint32(n)
|
tun.rdBuff.avail = 0
|
||||||
break
|
pe, ok := err.(*os.PathError)
|
||||||
|
if tun.close {
|
||||||
|
return 0, os.ErrClosed
|
||||||
|
}
|
||||||
|
if retries > 0 && ok && (pe.Err == windows.ERROR_HANDLE_EOF || pe.Err == windows.ERROR_OPERATION_ABORTED) {
|
||||||
|
retries--
|
||||||
|
tun.closeTUN()
|
||||||
|
time.Sleep(time.Millisecond * 2)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
if n == 0 {
|
||||||
|
if retries == 0 {
|
||||||
|
return 0, io.ErrShortBuffer
|
||||||
|
}
|
||||||
|
retries--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tun.rdBuff.offset = 0
|
||||||
|
tun.rdBuff.avail = uint32(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +291,11 @@ func (tun *NativeTun) Flush() error {
|
||||||
if tun.wrBuff.offset == 0 {
|
if tun.wrBuff.offset == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
tun.wrBuff.packetNum = 0
|
||||||
|
tun.wrBuff.offset = 0
|
||||||
|
}()
|
||||||
|
retries := 1000
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// Get TUN data pipe.
|
// Get TUN data pipe.
|
||||||
|
@ -297,23 +304,22 @@ func (tun *NativeTun) Flush() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush write buffer.
|
|
||||||
retries := 1000
|
|
||||||
for {
|
for {
|
||||||
_, err = file.Write(tun.wrBuff.data[:tun.wrBuff.offset])
|
_, err = file.Write(tun.wrBuff.data[:tun.wrBuff.offset])
|
||||||
tun.wrBuff.packetNum = 0
|
|
||||||
tun.wrBuff.offset = 0
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pe, ok := err.(*os.PathError)
|
pe, ok := err.(*os.PathError)
|
||||||
if tun.close {
|
if tun.close {
|
||||||
return os.ErrClosed
|
return os.ErrClosed
|
||||||
}
|
}
|
||||||
if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
|
if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED { // Adapter is paused or in low-power state.
|
||||||
retries--
|
retries--
|
||||||
|
time.Sleep(time.Millisecond * 2)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ok && pe.Err == windows.ERROR_HANDLE_EOF {
|
if retries > 0 && ok && pe.Err == windows.ERROR_HANDLE_EOF { // Adapter is going down.
|
||||||
|
retries--
|
||||||
tun.closeTUN()
|
tun.closeTUN()
|
||||||
|
time.Sleep(time.Millisecond * 2)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in a new issue