mirror of
https://github.com/go-ping/ping.git
synced 2025-08-20 05:56:50 +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)
|
signal.Notify(c, os.Interrupt)
|
||||||
go func() {
|
go func() {
|
||||||
for _ = range c {
|
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
|
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.
|
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
|
For a full ping example, see
|
||||||
[cmd/ping/ping.go](https://github.com/go-ping/ping/blob/master/cmd/ping/ping.go)
|
[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)
|
signal.Notify(c, os.Interrupt)
|
||||||
go func() {
|
go func() {
|
||||||
for range c {
|
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 (
|
var (
|
||||||
ipv4Proto = map[string]string{"icmp": "ip4:icmp", "udp": "udp4"}
|
ipv4Proto = map[string]string{"icmp": "ip4:icmp", "udp": "udp4"}
|
||||||
ipv6Proto = map[string]string{"icmp": "ip6:ipv6-icmp", "udp": "udp6"}
|
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.
|
// New returns a new Pinger struct pointer.
|
||||||
@ -84,7 +85,7 @@ func New(addr string) *Pinger {
|
|||||||
Tracker: r.Int63n(math.MaxInt64),
|
Tracker: r.Int63n(math.MaxInt64),
|
||||||
|
|
||||||
addr: addr,
|
addr: addr,
|
||||||
done: make(chan bool),
|
done: make(chan interface{}),
|
||||||
id: r.Intn(math.MaxInt16),
|
id: r.Intn(math.MaxInt16),
|
||||||
ipaddr: nil,
|
ipaddr: nil,
|
||||||
ipv4: false,
|
ipv4: false,
|
||||||
@ -140,8 +141,9 @@ type Pinger struct {
|
|||||||
// Source is the source IP address
|
// Source is the source IP address
|
||||||
Source string
|
Source string
|
||||||
|
|
||||||
// stop chan bool
|
// Cleardown channel and mutex
|
||||||
done chan bool
|
done chan interface{}
|
||||||
|
lock sync.Mutex
|
||||||
|
|
||||||
ipaddr *net.IPAddr
|
ipaddr *net.IPAddr
|
||||||
addr string
|
addr string
|
||||||
@ -350,7 +352,7 @@ func (p *Pinger) Run() error {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
case <-timeout.C:
|
case <-timeout.C:
|
||||||
close(p.done)
|
_ = p.Stop()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
case <-interval.C:
|
case <-interval.C:
|
||||||
@ -370,15 +372,29 @@ func (p *Pinger) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.Count > 0 && p.PacketsRecv >= p.Count {
|
if p.Count > 0 && p.PacketsRecv >= p.Count {
|
||||||
close(p.done)
|
_ = p.Stop()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return nil
|
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)
|
close(p.done)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pinger) finish() {
|
func (p *Pinger) finish() {
|
||||||
@ -466,7 +482,7 @@ func (p *Pinger) recvICMP(
|
|||||||
// Read timeout
|
// Read timeout
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
close(p.done)
|
_ = p.Stop()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -601,7 +617,7 @@ func (p *Pinger) sendICMP(conn *icmp.PacketConn) error {
|
|||||||
func (p *Pinger) listen(netProto string) (*icmp.PacketConn, error) {
|
func (p *Pinger) listen(netProto string) (*icmp.PacketConn, error) {
|
||||||
conn, err := icmp.ListenPacket(netProto, p.Source)
|
conn, err := icmp.ListenPacket(netProto, p.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
close(p.done)
|
_ = p.Stop()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return conn, nil
|
return conn, nil
|
||||||
|
Loading…
Reference in New Issue
Block a user