117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"time"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
var addresses = []string{
|
|
"8.8.8.8:53", // will succeed
|
|
//"8.8.8.8:88", // will fail
|
|
}
|
|
|
|
const timeout time.Duration = 2000 * time.Millisecond
|
|
|
|
func parseSockAddr(addr string) (unix.Sockaddr, error) {
|
|
tAddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var addr4 [4]byte
|
|
if tAddr.IP != nil {
|
|
copy(addr4[:], tAddr.IP.To4()) // copy last 4 bytes of slice to array
|
|
}
|
|
return &unix.SockaddrInet4{Port: tAddr.Port, Addr: addr4}, nil
|
|
}
|
|
|
|
func Ping(address string, timeout time.Duration) error {
|
|
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
|
|
if err != nil {
|
|
return os.NewSyscallError("socket", err)
|
|
}
|
|
unix.CloseOnExec(fd)
|
|
log.Println("Socket FD:", fd)
|
|
|
|
err = unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_QUICKACK, 0)
|
|
if err != nil {
|
|
return os.NewSyscallError("setsockopt", err)
|
|
}
|
|
|
|
var zeroLinger = unix.Linger{Onoff: 1, Linger: 0}
|
|
err = unix.SetsockoptLinger(fd, unix.SOL_SOCKET, unix.SO_LINGER, &zeroLinger)
|
|
if err != nil {
|
|
return os.NewSyscallError("setsockoptlinger", err)
|
|
}
|
|
|
|
rAddr, err := parseSockAddr(address)
|
|
if err != nil {
|
|
return errors.New("failed to parse address")
|
|
}
|
|
|
|
err = unix.Connect(fd, rAddr)
|
|
if err != nil {
|
|
return os.NewSyscallError("connect", err)
|
|
}
|
|
|
|
epfd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
|
if err != nil {
|
|
return os.NewSyscallError("epoll_create1", err)
|
|
}
|
|
log.Println("Epoll FD:", epfd)
|
|
|
|
var event unix.EpollEvent
|
|
event.Events = (unix.EPOLLOUT | unix.EPOLLIN | unix.EPOLLET)
|
|
event.Fd = int32(fd)
|
|
|
|
err = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, fd, &event)
|
|
if err != nil {
|
|
return os.NewSyscallError("epoll_ctl", err)
|
|
}
|
|
|
|
var epollEvents [1]unix.EpollEvent
|
|
var nEvents int
|
|
nEvents, err = unix.EpollWait(epfd, epollEvents[:], int(timeout.Milliseconds()))
|
|
|
|
log.Println("EpollWait err:", err)
|
|
if err != nil {
|
|
return os.NewSyscallError("epoll_wait", err)
|
|
}
|
|
|
|
log.Println("EpollWait #:", nEvents)
|
|
if nEvents == 0 {
|
|
return errors.New("no events found")
|
|
}
|
|
|
|
errCode, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_ERROR)
|
|
if err != nil {
|
|
return os.NewSyscallError("getsockoptint", err)
|
|
}
|
|
log.Println("SO_ERROR:", errCode)
|
|
|
|
log.Println("EpollEvent:", epollEvents[0])
|
|
if epollEvents[0].Events&unix.EPOLLOUT != 0 {
|
|
return nil
|
|
}
|
|
|
|
return errors.New("UNKNOWN ")
|
|
}
|
|
|
|
func main() {
|
|
log.SetPrefix("TCP_PING:")
|
|
|
|
for i := 0; i < len(addresses); i++ {
|
|
log.Println("PINGING:", addresses[i])
|
|
err := Ping(addresses[i], timeout)
|
|
if err != nil {
|
|
log.Println("FAILURE:", err)
|
|
} else {
|
|
log.Println("SUCCESS")
|
|
}
|
|
}
|
|
}
|