Merge pull request #18 from status-im/fix-android
Use x/sys/unix instead of syscall to fix EpollWait on Android
This commit is contained in:
commit
5aa79aeb78
|
@ -7,5 +7,6 @@ go:
|
|||
- "1.11.x"
|
||||
install:
|
||||
- go get "github.com/pkg/errors"
|
||||
- go get "golang.org/x/sys/unix"
|
||||
script: go test -v -bench=. -benchmem ./...
|
||||
|
||||
|
|
|
@ -86,5 +86,6 @@ conn.Close()
|
|||
## Special thanks to contributors
|
||||
|
||||
- @lujjjh
|
||||
- @jakubgs Fixed compatibility on Android
|
||||
|
||||
[tcp-handshake]: https://en.wikipedia.org/wiki/Handshaking#TCP_three-way_handshake
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Checker contains an epoll instance for TCP handshake checking
|
||||
|
@ -74,7 +74,7 @@ func (c *Checker) closePoller() error {
|
|||
defer c.pollerLock.Unlock()
|
||||
var err error
|
||||
if c.pollerFD() > 0 {
|
||||
err = syscall.Close(c.pollerFD())
|
||||
err = unix.Close(c.pollerFD())
|
||||
}
|
||||
c.setPollerFD(-1)
|
||||
return err
|
||||
|
@ -151,7 +151,7 @@ func (c *Checker) CheckAddrZeroLinger(addr string, timeout time.Duration, zeroLi
|
|||
return err
|
||||
}
|
||||
// Socket should be closed anyway
|
||||
defer syscall.Close(fd)
|
||||
defer unix.Close(fd)
|
||||
|
||||
// Connect to the address
|
||||
if success, cErr := connect(fd, rAddr); cErr != nil {
|
||||
|
|
5
err.go
5
err.go
|
@ -2,7 +2,8 @@ package tcp
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrTimeout indicates I/O timeout
|
||||
|
@ -22,7 +23,7 @@ type ErrConnect struct {
|
|||
|
||||
// newErrConnect returns a ErrConnect with given error code
|
||||
func newErrConnect(errCode int) *ErrConnect {
|
||||
return &ErrConnect{syscall.Errno(errCode)}
|
||||
return &ErrConnect{unix.Errno(errCode)}
|
||||
}
|
||||
|
||||
// ErrCheckerAlreadyStarted indicates there is another instance of CheckingLoop running.
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
module github.com/tevino/tcp-shaker
|
||||
|
||||
go 1.13
|
||||
|
||||
require golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 // indirect
|
|
@ -0,0 +1,2 @@
|
|||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM=
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
19
socket.go
19
socket.go
|
@ -3,11 +3,12 @@ package tcp
|
|||
import (
|
||||
"net"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// parseSockAddr resolves given addr to syscall.Sockaddr
|
||||
func parseSockAddr(addr string) (syscall.Sockaddr, error) {
|
||||
// parseSockAddr resolves given addr to unix.Sockaddr
|
||||
func parseSockAddr(addr string) (unix.Sockaddr, error) {
|
||||
tAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -16,21 +17,21 @@ func parseSockAddr(addr string) (syscall.Sockaddr, error) {
|
|||
if tAddr.IP != nil {
|
||||
copy(addr4[:], tAddr.IP.To4()) // copy last 4 bytes of slice to array
|
||||
}
|
||||
return &syscall.SockaddrInet4{Port: tAddr.Port, Addr: addr4}, nil
|
||||
return &unix.SockaddrInet4{Port: tAddr.Port, Addr: addr4}, nil
|
||||
}
|
||||
|
||||
// connect calls the connect syscall with error handled.
|
||||
func connect(fd int, addr syscall.Sockaddr) (success bool, err error) {
|
||||
switch serr := syscall.Connect(fd, addr); serr {
|
||||
case syscall.EALREADY, syscall.EINPROGRESS, syscall.EINTR:
|
||||
func connect(fd int, addr unix.Sockaddr) (success bool, err error) {
|
||||
switch serr := unix.Connect(fd, addr); serr {
|
||||
case unix.EALREADY, unix.EINPROGRESS, unix.EINTR:
|
||||
// Connection could not be made immediately but asynchronously.
|
||||
success = false
|
||||
err = nil
|
||||
case nil, syscall.EISCONN:
|
||||
case nil, unix.EISCONN:
|
||||
// The specified socket is already connected.
|
||||
success = true
|
||||
err = nil
|
||||
case syscall.EINVAL:
|
||||
case unix.EINVAL:
|
||||
// On Solaris we can see EINVAL if the socket has
|
||||
// already been accepted and closed by the server.
|
||||
// Treat this as a successful connection--writes to
|
||||
|
|
|
@ -3,8 +3,9 @@ package tcp
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const maxEpollEvents = 32
|
||||
|
@ -31,50 +32,48 @@ func _createNonBlockingSocket() (int, error) {
|
|||
// Set necessary options
|
||||
err = _setSockOpts(fd)
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
unix.Close(fd)
|
||||
}
|
||||
return fd, err
|
||||
}
|
||||
|
||||
// createSocket creates a socket with CloseOnExec set
|
||||
func _createSocket() (int, error) {
|
||||
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
|
||||
syscall.CloseOnExec(fd)
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
|
||||
unix.CloseOnExec(fd)
|
||||
return fd, err
|
||||
}
|
||||
|
||||
// setSockOpts sets SOCK_NONBLOCK and TCP_QUICKACK for given fd
|
||||
func _setSockOpts(fd int) error {
|
||||
err := syscall.SetNonblock(fd, true)
|
||||
err := unix.SetNonblock(fd, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syscall.SetsockoptInt(fd, syscall.SOL_TCP, syscall.TCP_QUICKACK, 0)
|
||||
return unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_QUICKACK, 0)
|
||||
}
|
||||
|
||||
var zeroLinger = syscall.Linger{Onoff: 1, Linger: 0}
|
||||
var zeroLinger = unix.Linger{Onoff: 1, Linger: 0}
|
||||
|
||||
// setLinger sets SO_Linger with 0 timeout to given fd
|
||||
func _setZeroLinger(fd int) error {
|
||||
return syscall.SetsockoptLinger(fd, syscall.SOL_SOCKET, syscall.SO_LINGER, &zeroLinger)
|
||||
return unix.SetsockoptLinger(fd, unix.SOL_SOCKET, unix.SO_LINGER, &zeroLinger)
|
||||
}
|
||||
|
||||
func createPoller() (fd int, err error) {
|
||||
fd, err = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC)
|
||||
fd, err = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||
if err != nil {
|
||||
err = os.NewSyscallError("epoll_create1", err)
|
||||
}
|
||||
return fd, err
|
||||
}
|
||||
|
||||
const epollET = 1 << 31
|
||||
|
||||
// registerEvents registers given fd with read and write events.
|
||||
func registerEvents(pollerFd int, fd int) error {
|
||||
var event syscall.EpollEvent
|
||||
event.Events = syscall.EPOLLOUT | syscall.EPOLLIN | epollET
|
||||
var event unix.EpollEvent
|
||||
event.Events = unix.EPOLLOUT | unix.EPOLLIN | unix.EPOLLET
|
||||
event.Fd = int32(fd)
|
||||
if err := syscall.EpollCtl(pollerFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
|
||||
if err := unix.EpollCtl(pollerFd, unix.EPOLL_CTL_ADD, fd, &event); err != nil {
|
||||
return os.NewSyscallError(fmt.Sprintf("epoll_ctl(%d, ADD, %d, ...)", pollerFd, fd), err)
|
||||
}
|
||||
return nil
|
||||
|
@ -82,10 +81,10 @@ func registerEvents(pollerFd int, fd int) error {
|
|||
|
||||
func pollEvents(pollerFd int, timeout time.Duration) ([]event, error) {
|
||||
var timeoutMS = int(timeout.Nanoseconds() / 1000000)
|
||||
var epollEvents [maxEpollEvents]syscall.EpollEvent
|
||||
nEvents, err := syscall.EpollWait(pollerFd, epollEvents[:], timeoutMS)
|
||||
var epollEvents [maxEpollEvents]unix.EpollEvent
|
||||
nEvents, err := unix.EpollWait(pollerFd, epollEvents[:], timeoutMS)
|
||||
if err != nil {
|
||||
if err == syscall.EINTR {
|
||||
if err == unix.EINTR {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, os.NewSyscallError("epoll_wait", err)
|
||||
|
@ -97,7 +96,7 @@ func pollEvents(pollerFd int, timeout time.Duration) ([]event, error) {
|
|||
var fd = int(epollEvents[i].Fd)
|
||||
var evt = event{Fd: fd, Err: nil}
|
||||
|
||||
errCode, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR)
|
||||
errCode, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_ERROR)
|
||||
if err != nil {
|
||||
evt.Err = os.NewSyscallError("getsockopt", err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue