… | |
… | |
10 | |
10 | |
11 | This module was written for a single purpose only: sending ICMP ECHO |
11 | This module was written for a single purpose only: sending ICMP ECHO |
12 | REQUEST packets as quickly as possible to a large number of hosts |
12 | REQUEST packets as quickly as possible to a large number of hosts |
13 | (thousands to millions). |
13 | (thousands to millions). |
14 | |
14 | |
15 | It employs a sending thread and is fully event-driven (using AnyEvent), so |
15 | It employs a separate thread and is fully event-driven (using AnyEvent), |
16 | you have to run an event model supported by AnyEvent to use this module. |
16 | so you have to run an event model supported by AnyEvent to use this |
|
|
17 | module. |
17 | |
18 | |
18 | =head1 FUNCTIONS |
19 | =head1 FUNCTIONS |
19 | |
20 | |
20 | =over 4 |
21 | =over 4 |
21 | |
22 | |
… | |
… | |
26 | use common::sense; |
27 | use common::sense; |
27 | |
28 | |
28 | use AnyEvent; |
29 | use AnyEvent; |
29 | |
30 | |
30 | BEGIN { |
31 | BEGIN { |
31 | our $VERSION = '2.0'; |
32 | our $VERSION = 2.1; |
32 | our @ISA = qw(Exporter); |
33 | our @ISA = qw(Exporter); |
33 | |
34 | |
34 | require Exporter; |
35 | require Exporter; |
35 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
36 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
36 | |
37 | |
… | |
… | |
38 | XSLoader::load (__PACKAGE__, $VERSION); |
39 | XSLoader::load (__PACKAGE__, $VERSION); |
39 | } |
40 | } |
40 | |
41 | |
41 | our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD); |
42 | our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD); |
42 | |
43 | |
43 | our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen"; |
44 | our $THR_RES_FH; |
44 | |
45 | |
45 | our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; |
46 | our $ICMP4_FH; |
46 | our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; |
47 | our $ICMP6_FH; |
|
|
48 | |
|
|
49 | our @IDLE_CB; |
47 | |
50 | |
48 | =item AnyEvent::FastPing::ipv4_supported |
51 | =item AnyEvent::FastPing::ipv4_supported |
49 | |
52 | |
50 | Returns true iff IPv4 is supported in this module and on this system. |
53 | Returns true iff IPv4 is supported in this module and on this system. |
51 | |
54 | |
… | |
… | |
101 | When a range is exhausted, it is removed. When all ranges are exhausted, |
104 | When a range is exhausted, it is removed. When all ranges are exhausted, |
102 | the pinger waits another C<max_rtt> seconds and then exits, causing the |
105 | the pinger waits another C<max_rtt> seconds and then exits, causing the |
103 | idle callback to trigger. |
106 | idle callback to trigger. |
104 | |
107 | |
105 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
108 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
106 | gigabit network card I can ping around 60k to 200k adresses per second, |
109 | gigabit network card I can ping around 60k to 200k addresses per second, |
107 | depending on routing decisions. |
110 | depending on routing decisions. |
108 | |
111 | |
109 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
112 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
110 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6 |
113 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6 |
111 | loopback address 5 times as fast as possible. Do not, however, exceed 1000 |
114 | loopback address 5 times as fast as possible. Do not, however, exceed 1000 |
112 | packets/s overall. Dump each received reply: |
115 | packets/s overall. Also dump each received reply. |
113 | |
116 | |
114 | use AnyEvent::Socket; |
117 | use AnyEvent::Socket; |
115 | use AnyEvent::FastPing; |
118 | use AnyEvent::FastPing; |
116 | |
119 | |
117 | my $done = AnyEvent->condvar; |
120 | my $done = AnyEvent->condvar; |
… | |
… | |
144 | =over 4 |
147 | =over 4 |
145 | |
148 | |
146 | =item $pinger = new AnyEvent::FastPing |
149 | =item $pinger = new AnyEvent::FastPing |
147 | |
150 | |
148 | Creates a new pinger - right now there can be at most C<65536> pingers in |
151 | Creates a new pinger - right now there can be at most C<65536> pingers in |
149 | a process, although that limit might change to somethind drastically lower |
152 | a process, although that limit might change to something drastically lower |
150 | - you should be stringy with your pinger objects. |
153 | - you should be stingy with your pinger objects. |
151 | |
154 | |
152 | =cut |
155 | =cut |
153 | |
156 | |
154 | sub new { |
157 | sub new { |
155 | my ($klass) = @_; |
158 | _boot; |
156 | |
159 | |
|
|
160 | our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; |
|
|
161 | our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; |
|
|
162 | |
|
|
163 | open $THR_RES_FH, "<&=$THR_RES_FD" or die "AnyEvent::FastPing: FATAL: cannot fdopen thread result fd"; |
|
|
164 | |
|
|
165 | our $THR_RES_W = AE::io $THR_RES_FH, 0, sub { |
|
|
166 | sysread $THR_RES_FH, my $buf, 8; |
|
|
167 | |
|
|
168 | for my $id (unpack "S*", $buf) { |
|
|
169 | _stop_id $id; |
|
|
170 | ($IDLE_CB[$id] || sub { })->(); |
|
|
171 | } |
|
|
172 | }; |
|
|
173 | |
|
|
174 | *new = sub { |
157 | _new $klass, (rand 65536), (rand 65536), (rand 65536) |
175 | _new shift, (rand 65536), (rand 65536), (rand 65536) |
|
|
176 | }; |
|
|
177 | |
|
|
178 | goto &new; |
158 | } |
179 | } |
159 | |
|
|
160 | our @IDLE_CB; |
|
|
161 | |
180 | |
162 | sub DESTROY { |
181 | sub DESTROY { |
163 | undef $IDLE_CB[ &id ]; |
182 | undef $IDLE_CB[ &id ]; |
164 | &_free; |
183 | &_free; |
165 | } |
184 | } |
166 | |
185 | |
167 | =item $pinger->on_recv ($callback->([[$host, $rtt], ...])) |
186 | =item $pinger->on_recv ($callback->([[$host, $rtt], ...])) |
168 | |
187 | |
169 | Registeres a callback to be called for ping replies. If no callback has |
188 | Registers a callback to be called for ping replies. If no callback has |
170 | been registered than ping replies will be ignored, otherwise this module |
189 | been registered than ping replies will be ignored, otherwise this module |
171 | calculates the round trip time, in seconds, for each reply and calls this |
190 | calculates the round trip time, in seconds, for each reply and calls this |
172 | callback. |
191 | callback. |
173 | |
192 | |
174 | The callback receives a single argument, which is an array reference |
193 | The callback receives a single argument, which is an array reference |
175 | with an entry for each reply packet (the replies will be batched for |
194 | with an entry for each reply packet (the replies will be batched for |
176 | efficiency). Each member in the array reference is again an array |
195 | efficiency). Each member in the array reference is again an array |
177 | reference with exactly two members: the binary host addresss (4 octets for |
196 | reference with exactly two members: the binary host address (4 octets for |
178 | IPv4, 16 for IPv6) and the approximate round trip time, in seconds. |
197 | IPv4, 16 for IPv6) and the approximate round trip time, in seconds. |
179 | |
198 | |
180 | The replies will be passed to the callback as soon as they arrive, and |
199 | The replies will be passed to the callback as soon as they arrive, and |
181 | this callback can be called many times with batches of replies. |
200 | this callback can be called many times with batches of replies. |
182 | |
201 | |
… | |
… | |
196 | |
215 | |
197 | $pinger->on_recv (sub { |
216 | $pinger->on_recv (sub { |
198 | for (@{ $_[0] }) { |
217 | for (@{ $_[0] }) { |
199 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
218 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
200 | } |
219 | } |
201 | }; |
220 | }); |
202 | |
221 | |
203 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
222 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
204 | like this: |
223 | like this: |
205 | |
224 | |
206 | [ |
225 | [ |
… | |
… | |
225 | |
244 | |
226 | sub on_idle { |
245 | sub on_idle { |
227 | $IDLE_CB[ &id ] = $_[1]; |
246 | $IDLE_CB[ &id ] = $_[1]; |
228 | } |
247 | } |
229 | |
248 | |
230 | our $THR_RES_W = AE::io $THR_RES_FH, 0, sub { |
|
|
231 | sysread $THR_RES_FH, my $buf, 8; |
|
|
232 | |
|
|
233 | for my $id (unpack "S*", $buf) { |
|
|
234 | _stop_id $id; |
|
|
235 | ($IDLE_CB[$id] || sub { })->(); |
|
|
236 | } |
|
|
237 | }; |
|
|
238 | |
|
|
239 | =item $pinger->interval ($seconds) |
249 | =item $pinger->interval ($seconds) |
240 | |
250 | |
241 | Configures the minimum interval between packet sends for this pinger - the |
251 | Configures the minimum interval between packet sends for this pinger - the |
242 | pinger will not send packets faster than this rate (or atcually 1 / rate), |
252 | pinger will not send packets faster than this rate (or actually 1 / rate), |
243 | even if individual ranges have a lower interval. |
253 | even if individual ranges have a lower interval. |
244 | |
254 | |
245 | A value of C<0> selects the fastests possible speed (currently no faster |
255 | A value of C<0> selects the fastest possible speed (currently no faster |
246 | than 1_000_000 packets/s). |
256 | than 1_000_000 packets/s). |
247 | |
257 | |
248 | =item $pinger->max_rtt ($seconds) |
258 | =item $pinger->max_rtt ($seconds) |
249 | |
259 | |
250 | If your idle callback were called instantly after all ranges were |
260 | If your idle callback were called instantly after all ranges were |
251 | exhausted and you destroyed the object inside (which is common), then |
261 | exhausted and you destroyed the object inside (which is common), then |
252 | there would be no chance to receive some replies, as there would be no |
262 | there would be no chance to receive some replies, as there would be no |
253 | time fo the packet to travel over the network. |
263 | time of the packet to travel over the network. |
254 | |
264 | |
255 | This can be fixed by starting a timer in the idle callback, or more simply |
265 | This can be fixed by starting a timer in the idle callback, or more simply |
256 | by selecting a suitable C<max_rtt> value, which should be the maximum time |
266 | by selecting a suitable C<max_rtt> value, which should be the maximum time |
257 | you allow a ping packet to travel to its destinazion and back. |
267 | you allow a ping packet to travel to its destination and back. |
258 | |
268 | |
259 | The pinger thread automatically waits for this amount of time before becoming idle. |
269 | The pinger thread automatically waits for this amount of time before becoming idle. |
260 | |
270 | |
261 | The default is currently C<0.5> seconds, which is usually plenty. |
271 | The default is currently C<0.5> seconds, which is usually plenty. |
262 | |
272 | |
… | |
… | |
270 | You can convert IP addresses from text to binary form by |
280 | You can convert IP addresses from text to binary form by |
271 | using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>, |
281 | using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>, |
272 | C<Socket6::inet_pton> or any other method that you like :) |
282 | C<Socket6::inet_pton> or any other method that you like :) |
273 | |
283 | |
274 | The algorithm to select the next address is O(log n) on the number of |
284 | The algorithm to select the next address is O(log n) on the number of |
275 | ranges, so even a large number of ranges (many thousands) is managable. |
285 | ranges, so even a large number of ranges (many thousands) is manageable. |
276 | |
286 | |
277 | No storage is allocated per address. |
287 | No storage is allocated per address. |
278 | |
288 | |
279 | Note that, while IPv6 addresses are currently supported, the usefulness of |
289 | Note that, while IPv6 addresses are currently supported, the usefulness of |
280 | this option is extremely limited and might be gone in future versions - if |
290 | this option is extremely limited and might be gone in future versions - if |
… | |
… | |
283 | |
293 | |
284 | =item $pinger->add_hosts ([$host...], $interval, $interleave) |
294 | =item $pinger->add_hosts ([$host...], $interval, $interleave) |
285 | |
295 | |
286 | Similar to C<add_range>, but uses a list of single addresses instead. The |
296 | Similar to C<add_range>, but uses a list of single addresses instead. The |
287 | list is specified as an array reference as first argument. Each entry in |
297 | list is specified as an array reference as first argument. Each entry in |
288 | the array should be a binary host address, either IPv4 or IPv6. Currently, |
298 | the array should be a binary host address, either IPv4 or IPv6. If all |
289 | all entries in the list must be either IPv4 B<OR> IPv6, so you have to |
299 | addresses are IPv4 addresses, then a compact IPv4-only format will be used |
290 | create two host ranges if you have mixed addresses. |
300 | to store the list internally. |
291 | |
301 | |
292 | Minimum C<$interval> is the same as for C<add_range> and can be left out. |
302 | Minimum C<$interval> is the same as for C<add_range> and can be left out. |
293 | |
303 | |
294 | C<$interlave> specifies an increment between addresses: often address |
304 | C<$interlave> specifies an increment between addresses: often address |
295 | lists are generated in a way that results in clustering - first all |
305 | lists are generated in a way that results in clustering - first all |