aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rwcancel/rwcancel_unix.go4
-rw-r--r--rwcancel/select_darwin.go12
-rw-r--r--rwcancel/select_linux.go13
-rw-r--r--tun_darwin.go61
4 files changed, 73 insertions, 17 deletions
diff --git a/rwcancel/rwcancel_unix.go b/rwcancel/rwcancel_unix.go
index cd3661f..7f2c9e0 100644
--- a/rwcancel/rwcancel_unix.go
+++ b/rwcancel/rwcancel_unix.go
@@ -77,7 +77,7 @@ func (rw *RWCancel) ReadyRead() bool {
fdset := fdSet{}
fdset.set(rw.fd)
fdset.set(closeFd)
- _, err := unix.Select(max(rw.fd, closeFd)+1, &fdset.fdset, nil, nil, nil)
+ err := unixSelect(max(rw.fd, closeFd)+1, &fdset.fdset, nil, nil, nil)
if err != nil {
return false
}
@@ -92,7 +92,7 @@ func (rw *RWCancel) ReadyWrite() bool {
fdset := fdSet{}
fdset.set(rw.fd)
fdset.set(closeFd)
- _, err := unix.Select(max(rw.fd, closeFd)+1, nil, &fdset.fdset, nil, nil)
+ err := unixSelect(max(rw.fd, closeFd)+1, nil, &fdset.fdset, nil, nil)
if err != nil {
return false
}
diff --git a/rwcancel/select_darwin.go b/rwcancel/select_darwin.go
new file mode 100644
index 0000000..d14edc8
--- /dev/null
+++ b/rwcancel/select_darwin.go
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+package rwcancel
+
+import "golang.org/x/sys/unix"
+
+func unixSelect(nfd int, r *unix.FdSet, w *unix.FdSet, e *unix.FdSet, timeout *unix.Timeval) error {
+ return unix.Select(nfd, r, w, e, timeout)
+}
diff --git a/rwcancel/select_linux.go b/rwcancel/select_linux.go
new file mode 100644
index 0000000..c3d4e27
--- /dev/null
+++ b/rwcancel/select_linux.go
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+package rwcancel
+
+import "golang.org/x/sys/unix"
+
+func unixSelect(nfd int, r *unix.FdSet, w *unix.FdSet, e *unix.FdSet, timeout *unix.Timeval) (err error) {
+ _, err = unix.Select(nfd, r, w, e, timeout)
+ return
+}
diff --git a/tun_darwin.go b/tun_darwin.go
index fa8efe0..1ce039d 100644
--- a/tun_darwin.go
+++ b/tun_darwin.go
@@ -6,7 +6,9 @@
package main
import (
+ "./rwcancel"
"encoding/binary"
+ "errors"
"fmt"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
@@ -34,9 +36,10 @@ type sockaddrCtl struct {
// NativeTun is a hack to work around the first 4 bytes "packet
// information" because there doesn't seem to be an IFF_NO_PI for darwin.
type NativeTun struct {
- name string
- fd *os.File
- mtu int
+ name string
+ fd *os.File
+ rwcancel *rwcancel.RWCancel
+ mtu int
events chan TUNEvent
errors chan error
@@ -121,6 +124,17 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
return nil, err
}
+ // set default MTU
+ err = tun.setMTU(DefaultMTU)
+ if err != nil {
+ return nil, err
+ }
+
+ tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
+ if err != nil {
+ return nil, err
+ }
+
// TODO: Fix this very naive implementation
go func(tun *NativeTun) {
var (
@@ -153,10 +167,7 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
}
}(tun)
- // set default MTU
- err = tun.setMTU(DefaultMTU)
-
- return tun, err
+ return tun, nil
}
func (tun *NativeTun) Name() (string, error) {
@@ -190,14 +201,30 @@ func (tun *NativeTun) Events() chan TUNEvent {
return tun.events
}
-func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
-
- buff = buff[offset-4:]
- n, err := tun.fd.Read(buff[:])
- if n < 4 {
+func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
+ select {
+ case err := <-tun.errors:
return 0, err
+ default:
+ buff := buff[offset-4:]
+ n, err := tun.fd.Read(buff[:])
+ if n < 4 {
+ return 0, err
+ }
+ return n - 4, err
+ }
+}
+
+func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+ for {
+ n, err := tun.doRead(buff, offset)
+ if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
+ return n, err
+ }
+ if !tun.rwcancel.ReadyRead() {
+ return 0, errors.New("tun device closed")
+ }
}
- return n - 4, err
}
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
@@ -224,9 +251,13 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
}
func (tun *NativeTun) Close() error {
- err := tun.fd.Close()
+ err1 := tun.rwcancel.Cancel()
+ err2 := tun.fd.Close()
close(tun.events)
- return err
+ if err1 != nil {
+ return err1
+ }
+ return err2
}
func (tun *NativeTun) setMTU(n int) error {