ping.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. // Package probing is a simple but powerful ICMP echo (ping) library.
  2. //
  3. // Here is a very simple example that sends and receives three packets:
  4. //
  5. // pinger, err := probing.NewPinger("www.google.com")
  6. // if err != nil {
  7. // panic(err)
  8. // }
  9. // pinger.Count = 3
  10. // err = pinger.Run() // blocks until finished
  11. // if err != nil {
  12. // panic(err)
  13. // }
  14. // stats := pinger.Statistics() // get send/receive/rtt stats
  15. //
  16. // Here is an example that emulates the traditional UNIX ping command:
  17. //
  18. // pinger, err := probing.NewPinger("www.google.com")
  19. // if err != nil {
  20. // panic(err)
  21. // }
  22. // // Listen for Ctrl-C.
  23. // c := make(chan os.Signal, 1)
  24. // signal.Notify(c, os.Interrupt)
  25. // go func() {
  26. // for _ = range c {
  27. // pinger.Stop()
  28. // }
  29. // }()
  30. // pinger.OnRecv = func(pkt *probing.Packet) {
  31. // fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n",
  32. // pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
  33. // }
  34. // pinger.OnFinish = func(stats *probing.Statistics) {
  35. // fmt.Printf("\n--- %s ping statistics ---\n", stats.Addr)
  36. // fmt.Printf("%d packets transmitted, %d packets received, %v%% packet loss\n",
  37. // stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
  38. // fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
  39. // stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
  40. // }
  41. // fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr())
  42. // err = pinger.Run()
  43. // if err != nil {
  44. // panic(err)
  45. // }
  46. //
  47. // It sends ICMP Echo Request packet(s) and waits for an Echo Reply in response.
  48. // If it receives a response, it calls the OnRecv callback. When it's finished,
  49. // it calls the OnFinish callback.
  50. //
  51. // For a full ping example, see "cmd/ping/ping.go".
  52. package probing
  53. import (
  54. "errors"
  55. "math"
  56. "math/rand"
  57. "net"
  58. "sync"
  59. "sync/atomic"
  60. "time"
  61. "trial/ping/probing/icmp"
  62. "golang.org/x/sync/errgroup"
  63. )
  64. var receive_buffer_count = mcfg.GetInt("ping.recv.buf.count", 500)
  65. var ping_ttl = mcfg.GetInt("ping.ttl", 64)
  66. // var ping_interval = mcfg.GetDuration("ping.interval", 1000*time.Millisecond)
  67. // var concurlimit_ping = mcfg.GetInt("concurlimit.ping", 100)
  68. // var concurchan_ping = make(chan struct{}, concurlimit_ping)
  69. // var lastpingtimemutex sync.Mutex
  70. // var lastpingtime = map[string]time.Time{}
  71. // var ETIMEDOUT error = fmt.Errorf("timeout")
  72. // const (
  73. // timeSliceLength = 8
  74. // trackerLength = len(uuid.UUID{})
  75. // )
  76. // New returns a new Pinger struct pointer.
  77. func New(addr string) *Pinger {
  78. r := rand.New(rand.NewSource(getSeed()))
  79. return &Pinger{
  80. Count: -1,
  81. Interval: time.Second,
  82. RecordRtts: true,
  83. Size: 64, // timeSliceLength + trackerLength,
  84. Timeout: time.Duration(math.MaxInt64),
  85. addr: addr,
  86. done: make(chan interface{}),
  87. id: r.Intn(math.MaxUint16),
  88. ipaddr: nil,
  89. ipv4: false,
  90. network: "ip",
  91. protocol: "udp",
  92. }
  93. }
  94. // NewPinger returns a new Pinger and resolves the address.
  95. func NewPinger(addr string) (*Pinger, error) {
  96. p := New(addr)
  97. return p, p.Resolve()
  98. }
  99. // Pinger represents a packet sender/receiver.
  100. type Pinger struct {
  101. // Size of packet being sent
  102. Size int
  103. // Interval is the wait time between each packet send. Default is 1s.
  104. Interval time.Duration
  105. // Timeout specifies a timeout before ping exits, regardless of how many
  106. // packets have been received.
  107. Timeout time.Duration
  108. // Count tells pinger to stop after sending (and receiving) Count echo
  109. // packets. If this option is not specified, pinger will operate until
  110. // interrupted.
  111. Count int
  112. // Number of packets sent
  113. PacketsSent int
  114. // Number of packets received
  115. PacketsRecv int
  116. // Number of duplicate packets received
  117. PacketsRecvDuplicates int
  118. // Round trip time statistics
  119. minRtt time.Duration
  120. maxRtt time.Duration
  121. avgRtt time.Duration
  122. stdDevRtt time.Duration
  123. stddevm2 time.Duration
  124. statsMu sync.RWMutex
  125. // If true, keep a record of rtts of all received packets.
  126. // Set to false to avoid memory bloat for long running pings.
  127. RecordRtts bool
  128. // rtts is all of the Rtts
  129. rtts []time.Duration
  130. // OnSetup is called when Pinger has finished setting up the listening socket
  131. OnSetup func()
  132. // OnSend is called when Pinger sends a packet
  133. OnSend func(*Packet)
  134. // OnRecv is called when Pinger receives and processes a packet
  135. OnRecv func(*Packet)
  136. // OnRecv is called when Pinger receives and processes a packet
  137. OnTimeout func(*Packet)
  138. // OnFinish is called when Pinger exits
  139. OnFinish func(*Statistics)
  140. // OnDuplicateRecv is called when a packet is received that has already been received.
  141. OnDuplicateRecv func(*Packet)
  142. // Source is the source IP address
  143. Source string
  144. // Channel and mutex used to communicate when the Pinger should stop between goroutines.
  145. done chan interface{}
  146. lock sync.Mutex
  147. ipaddr *net.IPAddr
  148. addr string
  149. ipv4 bool
  150. id int
  151. sequence_base int
  152. // network is one of "ip", "ip4", or "ip6".
  153. network string
  154. // protocol is "icmp" or "udp".
  155. protocol string
  156. }
  157. // Packet represents a received and processed ICMP echo packet.
  158. type Packet struct {
  159. // Host is the string address of the host being pinged.
  160. Host string
  161. // IPAddr is the address of the host being pinged.
  162. IPAddr *net.IPAddr
  163. // ID is the ICMP identifier.
  164. ID int
  165. // Seq is the ICMP sequence number.
  166. Seq int
  167. // NBytes is the number of bytes in the message.
  168. Nbytes int
  169. // TTL is the Time To Live on the packet.
  170. TTL int
  171. // Rtt is the round-trip time it took to ping.
  172. Rtt time.Duration
  173. }
  174. // Statistics represent the stats of a currently running or finished
  175. // pinger operation.
  176. type Statistics struct {
  177. // PacketsRecv is the number of packets received.
  178. PacketsRecv int
  179. // PacketsSent is the number of packets sent.
  180. PacketsSent int
  181. // PacketsRecvDuplicates is the number of duplicate responses there were to a sent packet.
  182. PacketsRecvDuplicates int
  183. // PacketLoss is the percentage of packets lost.
  184. PacketLoss float64
  185. // IPAddr is the address of the host being pinged.
  186. IPAddr *net.IPAddr
  187. // Addr is the string address of the host being pinged.
  188. Addr string
  189. // Rtts is all of the round-trip times sent via this pinger.
  190. Rtts []time.Duration
  191. // MinRtt is the minimum round-trip time sent via this pinger.
  192. MinRtt time.Duration
  193. // MaxRtt is the maximum round-trip time sent via this pinger.
  194. MaxRtt time.Duration
  195. // AvgRtt is the average round-trip time sent via this pinger.
  196. AvgRtt time.Duration
  197. // StdDevRtt is the standard deviation of the round-trip times sent via
  198. // this pinger.
  199. StdDevRtt time.Duration
  200. }
  201. func (p *Pinger) updateStatistics(pkt *Packet) {
  202. p.statsMu.Lock()
  203. defer p.statsMu.Unlock()
  204. p.PacketsRecv++
  205. if p.RecordRtts {
  206. // p.rtts = append(p.rtts, pkt.Rtt)
  207. p.rtts[pkt.Seq] = pkt.Rtt
  208. }
  209. if p.PacketsRecv == 1 || pkt.Rtt < p.minRtt {
  210. p.minRtt = pkt.Rtt
  211. }
  212. if pkt.Rtt > p.maxRtt {
  213. p.maxRtt = pkt.Rtt
  214. }
  215. pktCount := time.Duration(p.PacketsRecv)
  216. // welford's online method for stddev
  217. // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
  218. delta := pkt.Rtt - p.avgRtt
  219. p.avgRtt += delta / pktCount
  220. delta2 := pkt.Rtt - p.avgRtt
  221. p.stddevm2 += delta * delta2
  222. p.stdDevRtt = time.Duration(math.Sqrt(float64(p.stddevm2 / pktCount)))
  223. }
  224. // SetIPAddr sets the ip address of the target host.
  225. func (p *Pinger) SetIPAddr(ipaddr *net.IPAddr) {
  226. p.ipv4 = isIPv4(ipaddr.IP)
  227. p.ipaddr = ipaddr
  228. p.addr = ipaddr.String()
  229. }
  230. // IPAddr returns the ip address of the target host.
  231. func (p *Pinger) IPAddr() *net.IPAddr {
  232. return p.ipaddr
  233. }
  234. // Resolve does the DNS lookup for the Pinger address and sets IP protocol.
  235. func (p *Pinger) Resolve() error {
  236. if len(p.addr) == 0 {
  237. return errors.New("addr cannot be empty")
  238. }
  239. ipaddr, err := net.ResolveIPAddr(p.network, p.addr)
  240. if err != nil {
  241. return err
  242. }
  243. p.ipv4 = isIPv4(ipaddr.IP)
  244. p.ipaddr = ipaddr
  245. return nil
  246. }
  247. // SetAddr resolves and sets the ip address of the target host, addr can be a
  248. // DNS name like "www.google.com" or IP like "127.0.0.1".
  249. func (p *Pinger) SetAddr(addr string) error {
  250. oldAddr := p.addr
  251. p.addr = addr
  252. err := p.Resolve()
  253. if err != nil {
  254. p.addr = oldAddr
  255. return err
  256. }
  257. return nil
  258. }
  259. // Addr returns the string ip address of the target host.
  260. func (p *Pinger) Addr() string {
  261. return p.addr
  262. }
  263. // SetNetwork allows configuration of DNS resolution.
  264. // * "ip" will automatically select IPv4 or IPv6.
  265. // * "ip4" will select IPv4.
  266. // * "ip6" will select IPv6.
  267. func (p *Pinger) SetNetwork(n string) {
  268. switch n {
  269. case "ip4":
  270. p.network = "ip4"
  271. case "ip6":
  272. p.network = "ip6"
  273. default:
  274. p.network = "ip"
  275. }
  276. }
  277. /*
  278. https://stackoverflow.com/questions/41423637/go-ping-library-for-unprivileged-icmp-ping-in-golang/41425527#41425527
  279. This library attempts to send an "unprivileged" ping via UDP. On linux, this must be enabled by setting
  280. sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
  281. If you do not wish to do this, you can set pinger.SetPrivileged(true) and use setcap to allow your binary using go-ping to bind to raw sockets (or just run as super-user):
  282. setcap cap_net_raw=+ep /bin/goping-binary
  283. getcap /bin/goping-binary to validate
  284. */
  285. // SetPrivileged sets the type of ping pinger will send.
  286. // false means pinger will send an "unprivileged" UDP ping.
  287. // true means pinger will send a "privileged" raw ICMP ping.
  288. // NOTE: setting to true requires that it be run with super-user privileges.
  289. func (p *Pinger) SetPrivileged(privileged bool) {
  290. if privileged {
  291. p.protocol = "icmp"
  292. } else {
  293. p.protocol = "udp"
  294. }
  295. }
  296. // Privileged returns whether pinger is running in privileged mode.
  297. func (p *Pinger) Privileged() bool {
  298. return p.protocol == "icmp"
  299. }
  300. // SetID sets the ICMP identifier.
  301. func (p *Pinger) SetID(id int) {
  302. p.id = id
  303. }
  304. // ID returns the ICMP identifier.
  305. func (p *Pinger) ID() int {
  306. return p.id
  307. }
  308. var pingipmtx sync.Mutex
  309. var pingips = map[string]chan interface{}{}
  310. var pingads = map[string]chan interface{}{}
  311. // Run runs the pinger. This is a blocking function that will exit when it's
  312. // done. If Count or Interval are not specified, it will run continuously until
  313. // it is interrupted.
  314. func (p *Pinger) Run() (err error) {
  315. // 同一地址,只能有一个实例运行,排队等待
  316. pingipmtx.Lock()
  317. pingipchan := pingips[p.ipaddr.String()]
  318. if pingipchan == nil {
  319. pingipchan = make(chan interface{}, 1)
  320. pingips[p.ipaddr.String()] = pingipchan
  321. }
  322. pingadchan := pingads[p.addr]
  323. if pingadchan == nil {
  324. pingadchan = make(chan interface{}, 1)
  325. pingads[p.addr] = pingadchan
  326. }
  327. pingipmtx.Unlock()
  328. pingipchan <- 1
  329. pingadchan <- 1
  330. var last_send_time time.Time
  331. defer func() {
  332. d := p.Interval - time.Since(last_send_time)
  333. if d > 0 {
  334. time.Sleep(d) // 两次运行之间至少间隔
  335. }
  336. <-pingipchan
  337. <-pingadchan
  338. }()
  339. // sleeptime := time.Duration(0)
  340. // for sleeptime >= 0 {
  341. // time.Sleep(sleeptime)
  342. // lastpingtimemutex.Lock()
  343. // alastpingtime := lastpingtime[p.ipaddr.String()]
  344. // sleeptime = ping_interval_one_host - time.Since(alastpingtime)
  345. // if sleeptime <= 0 {
  346. // lastpingtime[p.ipaddr.String()] = time.Now()
  347. // } else {
  348. // // logger.Error(fmt.Sprint("ping", p.addr, "[", p.ipaddr.String(), "]", "同一地址至少间隔一秒"))
  349. // }
  350. // lastpingtimemutex.Unlock()
  351. // }
  352. // defer func() {
  353. // lastpingtimemutex.Lock()
  354. // lastpingtime[p.ipaddr.String()] = time.Now()
  355. // lastpingtimemutex.Unlock()
  356. // }()
  357. // concurchan_ping <- struct{}{}
  358. // defer func() {
  359. // <-concurchan_ping
  360. // }()
  361. last_send_time, err = p.run()
  362. return
  363. }
  364. func (p *Pinger) init() *mpinfo {
  365. pinfo := getPingInfo(p.ipaddr)
  366. pinfo.host = p.addr
  367. pinfo.size = p.Size
  368. pinfo.timeout = p.Timeout
  369. p.sequence_base = pinfo.lastseq
  370. if p.RecordRtts {
  371. p.rtts = make([]time.Duration, p.Count)
  372. }
  373. return pinfo
  374. }
  375. func (p *Pinger) run() (time.Time, error) {
  376. pinfo := p.init()
  377. defer p.finish()
  378. err := MPConn(p.ipv4, p.protocol).Listen()
  379. if err != nil {
  380. return time.Time{}, err
  381. }
  382. if handler := p.OnSetup; handler != nil {
  383. handler()
  384. }
  385. var g errgroup.Group
  386. var last_send_time time.Time
  387. g.Go(func() (err error) {
  388. defer p.Stop()
  389. last_send_time, err = p.runLoop(pinfo)
  390. return err
  391. })
  392. return last_send_time, g.Wait()
  393. }
  394. func (p *Pinger) runLoop(pinfo *mpinfo) (time.Time, error) {
  395. timeout := time.NewTimer(p.Timeout)
  396. interval := time.NewTimer(0)
  397. timeout.Stop()
  398. defer func() {
  399. interval.Stop()
  400. timeout.Stop()
  401. }()
  402. received := make(chan interface{}, 1)
  403. last_send_time := time.Now()
  404. pinfo.OnSend = func(pkt *icmp.Packet) {
  405. last_send_time = pkt.SendTime
  406. seq := pkt.Seq - p.sequence_base
  407. if seq < 0 || seq >= p.Count {
  408. return
  409. }
  410. p.PacketsSent++
  411. if p.OnSend != nil {
  412. p.OnSend(&Packet{
  413. Host: p.addr,
  414. IPAddr: pkt.IPAddr,
  415. ID: p.id,
  416. Seq: seq,
  417. Nbytes: pkt.Nbytes,
  418. TTL: pkt.TTL,
  419. Rtt: pkt.Rtt,
  420. })
  421. }
  422. }
  423. pinfo.OnRecv = func(pkt *icmp.Packet) {
  424. seq := pkt.Seq - p.sequence_base
  425. if seq < 0 || seq >= p.Count {
  426. return
  427. }
  428. inpkt := &Packet{
  429. Host: p.addr,
  430. IPAddr: pkt.IPAddr,
  431. ID: p.id,
  432. Seq: seq,
  433. Nbytes: pkt.Nbytes,
  434. TTL: pkt.TTL,
  435. Rtt: pkt.Rtt,
  436. }
  437. if p.OnRecv != nil {
  438. p.OnRecv(inpkt)
  439. }
  440. p.updateStatistics(inpkt)
  441. received <- nil
  442. }
  443. pinfo.OnRecvDup = func(pkt *icmp.Packet) {
  444. seq := pkt.Seq - p.sequence_base
  445. if seq < 0 || seq >= p.Count {
  446. return
  447. }
  448. inpkt := &Packet{
  449. Host: p.addr,
  450. IPAddr: pkt.IPAddr,
  451. ID: p.id,
  452. Seq: seq,
  453. Nbytes: pkt.Nbytes,
  454. TTL: pkt.TTL,
  455. Rtt: pkt.Rtt,
  456. }
  457. if p.OnDuplicateRecv != nil {
  458. p.OnDuplicateRecv(inpkt)
  459. }
  460. }
  461. pinfo.OnRecvTimeout = func(pkt *icmp.Packet) {
  462. seq := pkt.Seq - p.sequence_base
  463. if seq < 0 || seq >= p.Count {
  464. return
  465. }
  466. outpkt := &Packet{
  467. Host: p.addr,
  468. IPAddr: pkt.IPAddr,
  469. ID: p.id,
  470. Seq: seq,
  471. Nbytes: pkt.Nbytes,
  472. TTL: pkt.TTL,
  473. Rtt: pkt.Rtt,
  474. }
  475. if p.OnTimeout != nil {
  476. p.OnTimeout(outpkt)
  477. }
  478. }
  479. for {
  480. select {
  481. case <-p.done:
  482. return last_send_time, nil
  483. case <-timeout.C:
  484. return last_send_time, nil
  485. case <-interval.C:
  486. if p.Count > 0 && p.PacketsSent >= p.Count {
  487. timeout.Reset(p.Timeout)
  488. } else {
  489. if err := MPConn(p.ipv4, p.protocol).Ping(pinfo); err != nil {
  490. logger.Errorf("sending packet: %s", err)
  491. }
  492. interval.Reset(p.Interval)
  493. }
  494. case <-received:
  495. if p.Count > 0 && p.PacketsRecv >= p.Count {
  496. return last_send_time, nil
  497. }
  498. }
  499. }
  500. }
  501. // func (p *Pinger) ping(pinfo *mpinfo, received chan interface{}) error {
  502. // sleeptime := time.Duration(0)
  503. // for sleeptime >= 0 {
  504. // time.Sleep(sleeptime)
  505. // lastpingtimemutex.Lock()
  506. // alastpingtime := lastpingtime[p.ipaddr.String()]
  507. // sleeptime = ping_interval - time.Since(alastpingtime)
  508. // if sleeptime <= 0 {
  509. // lastpingtime[p.ipaddr.String()] = time.Now()
  510. // } else {
  511. // // logger.Error(fmt.Sprint("ping", p.addr, "[", p.ipaddr.String(), "]", "同一地址至少间隔一秒"))
  512. // }
  513. // lastpingtimemutex.Unlock()
  514. // }
  515. // defer func() {
  516. // lastpingtimemutex.Lock()
  517. // lastpingtime[p.ipaddr.String()] = time.Now()
  518. // lastpingtimemutex.Unlock()
  519. // }()
  520. // return MPConn(p.ipv4, p.protocol).Ping(pinfo)
  521. // }
  522. func (p *Pinger) Stop() {
  523. p.lock.Lock()
  524. defer p.lock.Unlock()
  525. open := true
  526. select {
  527. case _, open = <-p.done:
  528. default:
  529. }
  530. if open {
  531. close(p.done)
  532. }
  533. }
  534. func (p *Pinger) finish() {
  535. handler := p.OnFinish
  536. if handler != nil {
  537. s := p.Statistics()
  538. handler(s)
  539. }
  540. }
  541. // Statistics returns the statistics of the pinger. This can be run while the
  542. // pinger is running or after it is finished. OnFinish calls this function to
  543. // get it's finished statistics.
  544. func (p *Pinger) Statistics() *Statistics {
  545. p.statsMu.RLock()
  546. defer p.statsMu.RUnlock()
  547. sent := p.PacketsSent
  548. loss := float64(sent-p.PacketsRecv) / float64(sent) * 100
  549. s := Statistics{
  550. PacketsSent: sent,
  551. PacketsRecv: p.PacketsRecv,
  552. PacketsRecvDuplicates: p.PacketsRecvDuplicates,
  553. PacketLoss: loss,
  554. Rtts: p.rtts,
  555. Addr: p.addr,
  556. IPAddr: p.ipaddr,
  557. MaxRtt: p.maxRtt,
  558. MinRtt: p.minRtt,
  559. AvgRtt: p.avgRtt,
  560. StdDevRtt: p.stdDevRtt,
  561. }
  562. return &s
  563. }
  564. func isIPv4(ip net.IP) bool {
  565. return len(ip.To4()) == net.IPv4len
  566. }
  567. var seed = time.Now().UnixNano()
  568. // getSeed returns a goroutine-safe unique seed
  569. func getSeed() int64 {
  570. return atomic.AddInt64(&seed, 1)
  571. }