]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
tun: use netpoll instead of rwcancel
authorJason A. Donenfeld <Jason@zx2c4.com>
Wed, 27 Feb 2019 00:48:58 +0000 (01:48 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Wed, 27 Feb 2019 00:52:55 +0000 (01:52 +0100)
The new sysconn function of Go 1.12 makes this possible:

package main

import "log"
import "os"
import "unsafe"
import "time"
import "syscall"
import "sync"
import "golang.org/x/sys/unix"

func main() {
fd, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}

var ifr [unix.IFNAMSIZ + 64]byte
copy(ifr[:], []byte("cheese"))
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = unix.IFF_TUN

var errno syscall.Errno
s, _ := fd.SyscallConn()
s.Control(func(fd uintptr) {
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
})
if errno != 0 {
log.Fatal(errno)
}

b := [4]byte{}
wait := sync.WaitGroup{}
wait.Add(1)
go func() {
_, err := fd.Read(b[:])
log.Print("Read errored: ", err)
wait.Done()
}()
time.Sleep(time.Second)
log.Print("Closing")
err = fd.Close()
if err != nil {
log.Print("Close errored: " , err)
}
wait.Wait()
log.Print("Exiting")
}

main.go
tun/tun.go
tun/tun_darwin.go
tun/tun_freebsd.go
tun/tun_linux.go
tun/tun_openbsd.go

diff --git a/main.go b/main.go
index 23a1d2d201e2439793ca5ff91a98746cdc1693a3..08f8cc6a45ae56f45869fd041731f97875ef4760 100644 (file)
--- a/main.go
+++ b/main.go
@@ -145,6 +145,11 @@ func main() {
                        return nil, err
                }
 
+               err = syscall.SetNonblock(int(fd), true)
+               if err != nil {
+                       return nil, err
+               }
+
                file := os.NewFile(uintptr(fd), "")
                return tun.CreateTUNFromFile(file, DefaultMTU)
        }()
index d9c3c151b058c42cdb1f2ea2fff1888f779eacc9..3493b484c1cbd63646ca0d367cb89f597fd41394 100644 (file)
@@ -38,4 +38,4 @@ func (tun *nativeTun) operateOnFd(fn func(fd uintptr)) {
        if err != nil {
                tun.errors <- fmt.Errorf("unable to control sysconn for tunfile: %s", err.Error())
        }
-}
\ No newline at end of file
+}
index 1190a9d91fd0c5788d0bb70d65e322a2d8fedc74..8cb29810964679c181a9d6a7d3d58198e1c4d3dc 100644 (file)
@@ -6,11 +6,9 @@
 package tun
 
 import (
-       "errors"
        "fmt"
        "golang.org/x/net/ipv6"
        "golang.org/x/sys/unix"
-       "golang.zx2c4.com/wireguard/rwcancel"
        "io/ioutil"
        "net"
        "os"
@@ -36,7 +34,6 @@ type sockaddrCtl struct {
 type nativeTun struct {
        name        string
        tunFile     *os.File
-       rwcancel    *rwcancel.RWCancel
        events      chan TUNEvent
        errors      chan error
        routeSocket int
@@ -154,6 +151,10 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
                return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
        }
 
+       err = syscall.SetNonblock(fd, true)
+       if err != nil {
+               return nil, err
+       }
        tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu)
 
        if err == nil && name == "utun" {
@@ -191,14 +192,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
                return nil, err
        }
 
-       tun.operateOnFd(func (fd uintptr) {
-               tun.rwcancel, err = rwcancel.NewRWCancel(int(fd))
-       })
-       if err != nil {
-               tun.tunFile.Close()
-               return nil, err
-       }
-
        tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
        if err != nil {
                tun.tunFile.Close()
@@ -249,7 +242,7 @@ func (tun *nativeTun) Events() chan TUNEvent {
        return tun.events
 }
 
-func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
        select {
        case err := <-tun.errors:
                return 0, err
@@ -263,18 +256,6 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
        }
 }
 
-func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
-       for {
-               n, err := tun.doRead(buff, offset)
-               if err == nil || !rwcancel.RetryAfterError(err) {
-                       return n, err
-               }
-               if !tun.rwcancel.ReadyRead() {
-                       return 0, errors.New("tun device closed")
-               }
-       }
-}
-
 func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 
        // reserve space for header
@@ -299,12 +280,11 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 }
 
 func (tun *nativeTun) Close() error {
-       var err3 error
-       err1 := tun.rwcancel.Cancel()
-       err2 := tun.tunFile.Close()
+       var err2 error
+       err1 := tun.tunFile.Close()
        if tun.routeSocket != -1 {
                unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
-               err3 = unix.Close(tun.routeSocket)
+               err2 = unix.Close(tun.routeSocket)
                tun.routeSocket = -1
        } else if tun.events != nil {
                close(tun.events)
@@ -312,10 +292,7 @@ func (tun *nativeTun) Close() error {
        if err1 != nil {
                return err1
        }
-       if err2 != nil {
-               return err2
-       }
-       return err3
+       return err2
 }
 
 func (tun *nativeTun) setMTU(n int) error {
index 1aec123a3de734f8b13ec3587f0745d847f72d59..9e5c5ad92fa67fd9f2ae1925ee0ed5a609d84bcb 100644 (file)
@@ -11,7 +11,6 @@ import (
        "fmt"
        "golang.org/x/net/ipv6"
        "golang.org/x/sys/unix"
-       "golang.zx2c4.com/wireguard/rwcancel"
        "net"
        "os"
        "syscall"
@@ -52,7 +51,6 @@ type ifstat struct {
 type nativeTun struct {
        name        string
        tunFile     *os.File
-       rwcancel    *rwcancel.RWCancel
        events      chan TUNEvent
        errors      chan error
        routeSocket int
@@ -333,14 +331,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
                return nil, err
        }
 
-       tun.operateOnFd(func(fd uintptr) {
-               tun.rwcancel, err = rwcancel.NewRWCancel(int(fd))
-       })
-       if err != nil {
-               tun.tunFile.Close()
-               return nil, err
-       }
-
        tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
        if err != nil {
                tun.tunFile.Close()
@@ -379,7 +369,7 @@ func (tun *nativeTun) Events() chan TUNEvent {
        return tun.events
 }
 
-func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
        select {
        case err := <-tun.errors:
                return 0, err
@@ -393,18 +383,6 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
        }
 }
 
-func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
-       for {
-               n, err := tun.doRead(buff, offset)
-               if err == nil || !rwcancel.RetryAfterError(err) {
-                       return n, err
-               }
-               if !tun.rwcancel.ReadyRead() {
-                       return 0, errors.New("tun device closed")
-               }
-       }
-}
-
 func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 
        // reserve space for header
@@ -429,13 +407,12 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 }
 
 func (tun *nativeTun) Close() error {
-       var err4 error
-       err1 := tun.rwcancel.Cancel()
-       err2 := tun.tunFile.Close()
-       err3 := tunDestroy(tun.name)
+       var err3 error
+       err1 := tun.tunFile.Close()
+       err2 := tunDestroy(tun.name)
        if tun.routeSocket != -1 {
                unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
-               err4 = unix.Close(tun.routeSocket)
+               err3 = unix.Close(tun.routeSocket)
                tun.routeSocket = -1
        } else if tun.events != nil {
                close(tun.events)
@@ -446,10 +423,7 @@ func (tun *nativeTun) Close() error {
        if err2 != nil {
                return err2
        }
-       if err3 != nil {
-               return err3
-       }
-       return err4
+       return err3
 }
 
 func (tun *nativeTun) setMTU(n int) error {
index abdcce2a8331c1fe336e2657bb91ba93d513a0c3..8dcad6b6f8d3b42feb592c2a1153e343061ab82e 100644 (file)
@@ -31,7 +31,6 @@ const (
 
 type nativeTun struct {
        tunFile                 *os.File
-       fdCancel                *rwcancel.RWCancel
        index                   int32         // if index
        name                    string        // name of interface
        errors                  chan error    // async error handling
@@ -307,7 +306,7 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
        return tun.tunFile.Write(buff)
 }
 
-func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
        select {
        case err := <-tun.errors:
                return 0, err
@@ -325,18 +324,6 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
        }
 }
 
-func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
-       for {
-               n, err := tun.doRead(buff, offset)
-               if err == nil || !rwcancel.RetryAfterError(err) {
-                       return n, err
-               }
-               if !tun.fdCancel.ReadyRead() {
-                       return 0, errors.New("tun device closed")
-               }
-       }
-}
-
 func (tun *nativeTun) Events() chan TUNEvent {
        return tun.events
 }
@@ -352,30 +339,20 @@ func (tun *nativeTun) Close() error {
                close(tun.events)
        }
        err2 := tun.tunFile.Close()
-       err3 := tun.fdCancel.Cancel()
 
        if err1 != nil {
                return err1
        }
-       if err2 != nil {
-               return err2
-       }
-       return err3
+       return err2
 }
 
 func CreateTUN(name string, mtu int) (TUNDevice, error) {
-       nfd, err := unix.Open(cloneDevicePath, os.O_RDWR, 0)
-       if err != nil {
-               return nil, err
-       }
-
-       fd := os.NewFile(uintptr(nfd), cloneDevicePath)
+       tunFile, err := os.OpenFile(cloneDevicePath, os.O_RDWR, 0)
        if err != nil {
                return nil, err
        }
 
        // create new device
-
        var ifr [ifReqSize]byte
        var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack)
        nameBytes := []byte(name)
@@ -385,17 +362,20 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
        copy(ifr[:], nameBytes)
        *(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
 
-       _, _, errno := unix.Syscall(
-               unix.SYS_IOCTL,
-               nfd,
-               uintptr(unix.TUNSETIFF),
-               uintptr(unsafe.Pointer(&ifr[0])),
-       )
+       var errno syscall.Errno
+       (&nativeTun{tunFile: tunFile}).operateOnFd(func(fd uintptr) {
+               _, _, errno = unix.Syscall(
+                       unix.SYS_IOCTL,
+                       fd,
+                       uintptr(unix.TUNSETIFF),
+                       uintptr(unsafe.Pointer(&ifr[0])),
+               )
+       })
        if errno != 0 {
                return nil, errno
        }
 
-       return CreateTUNFromFile(fd, mtu)
+       return CreateTUNFromFile(tunFile, mtu)
 }
 
 func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
@@ -408,14 +388,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
        }
        var err error
 
-       tun.operateOnFd(func(fd uintptr) {
-               tun.fdCancel, err = rwcancel.NewRWCancel(int(fd))
-       })
-       if err != nil {
-               tun.tunFile.Close()
-               return nil, err
-       }
-
        _, err = tun.Name()
        if err != nil {
                tun.tunFile.Close()
index b10c460c9eefeb05eadccaf49a313afd502926b9..4e740c5f42d16ce6af7edc5dbfa3cb259f05f2b6 100644 (file)
@@ -6,11 +6,9 @@
 package tun
 
 import (
-       "errors"
        "fmt"
        "golang.org/x/net/ipv6"
        "golang.org/x/sys/unix"
-       "golang.zx2c4.com/wireguard/rwcancel"
        "io/ioutil"
        "net"
        "os"
@@ -30,7 +28,6 @@ const _TUNSIFMODE = 0x8004745d
 type nativeTun struct {
        name        string
        tunFile     *os.File
-       rwcancel    *rwcancel.RWCancel
        events      chan TUNEvent
        errors      chan error
        routeSocket int
@@ -167,14 +164,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
                return nil, err
        }
 
-       tun.operateOnFd(func(fd uintptr) {
-               tun.rwcancel, err = rwcancel.NewRWCancel(int(fd))
-       })
-       if err != nil {
-               tun.tunFile.Close()
-               return nil, err
-       }
-
        tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
        if err != nil {
                tun.tunFile.Close()
@@ -211,7 +200,7 @@ func (tun *nativeTun) Events() chan TUNEvent {
        return tun.events
 }
 
-func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
        select {
        case err := <-tun.errors:
                return 0, err
@@ -225,18 +214,6 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
        }
 }
 
-func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
-       for {
-               n, err := tun.doRead(buff, offset)
-               if err == nil || !rwcancel.RetryAfterError(err) {
-                       return n, err
-               }
-               if !tun.rwcancel.ReadyRead() {
-                       return 0, errors.New("tun device closed")
-               }
-       }
-}
-
 func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 
        // reserve space for header
@@ -261,12 +238,11 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
 }
 
 func (tun *nativeTun) Close() error {
-       var err3 error
-       err1 := tun.rwcancel.Cancel()
-       err2 := tun.tunFile.Close()
+       var err2 error
+       err1 := tun.tunFile.Close()
        if tun.routeSocket != -1 {
                unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
-               err3 = unix.Close(tun.routeSocket)
+               err2 = unix.Close(tun.routeSocket)
                tun.routeSocket = -1
        } else if tun.events != nil {
                close(tun.events)
@@ -274,10 +250,7 @@ func (tun *nativeTun) Close() error {
        if err1 != nil {
                return err1
        }
-       if err2 != nil {
-               return err2
-       }
-       return err3
+       return err2
 }
 
 func (tun *nativeTun) setMTU(n int) error {