Introduce rwcancel

This commit is contained in:
Jason A. Donenfeld
2018-05-14 00:28:30 +02:00
parent e21ea58db3
commit 7e10ebe101
5 changed files with 170 additions and 75 deletions

View File

@@ -11,6 +11,7 @@ package main
*/
import (
"./rwcancel"
"bytes"
"encoding/binary"
"errors"
@@ -20,7 +21,6 @@ import (
"net"
"os"
"strconv"
"syscall"
"time"
"unsafe"
)
@@ -31,14 +31,13 @@ const (
)
type NativeTun struct {
fd *os.File
index int32 // if index
name string // name of interface
errors chan error // async error handling
events chan TUNEvent // device related events
nopi bool // the device was pased IFF_NO_PI
closingReader *os.File
closingWriter *os.File
fd *os.File
index int32 // if index
name string // name of interface
errors chan error // async error handling
events chan TUNEvent // device related events
nopi bool // the device was pased IFF_NO_PI
rwcancel *rwcancel.RWCancel
}
func (tun *NativeTun) File() *os.File {
@@ -305,43 +304,6 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
return tun.fd.Write(buff)
}
type FdSet struct {
fdset unix.FdSet
}
func (fdset *FdSet) set(i int) {
bits := 32 << (^uint(0) >> 63)
fdset.fdset.Bits[i/bits] |= 1 << uint(i%bits)
}
func (fdset *FdSet) check(i int) bool {
bits := 32 << (^uint(0) >> 63)
return (fdset.fdset.Bits[i/bits] & (1 << uint(i%bits))) != 0
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func (tun *NativeTun) readyRead() bool {
readFd := int(tun.fd.Fd())
closeFd := int(tun.closingReader.Fd())
fdset := FdSet{}
fdset.set(readFd)
fdset.set(closeFd)
_, err := unix.Select(max(readFd, closeFd)+1, &fdset.fdset, nil, nil, nil)
if err != nil {
return false
}
if fdset.check(closeFd) {
return false
}
return fdset.check(readFd)
}
func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
@@ -360,24 +322,14 @@ func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
}
}
/* https://golang.org/src/crypto/rand/eagain.go */
func unixIsEAGAIN(err error) bool {
if pe, ok := err.(*os.PathError); ok {
if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EAGAIN {
return true
}
}
return false
}
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !unixIsEAGAIN(err) {
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
return n, err
}
if !tun.readyRead() {
return 0, errors.New("Tun device closed")
if !tun.rwcancel.ReadyRead() {
return 0, errors.New("tun device closed")
}
}
}
@@ -391,7 +343,7 @@ func (tun *NativeTun) Close() error {
if err != nil {
return err
}
tun.closingWriter.Write([]byte{0})
tun.rwcancel.Cancel()
close(tun.events)
return nil
}
@@ -450,7 +402,7 @@ func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
}
var err error
err = unix.SetNonblock(int(fd.Fd()), true)
device.rwcancel, err = rwcancel.NewRWCancel(int(fd.Fd()))
if err != nil {
return nil, err
}
@@ -460,11 +412,6 @@ func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
return nil, err
}
device.closingReader, device.closingWriter, err = os.Pipe()
if err != nil {
return nil, err
}
// start event listener
device.index, err = getIFIndex(device.name)