Quellcode durchsuchen

use blocking mode pre-go1.11

Song Gao vor 6 Jahren
Ursprung
Commit
3fe638a7bf

+ 2 - 1
.travis.yml

@@ -1,6 +1,7 @@
 language: go
 go:
-  - "1.11.4"
+  - "1.12.1"
+  - "1.10.8"
 go_import_path: github.com/songgao/water
 install: go get -u golang.org/x/lint/golint
 script: make ci

+ 2 - 4
if.go

@@ -57,10 +57,8 @@ func New(config Config) (ifce *Interface, err error) {
 		config.PlatformSpecificParams = defaultPlatformSpecificParams()
 	}
 	switch config.DeviceType {
-	case TUN:
-		return newTUN(config)
-	case TAP:
-		return newTAP(config)
+	case TUN, TAP:
+		return openDev(config)
 	default:
 		return nil, errors.New("unknown device type")
 	}

+ 2 - 2
if_linux.go

@@ -14,7 +14,7 @@ func NewTAP(ifName string) (ifce *Interface, err error) {
 	fmt.Println("Deprecated: NewTAP(..) may be removed in the future. Please use New() instead.")
 	config := Config{DeviceType: TAP}
 	config.Name = ifName
-	return newTAP(config)
+	return openDev(config)
 }
 
 // NewTUN creates a new TUN interface whose name is ifName. If ifName is empty, a
@@ -26,5 +26,5 @@ func NewTUN(ifName string) (ifce *Interface, err error) {
 	fmt.Println("Deprecated: NewTUN(..) may be removed in the future. Please use New() instead.")
 	config := Config{DeviceType: TUN}
 	config.Name = ifName
-	return newTUN(config)
+	return openDev(config)
 }

+ 36 - 0
ipv4_go1.11_test.go

@@ -0,0 +1,36 @@
+// +build go1.11
+
+package water
+
+import (
+	"context"
+	"testing"
+	"time"
+)
+
+func TestCloseUnblockPendingRead(t *testing.T) {
+	ifce, err := New(Config{DeviceType: TUN})
+	if err != nil {
+		t.Fatalf("creating TUN error: %v\n", err)
+	}
+
+	c := make(chan struct{})
+	go func() {
+		ifce.Read(make([]byte, 1<<16))
+		close(c)
+	}()
+
+	// make sure ifce.Close() happens after ifce.Read() blocks
+	time.Sleep(1 * time.Second)
+
+	ifce.Close()
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+
+	select {
+	case <-c:
+		t.Log("Pending Read unblocked")
+	case <-ctx.Done():
+		t.Fatal("Timeouted, pending read blocked")
+	}
+}

+ 0 - 29
ipv4_test.go

@@ -1,9 +1,7 @@
 package water
 
 import (
-	"context"
 	"testing"
-	"time"
 )
 
 const BUFFERSIZE = 1522
@@ -22,30 +20,3 @@ func startRead(t *testing.T, ifce *Interface, dataCh chan<- []byte, errCh chan<-
 		}
 	}()
 }
-
-func TestCloseUnblockPendingRead(t *testing.T) {
-	ifce, err := New(Config{DeviceType: TUN})
-	if err != nil {
-		t.Fatalf("creating TUN error: %v\n", err)
-	}
-
-	c := make(chan struct{})
-	go func() {
-		ifce.Read(make([]byte, 1<<16))
-		close(c)
-	}()
-
-	// make sure ifce.Close() happens after ifce.Read() blocks
-	time.Sleep(1 * time.Second)
-
-	ifce.Close()
-	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
-	defer cancel()
-
-	select {
-	case <-c:
-		t.Log("Pending Read unblocked")
-	case <-ctx.Done():
-		t.Fatal("Timeouted, pending read blocked")
-	}
-}

+ 5 - 6
syscalls_darwin.go

@@ -59,7 +59,10 @@ type sockaddrCtl struct {
 
 var sockaddrCtlSize uintptr = 32
 
-func newTUN(config Config) (ifce *Interface, err error) {
+func openDev(config Config) (ifce *Interface, err error) {
+	if config.DeviceType != TUN {
+		return nil, errors.New("only tun is implemented on this platform")
+	}
 	var fd int
 	// Supposed to be socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), but ...
 	//
@@ -111,7 +114,7 @@ func newTUN(config Config) (ifce *Interface, err error) {
 		return nil, fmt.Errorf("error in syscall.Syscall6(syscall.SYS_GETSOCKOPT, ...): %v", err)
 	}
 
-	if err = syscall.SetNonblock(fd, true); err != nil {
+	if err = setNonBlock(fd); err != nil {
 		return nil, fmt.Errorf("setting non-blocking error")
 	}
 
@@ -124,10 +127,6 @@ func newTUN(config Config) (ifce *Interface, err error) {
 	}, nil
 }
 
-func newTAP(config Config) (ifce *Interface, err error) {
-	return nil, errors.New("tap interface not implemented on this platform")
-}
-
 // tunReadCloser 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 tunReadCloser struct {

+ 9 - 0
syscalls_darwin_go1.11.go

@@ -0,0 +1,9 @@
+// +build darwin,go1.11
+
+package water
+
+import "syscall"
+
+func setNonBlock(fd int) error {
+	return syscall.SetNonblock(fd, true)
+}

+ 10 - 0
syscalls_darwin_legacy.go

@@ -0,0 +1,10 @@
+// +build darwin,!go1.11
+
+package water
+
+func setNonBlock(fd int) error {
+	// There's a but pre-go1.11 that causes 'resource temporarily unavailable'
+	// error in non-blocking mode. So just skip it here. Close() won't be able
+	// to unblock a pending read, but that's better than being broken.
+	return nil
+}

+ 10 - 38
syscalls_linux.go

@@ -28,54 +28,26 @@ func ioctl(fd uintptr, request uintptr, argp uintptr) error {
 	return nil
 }
 
-func newTAP(config Config) (ifce *Interface, err error) {
-	fdInt, err := syscall.Open("/dev/net/tun", os.O_RDWR|syscall.O_NONBLOCK, 0)
-	if err != nil {
-		return nil, err
+func setupFd(config Config, fd uintptr) (name string, err error) {
+	var flags uint16 = cIFFNOPI
+	if config.DeviceType == TUN {
+		flags |= cIFFTUN
+	} else {
+		flags |= cIFFTAP
 	}
-	fd := uintptr(fdInt)
-
-	var flags uint16
-	flags = cIFFTAP | cIFFNOPI
 	if config.PlatformSpecificParams.MultiQueue {
 		flags |= cIFFMULTIQUEUE
 	}
-	name, err := createInterface(fd, config.Name, flags)
-	if err != nil {
-		return nil, err
-	}
-
-	if err = setDeviceOptions(fd, config); err != nil {
-		return nil, err
-	}
-
-	ifce = &Interface{isTAP: true, ReadWriteCloser: os.NewFile(fd, "tun"), name: name}
-	return
-}
-
-func newTUN(config Config) (ifce *Interface, err error) {
-	fdInt, err := syscall.Open("/dev/net/tun", os.O_RDWR|syscall.O_NONBLOCK, 0)
-	if err != nil {
-		return nil, err
-	}
-	fd := uintptr(fdInt)
 
-	var flags uint16
-	flags = cIFFTUN | cIFFNOPI
-	if config.PlatformSpecificParams.MultiQueue {
-		flags |= cIFFMULTIQUEUE
-	}
-	name, err := createInterface(fd, config.Name, flags)
-	if err != nil {
-		return nil, err
+	if name, err = createInterface(fd, config.Name, flags); err != nil {
+		return "", err
 	}
 
 	if err = setDeviceOptions(fd, config); err != nil {
-		return nil, err
+		return "", err
 	}
 
-	ifce = &Interface{isTAP: false, ReadWriteCloser: os.NewFile(fd, "tun"), name: name}
-	return
+	return name, nil
 }
 
 func createInterface(fd uintptr, ifName string, flags uint16) (createdIFName string, err error) {

+ 27 - 0
syscalls_linux_go1.11.go

@@ -0,0 +1,27 @@
+// +build linux,go1.11
+
+package water
+
+import (
+	"os"
+	"syscall"
+)
+
+func openDev(config Config) (ifce *Interface, err error) {
+	var fdInt int
+	if fdInt, err = syscall.Open(
+		"/dev/net/tun", os.O_RDWR|syscall.O_NONBLOCK, 0); err != nil {
+		return nil, err
+	}
+
+	name, err := setupFd(config, uintptr(fdInt))
+	if err != nil {
+		return nil, err
+	}
+
+	return &Interface{
+		isTAP:           config.DeviceType == TAP,
+		ReadWriteCloser: os.NewFile(uintptr(fdInt), "tun"),
+		name:            name,
+	}, nil
+}

+ 26 - 0
syscalls_linux_legacy.go

@@ -0,0 +1,26 @@
+// +build linux,!go1.11
+
+package water
+
+import (
+	"os"
+)
+
+func openDev(config Config) (ifce *Interface, err error) {
+	var file *os.File
+	if file, err = os.OpenFile(
+		"/dev/net/tun", os.O_RDWR, 0); err != nil {
+		return nil, err
+	}
+
+	name, err := setupFd(config, file.Fd())
+	if err != nil {
+		return nil, err
+	}
+
+	return &Interface{
+		isTAP:           config.DeviceType == TAP,
+		ReadWriteCloser: file,
+		name:            name,
+	}, nil
+}

+ 2 - 6
syscalls_other.go

@@ -4,10 +4,6 @@ package water
 
 import "errors"
 
-func newTAP(config Config) (ifce *Interface, err error) {
-	return nil, errors.New("tap interface not implemented on this platform")
-}
-
-func newTUN(config Config) (ifce *Interface, err error) {
-	return nil, errors.New("tap interface not implemented on this platform")
+func openDev(config Config) (*Interface, error) {
+	return nil, errors.New("not implemented on this platform")
 }

+ 0 - 8
syscalls_windows.go

@@ -306,11 +306,3 @@ func openDev(config Config) (ifce *Interface, err error) {
 
 	return nil, errIfceNameNotFound
 }
-
-func newTAP(config Config) (ifce *Interface, err error) {
-	return openDev(config)
-}
-
-func newTUN(config Config) (ifce *Interface, err error) {
-	return openDev(config)
-}