@@ -21,7 +21,6 @@ package multiping
21
21
import (
22
22
"context"
23
23
"math/rand"
24
- "net/netip"
25
24
"sync"
26
25
"time"
27
26
@@ -64,6 +63,7 @@ type MultiPing struct {
64
63
conn4 * icmp.PacketConn
65
64
conn6 * icmp.PacketConn
66
65
rxChan chan * pinger.Packet
66
+ txChan chan * pinger.Packet
67
67
}
68
68
69
69
func New (privileged bool ) (* MultiPing , error ) {
@@ -88,7 +88,7 @@ func New(privileged bool) (*MultiPing, error) {
88
88
// try initialise connections to test that everything's working
89
89
err := mp .restart ()
90
90
if err != nil {
91
- mp .close ()
91
+ mp .closeConnection ()
92
92
return nil , err
93
93
}
94
94
@@ -125,12 +125,13 @@ func (mp *MultiPing) restart() (err error) {
125
125
}
126
126
127
127
mp .rxChan = make (chan * pinger.Packet )
128
+ mp .txChan = make (chan * pinger.Packet )
128
129
129
130
return nil
130
131
}
131
132
132
133
// closes active connections
133
- func (mp * MultiPing ) close () {
134
+ func (mp * MultiPing ) closeConnection () {
134
135
if mp .conn4 != nil {
135
136
mp .conn4 .Close ()
136
137
}
@@ -141,7 +142,8 @@ func (mp *MultiPing) close() {
141
142
142
143
// cleanup cannot be done in close, because some goroutines may be using struct members
143
144
func (mp * MultiPing ) cleanup () {
144
- // Close channels
145
+ // Close rx channel.
146
+ // Tx channel is closed in batchPrepareIcmp()
145
147
close (mp .rxChan )
146
148
147
149
// invalidate connections
@@ -154,92 +156,3 @@ func (mp *MultiPing) cleanup() {
154
156
// Invalidate IP address
155
157
mp .pinger .SetIPAddr (nil )
156
158
}
157
-
158
- // Ping is blocking function and runs for mp.Timeout time and pings all hosts in data
159
- func (mp * MultiPing ) Ping (data * pingdata.PingData ) {
160
- if data .Count () == 0 {
161
- return
162
- }
163
-
164
- // Lock the pinger - its instance may be reused by several clients
165
- mp .Lock ()
166
- defer mp .Unlock ()
167
-
168
- err := mp .restart ()
169
- if err != nil {
170
- return
171
- }
172
-
173
- // Some subfunctions in goroutines will need this pointer to store ping results
174
- mp .pingData = data
175
-
176
- mp .ctx , mp .cancel = context .WithTimeout (context .Background (), mp .Timeout )
177
- defer mp .cancel ()
178
-
179
- // This goroutine depends on rxChan and no need to add it to workgroup
180
- // It will terminate on channel close
181
- go mp .batchProcessPacket ()
182
-
183
- if mp .conn4 != nil {
184
- mp .wg .Add (1 )
185
- mp .conn4 .SetReadDeadline (time .Now ().Add (mp .Timeout ))
186
- go mp .batchRecvICMP (pinger .ProtocolIpv4 )
187
- }
188
- if mp .conn6 != nil {
189
- mp .wg .Add (1 )
190
- mp .conn6 .SetReadDeadline (time .Now ().Add (mp .Timeout ))
191
- go mp .batchRecvICMP (pinger .ProtocolIpv6 )
192
- }
193
-
194
- // Sender goroutine
195
- mp .wg .Add (1 )
196
- go func () {
197
- defer mp .wg .Done ()
198
- mp .pingData .Iterate (func (addr netip.Addr , stats * pingdata.PingStats ) {
199
- mp .pinger .SetIPAddr (& addr )
200
- stats .Send (mp .sequence )
201
-
202
- mp .pinger .SendICMP (mp .sequence )
203
- time .Sleep (time .Millisecond )
204
- })
205
- }()
206
-
207
- // wait for timeout and close connections
208
- <- mp .ctx .Done ()
209
- mp .close ()
210
-
211
- // wait for all goroutines to terminate
212
- mp .wg .Wait ()
213
-
214
- mp .cleanup ()
215
- }
216
-
217
- func (mp * MultiPing ) batchRecvICMP (proto pinger.ProtocolVersion ) {
218
- defer func () {
219
- mp .wg .Done ()
220
- }()
221
-
222
- for {
223
- pkt , err := mp .pinger .RecvPacket (proto )
224
- if err != nil {
225
- return
226
- }
227
-
228
- mp .rxChan <- pkt
229
- }
230
- }
231
-
232
- // This function runs in goroutine and nobody is interested in return errors
233
- // Discard errors silently
234
- func (mp * MultiPing ) batchProcessPacket () {
235
- for recv := range mp .rxChan {
236
- pingStats := mp .pinger .ParsePacket (recv )
237
- if pingStats .Tracker != mp .Tracker {
238
- continue
239
- }
240
-
241
- if stats , ok := mp .pingData .Get (recv .Addr ); ok {
242
- stats .Recv (pingStats .Seq , pingStats .RTT )
243
- }
244
- }
245
- }
0 commit comments