mirror of
https://github.com/go-ping/ping.git
synced 2025-08-19 05:27:15 +00:00
Allow pinger.Stop() to be safely called repeatedly. Fix #94
Signed-off-by: Charlie Jonas <charlie@charliejonas.co.uk>
This commit is contained in:
parent
5f9dc3248b
commit
c7a3d708cc
10
README.md
10
README.md
@ -30,7 +30,10 @@ c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
for _ = range c {
|
||||
pinger.Stop()
|
||||
if err := pinger.Stop(); err != nil {
|
||||
// pinger.Stop() will return an error if called more than once
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@ -52,7 +55,10 @@ pinger.Run()
|
||||
|
||||
It sends ICMP Echo Request packet(s) and waits for an Echo Reply in
|
||||
response. If it receives a response, it calls the `OnRecv` callback.
|
||||
When it's finished, it calls the `OnFinish` callback.
|
||||
When it's finished, it calls the `OnFinish` callback. Note that whilst
|
||||
it is safe to call `pinger.Stop()` repeatedly, it will return errors if
|
||||
called more than once. However these errors are purely informational and
|
||||
can be safely ignored.
|
||||
|
||||
For a full ping example, see
|
||||
[cmd/ping/ping.go](https://github.com/go-ping/ping/blob/master/cmd/ping/ping.go)
|
||||
|
@ -60,7 +60,9 @@ func main() {
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
for range c {
|
||||
pinger.Stop()
|
||||
if err := pinger.Stop(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
36
ping.go
36
ping.go
@ -69,8 +69,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ipv4Proto = map[string]string{"icmp": "ip4:icmp", "udp": "udp4"}
|
||||
ipv6Proto = map[string]string{"icmp": "ip6:ipv6-icmp", "udp": "udp6"}
|
||||
ipv4Proto = map[string]string{"icmp": "ip4:icmp", "udp": "udp4"}
|
||||
ipv6Proto = map[string]string{"icmp": "ip6:ipv6-icmp", "udp": "udp6"}
|
||||
ErrTornDown = errors.New("Stop() called more than once")
|
||||
)
|
||||
|
||||
// New returns a new Pinger struct pointer.
|
||||
@ -84,7 +85,7 @@ func New(addr string) *Pinger {
|
||||
Tracker: r.Int63n(math.MaxInt64),
|
||||
|
||||
addr: addr,
|
||||
done: make(chan bool),
|
||||
done: make(chan interface{}),
|
||||
id: r.Intn(math.MaxInt16),
|
||||
ipaddr: nil,
|
||||
ipv4: false,
|
||||
@ -140,8 +141,9 @@ type Pinger struct {
|
||||
// Source is the source IP address
|
||||
Source string
|
||||
|
||||
// stop chan bool
|
||||
done chan bool
|
||||
// Cleardown channel and mutex
|
||||
done chan interface{}
|
||||
lock sync.Mutex
|
||||
|
||||
ipaddr *net.IPAddr
|
||||
addr string
|
||||
@ -350,7 +352,7 @@ func (p *Pinger) Run() error {
|
||||
wg.Wait()
|
||||
return nil
|
||||
case <-timeout.C:
|
||||
close(p.done)
|
||||
_ = p.Stop()
|
||||
wg.Wait()
|
||||
return nil
|
||||
case <-interval.C:
|
||||
@ -370,15 +372,29 @@ func (p *Pinger) Run() error {
|
||||
}
|
||||
}
|
||||
if p.Count > 0 && p.PacketsRecv >= p.Count {
|
||||
close(p.done)
|
||||
_ = p.Stop()
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pinger) Stop() {
|
||||
func (p *Pinger) Stop() error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
ok := true
|
||||
select {
|
||||
case _, ok = <-p.done:
|
||||
default:
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return ErrTornDown
|
||||
}
|
||||
|
||||
close(p.done)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pinger) finish() {
|
||||
@ -466,7 +482,7 @@ func (p *Pinger) recvICMP(
|
||||
// Read timeout
|
||||
continue
|
||||
} else {
|
||||
close(p.done)
|
||||
_ = p.Stop()
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -601,7 +617,7 @@ func (p *Pinger) sendICMP(conn *icmp.PacketConn) error {
|
||||
func (p *Pinger) listen(netProto string) (*icmp.PacketConn, error) {
|
||||
conn, err := icmp.ListenPacket(netProto, p.Source)
|
||||
if err != nil {
|
||||
close(p.done)
|
||||
_ = p.Stop()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
|
Loading…
Reference in New Issue
Block a user