From 8100eb92070eba89998d8971c185a245a6376dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Sun, 10 Nov 2019 12:42:55 +0100 Subject: [PATCH 1/3] use x/sys/unix instead of syscall to fix EpollWait on Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub SokoĊ‚owski --- .travis.yml | 1 + checker_linux.go | 6 +++--- err.go | 5 +++-- go.mod | 5 +++++ go.sum | 2 ++ socket.go | 19 ++++++++++--------- socket_linux.go | 35 +++++++++++++++++------------------ 7 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/.travis.yml b/.travis.yml index db9fcfb..070449e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 ./... diff --git a/checker_linux.go b/checker_linux.go index ef653b5..69c07be 100644 --- a/checker_linux.go +++ b/checker_linux.go @@ -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 { diff --git a/err.go b/err.go index f4bdf58..b83e190 100644 --- a/err.go +++ b/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. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5e07507 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/status-im/tcp-shaker + +go 1.13 + +require golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2bc7542 --- /dev/null +++ b/go.sum @@ -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= diff --git a/socket.go b/socket.go index dacfde6..6c9237a 100644 --- a/socket.go +++ b/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 diff --git a/socket_linux.go b/socket_linux.go index db6998b..21627e0 100644 --- a/socket_linux.go +++ b/socket_linux.go @@ -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) } From 04a3451fa2f0d182aafa91892c363f79a3ed2e1e Mon Sep 17 00:00:00 2001 From: Tevin Date: Tue, 12 Nov 2019 11:29:27 +0800 Subject: [PATCH 2/3] Update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5e07507..49cddcb 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/status-im/tcp-shaker +module github.com/tevino/tcp-shaker go 1.13 From 650050ef9be975a0a5ef09dac2e98f3f69ddd1bd Mon Sep 17 00:00:00 2001 From: Tevin Date: Tue, 12 Nov 2019 15:57:04 +0800 Subject: [PATCH 3/3] Add special thanks to @jakubgs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2b3b69d..9e18f72 100644 --- a/README.md +++ b/README.md @@ -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