From 5f5503afa8c8b9cf2bc2bbe5a3a588e68eae15ef Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 14 May 2018 03:55:46 +0200 Subject: [PATCH] Add rwcancelation to darwin --- rwcancel/rwcancel_unix.go | 4 +-- rwcancel/select_darwin.go | 12 ++++++++ rwcancel/select_linux.go | 13 +++++++++ tun_darwin.go | 61 +++++++++++++++++++++++++++++---------- 4 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 rwcancel/select_darwin.go create mode 100644 rwcancel/select_linux.go 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 . 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 . 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 {