func Pinger(address *net.IPAddr, timeout time.Duration) error { var ( c *net.IPConn err error ) v6 := address.IP.To4() == nil if v6 { c, err = net.DialIP("ip6:ipv6-icmp", nil, address) } else { c, err = net.DialIP("ip4:icmp", nil, address) } if err != nil { return err } c.SetDeadline(time.Now().Add(timeout)) defer c.Close() typ := icmpv4EchoRequest if v6 { typ = icmpv6EchoRequest } xid, xseq := os.Getpid()&0xffff, 1 wb, err := (&icmpMessage{ Type: typ, Code: 0, Body: &icmpEcho{ ID: xid, Seq: xseq, Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3), }, }).Marshal() if err != nil { return err } if _, err = c.Write(wb); err != nil { return err } var m *icmpMessage rb := make([]byte, 20+len(wb)) for { if _, err = c.Read(rb); err != nil { return err } if !v6 { rb = ipv4Payload(rb) } if m, err = parseICMPMessage(rb); err != nil { return err } switch m.Type { case icmpv4EchoRequest, icmpv6EchoRequest: continue } break } return nil }
func (p *Pinger) run(once bool) { p.debugln("Run(): Start") var conn, conn6 *net.IPConn if p.hasIPv4 { if conn = p.listen("ip4:icmp"); conn == nil { return } defer conn.Close() } if p.hasIPv6 { if conn6 = p.listen("ip6:ipv6-icmp"); conn6 == nil { return } defer conn6.Close() } recv := make(chan *packet, 1) recvCtx := newContext() wg := new(sync.WaitGroup) p.debugln("Run(): call recvICMP()") if conn != nil { wg.Add(1) go p.recvICMP(conn, recv, recvCtx, wg) } if conn6 != nil { wg.Add(1) go p.recvICMP(conn6, recv, recvCtx, wg) } p.debugln("Run(): call sendICMP()") queue, err := p.sendICMP(conn, conn6) ticker := time.NewTicker(p.MaxRTT) mainloop: for { select { case <-p.ctx.stop: p.debugln("Run(): <-p.ctx.stop") break mainloop case <-recvCtx.done: p.debugln("Run(): <-recvCtx.done") p.mu.Lock() err = recvCtx.err p.mu.Unlock() break mainloop case <-ticker.C: p.mu.Lock() handler := p.OnIdle p.mu.Unlock() if handler != nil { handler() } if once || err != nil { break mainloop } p.debugln("Run(): call sendICMP()") queue, err = p.sendICMP(conn, conn6) case r := <-recv: p.debugln("Run(): <-recv") p.procRecv(r, queue) } } ticker.Stop() p.debugln("Run(): close(recvCtx.stop)") close(recvCtx.stop) p.debugln("Run(): wait recvICMP()") wg.Wait() p.mu.Lock() p.ctx.err = err p.mu.Unlock() p.debugln("Run(): close(p.ctx.done)") close(p.ctx.done) p.debugln("Run(): End") }