package main import ( "flag" "fmt" "net" "os" "os/signal" "strings" "syscall" "time" "github.com/tatsushid/go-fastping" ) type response struct { addr *net.IPAddr rtt time.Duration } func main() { var useUDP bool flag.BoolVar(&useUDP, "udp", false, "use non-privileged datagram-oriented UDP as ICMP endpoints") flag.BoolVar(&useUDP, "u", false, "use non-privileged datagram-oriented UDP as ICMP endpoints (shorthand)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage:\n %s [options] hostname\n\nOptions:\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() hostname := flag.Arg(0) if len(hostname) == 0 { flag.Usage() os.Exit(1) } p := fastping.NewPinger() if useUDP { p.Network("udp") } netProto := "ip4:icmp" if strings.Index(hostname, ":") != -1 { netProto = "ip6:ipv6-icmp" } ra, err := net.ResolveIPAddr(netProto, hostname) if err != nil { fmt.Println(err) os.Exit(1) } results := make(map[string]*response) results[ra.String()] = nil p.AddIPAddr(ra) onRecv, onIdle := make(chan *response), make(chan bool) p.OnRecv = func(addr *net.IPAddr, t time.Duration) { onRecv <- &response{addr: addr, rtt: t} } p.OnIdle = func() { onIdle <- true } p.MaxRTT = time.Second p.RunLoop() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) signal.Notify(c, syscall.SIGTERM) loop: for { select { case <-c: fmt.Println("get interrupted") break loop case res := <-onRecv: if _, ok := results[res.addr.String()]; ok { results[res.addr.String()] = res } case <-onIdle: for host, r := range results { if r == nil { fmt.Printf("%s : unreachable %v\n", host, time.Now()) } else { fmt.Printf("%s : %v %v\n", host, r.rtt, time.Now()) } results[host] = nil } case <-p.Done(): if err = p.Err(); err != nil { fmt.Println("Ping failed:", err) } break loop } } signal.Stop(c) p.Stop() }