func pkt(ip [4]byte) []byte { h := ipv4.Header{ Version: 4, Len: 20, TotalLen: 20 + 10, // 20 bytes for IP, 10 for ICMP TTL: 64, Protocol: 1, // ICMP Dst: net.IPv4(ip[0], ip[1], ip[2], ip[3]), // ID, Src and Checksum will be set for us by the kernel } icmp := []byte{ 8, // type: echo request 0, // code: not used by echo request 0, // checksum (16 bit), we fill in below 0, 0, // identifier (16 bit). zero allowed. 0, 0, // sequence number (16 bit). zero allowed. 0, 0xC0, // Optional data. ping puts time packet sent here 0xDE, } cs := csum(icmp) icmp[2] = byte(cs) icmp[3] = byte(cs >> 8) out, err := h.Marshal() if err != nil { glog.Error(err) } return append(out, icmp...) }
func (this *Pinger) sendMessage(m *icmp.Message, wh *ipv4.Header) error { select { case <-this.done: return nil default: } var ( wb []byte tempDelay time.Duration // how long to sleep on accept failure ticker = time.NewTicker(this.Interval) ) for i, dst := range this.IPs() { if i != 0 { <-ticker.C } binary.BigEndian.PutUint64(this.payload, uint64(time.Now().UnixNano())) wb, err := this.marshalMessage(m, wb) if err != nil { glog.Errorf("Error creating ICMP payload: %v", err) continue } wh.TotalLen = ipv4.HeaderLen + len(wb) wh.Dst = dst glog.Debugf("Pinging %s", wh.Dst) this.mu.Lock() this.results[wh.Dst.String()] = nil this.mu.Unlock() if err := this.rconn.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { return err } if err := this.rconn.WriteTo(wh, wb, nil); err != nil { select { case <-this.done: return nil default: } // Borrowed from go1.3.3/src/pkg/net/http/server.go:1699 if ne, ok := err.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } glog.Errorf("write error: %v; retrying in %v", err, tempDelay) time.Sleep(tempDelay) continue // out of the IP list, wait for next tick } return err } } if err := this.rconn.SetReadDeadline(time.Now().Add(this.MaxRTT)); err != nil { return err } return nil }