mirror of
https://github.com/yggdrasil-network/water.git
synced 2025-05-19 08:25:09 +03:00
use blocking mode pre-go1.11
This commit is contained in:
parent
240a3d7b51
commit
3fe638a7bf
13 changed files with 132 additions and 95 deletions
|
@ -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
|
||||
|
|
6
if.go
6
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")
|
||||
}
|
||||
|
|
|
@ -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
ipv4_go1.11_test.go
Normal file
36
ipv4_go1.11_test.go
Normal file
|
@ -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")
|
||||
}
|
||||
}
|
29
ipv4_test.go
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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
syscalls_darwin_go1.11.go
Normal file
9
syscalls_darwin_go1.11.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build darwin,go1.11
|
||||
|
||||
package water
|
||||
|
||||
import "syscall"
|
||||
|
||||
func setNonBlock(fd int) error {
|
||||
return syscall.SetNonblock(fd, true)
|
||||
}
|
10
syscalls_darwin_legacy.go
Normal file
10
syscalls_darwin_legacy.go
Normal file
|
@ -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
|
||||
}
|
|
@ -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 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: 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 err = setDeviceOptions(fd, config); err != nil {
|
||||
return nil, 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
syscalls_linux_go1.11.go
Normal file
27
syscalls_linux_go1.11.go
Normal file
|
@ -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
syscalls_linux_legacy.go
Normal file
26
syscalls_linux_legacy.go
Normal file
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue