ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
Revision: 1.19
Committed: Sat Nov 12 01:20:46 2016 UTC (7 years, 5 months ago) by root
Branch: MAIN
CVS Tags: rel-2_1, HEAD
Changes since 1.18: +21 -19 lines
Log Message:
2.1

File Contents

# Content
1 =head1 NAME
2
3 AnyEvent::FastPing - quickly ping a large number of hosts
4
5 =head1 SYNOPSIS
6
7 use AnyEvent::FastPing;
8
9 =head1 DESCRIPTION
10
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
13 (thousands to millions).
14
15 It employs a separate thread and is fully event-driven (using AnyEvent),
16 so you have to run an event model supported by AnyEvent to use this
17 module.
18
19 =head1 FUNCTIONS
20
21 =over 4
22
23 =cut
24
25 package AnyEvent::FastPing;
26
27 use common::sense;
28
29 use AnyEvent;
30
31 BEGIN {
32 our $VERSION = 2.1;
33 our @ISA = qw(Exporter);
34
35 require Exporter;
36 #Exporter::export_ok_tags (keys %EXPORT_TAGS);
37
38 require XSLoader;
39 XSLoader::load (__PACKAGE__, $VERSION);
40 }
41
42 our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
43
44 our $THR_RES_FH;
45
46 our $ICMP4_FH;
47 our $ICMP6_FH;
48
49 our @IDLE_CB;
50
51 =item AnyEvent::FastPing::ipv4_supported
52
53 Returns true iff IPv4 is supported in this module and on this system.
54
55 =item AnyEvent::FastPing::ipv6_supported
56
57 Returns true iff IPv6 is supported in this module and on this system.
58
59 =item AnyEvent::FastPing::icmp4_pktsize
60
61 Returns the number of octets per IPv4 ping packet (the whole IP packet
62 including headers, excluding lower-level headers or trailers such as
63 Ethernet).
64
65 Can be used to calculate e.g. octets/s from rate ...
66
67 my $octets_per_second = $packets_per_second * AnyEvent::FastPing::icmp4_pktsize;
68
69 ... or convert kilobit/second to packet rate ...
70
71 my $packets_per_second = $kilobit_per_second
72 * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize);
73
74 etc.
75
76 =item AnyEvent::FastPing::icmp6_pktsize
77
78 Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.
79
80 =back
81
82 =head1 THE AnyEvent::FastPing CLASS
83
84 The AnyEvent::FastPing class represents a single "pinger". A "pinger"
85 comes with its own thread to send packets in the background, a rate-limit
86 machinery and separate idle/receive callbacks.
87
88 The recommended workflow (there are others) is this: 1. create a new
89 AnyEvent::FastPing object 2. configure the address lists and ranges to
90 ping, also configure an idle callback and optionally a receive callback
91 3. C<start> the pinger.
92
93 When the pinger has finished pinging all the configured addresses it will
94 call the idle callback.
95
96 The pinging process works like this: every range has a minimum interval
97 between sends, which is used to limit the rate at which hosts in that
98 range are being pinged. Distinct ranges are independent of each other,
99 which is why there is a per-pinger "global" minimum interval as well.
100
101 The pinger sends pings as fats as possible, while both obeying the pinger
102 rate limit as well as range limits.
103
104 When a range is exhausted, it is removed. When all ranges are exhausted,
105 the pinger waits another C<max_rtt> seconds and then exits, causing the
106 idle callback to trigger.
107
108 Performance: On my 2 GHz Opteron system with a pretty average nvidia
109 gigabit network card I can ping around 60k to 200k addresses per second,
110 depending on routing decisions.
111
112 Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
113 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6
114 loopback address 5 times as fast as possible. Do not, however, exceed 1000
115 packets/s overall. Also dump each received reply.
116
117 use AnyEvent::Socket;
118 use AnyEvent::FastPing;
119
120 my $done = AnyEvent->condvar;
121
122 my $pinger = new AnyEvent::FastPing;
123
124 $pinger->interval (1/1000);
125 $pinger->max_rtt (0.1); # reasonably fast/reliable network
126
127 $pinger->add_range (v10.0.0.1, v10.0.0.15, 1/100);
128 $pinger->add_range (v11.0.0.1, v11.0.255.255, 1/1000);
129 $pinger->add_hosts ([ (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1) x 5 ]);
130
131 $pinger->on_recv (sub {
132 for (@{ $_[0] }) {
133 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
134 }
135 });
136
137 $pinger->on_idle (sub {
138 print "done\n";
139 undef $pinger;
140 });
141
142 $pinger->start;
143 $done->wait;
144
145 =head2 METHODS
146
147 =over 4
148
149 =item $pinger = new AnyEvent::FastPing
150
151 Creates a new pinger - right now there can be at most C<65536> pingers in
152 a process, although that limit might change to something drastically lower
153 - you should be stingy with your pinger objects.
154
155 =cut
156
157 sub new {
158 _boot;
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 {
175 _new shift, (rand 65536), (rand 65536), (rand 65536)
176 };
177
178 goto &new;
179 }
180
181 sub DESTROY {
182 undef $IDLE_CB[ &id ];
183 &_free;
184 }
185
186 =item $pinger->on_recv ($callback->([[$host, $rtt], ...]))
187
188 Registers a callback to be called for ping replies. If no callback has
189 been registered than ping replies will be ignored, otherwise this module
190 calculates the round trip time, in seconds, for each reply and calls this
191 callback.
192
193 The callback receives a single argument, which is an array reference
194 with an entry for each reply packet (the replies will be batched for
195 efficiency). Each member in the array reference is again an array
196 reference with exactly two members: the binary host address (4 octets for
197 IPv4, 16 for IPv6) and the approximate round trip time, in seconds.
198
199 The replies will be passed to the callback as soon as they arrive, and
200 this callback can be called many times with batches of replies.
201
202 The receive callback will be called whenever a suitable reply arrives,
203 whether generated by this pinger or not, whether this pinger is started
204 or not. The packets will have a unique 64 bit ID to distinguish them from
205 other pinger objects and other generators, but this doesn't help against
206 malicious replies.
207
208 Note that very high packet rates can overwhelm your process, causing
209 replies to be dropped (configure your kernel with long receive queues for
210 raw sockets if this is a problem).
211
212 Example: register a callback which simply dumps the received data.
213
214 use AnyEvent::Socket;
215
216 $pinger->on_recv (sub {
217 for (@{ $_[0] }) {
218 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
219 }
220 });
221
222 Example: a single ping reply with payload of 1 from C<::1> gets passed
223 like this:
224
225 [
226 [ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 0.000280141830444336 ]
227 ]
228
229 Example: ping replies for C<127.0.0.1> and C<127.0.0.2>:
230
231 [
232 [ "\177\0\0\1", 0.00015711784362793 ],
233 [ "\177\0\0\2", 0.00090184211731 ]
234 ]
235
236 =item $pinger->on_idle ($callback->())
237
238 Registers a callback to be called when the pinger becomes I<idle>, that
239 is, it has been started, has exhausted all ping ranges and waited for
240 the C<max_rtt> time. An idle pinger is also stopped, so the callback can
241 instantly add new ranges, if it so desires.
242
243 =cut
244
245 sub on_idle {
246 $IDLE_CB[ &id ] = $_[1];
247 }
248
249 =item $pinger->interval ($seconds)
250
251 Configures the minimum interval between packet sends for this pinger - the
252 pinger will not send packets faster than this rate (or actually 1 / rate),
253 even if individual ranges have a lower interval.
254
255 A value of C<0> selects the fastest possible speed (currently no faster
256 than 1_000_000 packets/s).
257
258 =item $pinger->max_rtt ($seconds)
259
260 If your idle callback were called instantly after all ranges were
261 exhausted and you destroyed the object inside (which is common), then
262 there would be no chance to receive some replies, as there would be no
263 time of the packet to travel over the network.
264
265 This can be fixed by starting a timer in the idle callback, or more simply
266 by selecting a suitable C<max_rtt> value, which should be the maximum time
267 you allow a ping packet to travel to its destination and back.
268
269 The pinger thread automatically waits for this amount of time before becoming idle.
270
271 The default is currently C<0.5> seconds, which is usually plenty.
272
273 =item $pinger->add_range ($lo, $hi[, $interval])
274
275 Ping the IPv4 (or IPv6, but see below) address range, starting at binary
276 address C<$lo> and ending at C<$hi> (both C<$lo> and C<$hi> will be
277 pinged), generating no more than one ping per C<$interval> seconds (or as
278 fast as possible if omitted).
279
280 You can convert IP addresses from text to binary form by
281 using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>,
282 C<Socket6::inet_pton> or any other method that you like :)
283
284 The algorithm to select the next address is O(log n) on the number of
285 ranges, so even a large number of ranges (many thousands) is manageable.
286
287 No storage is allocated per address.
288
289 Note that, while IPv6 addresses are currently supported, the usefulness of
290 this option is extremely limited and might be gone in future versions - if
291 you want to ping a number of IPv6 hosts, better specify them individually
292 using the C<add_hosts> method.
293
294 =item $pinger->add_hosts ([$host...], $interval, $interleave)
295
296 Similar to C<add_range>, but uses a list of single addresses instead. The
297 list is specified as an array reference as first argument. Each entry in
298 the array should be a binary host address, either IPv4 or IPv6. If all
299 addresses are IPv4 addresses, then a compact IPv4-only format will be used
300 to store the list internally.
301
302 Minimum C<$interval> is the same as for C<add_range> and can be left out.
303
304 C<$interlave> specifies an increment between addresses: often address
305 lists are generated in a way that results in clustering - first all
306 addresses from one subnet, then from the next, and so on. To avoid this,
307 you can specify an interleave factor. If it is C<1> (the default), then
308 every address is pinged in the order specified. If it is C<2>, then only
309 every second address will be pinged in the first round, followed by a
310 second round with the others. Higher factors will create C<$interleave>
311 runs of addresses spaced C<$interleave> indices in the list.
312
313 The special value C<0> selects a (hopefully) suitable interleave factor
314 automatically - currently C<256> for lists with less than 65536 addresses,
315 and the square root of the list length otherwise.
316
317 =item $pinger->start
318
319 Start the pinger, unless it is running already. While a pinger is running
320 you must not modify the pinger. If you want to change a parameter, you
321 have to C<stop> the pinger first.
322
323 The pinger will automatically stop when destroyed.
324
325 =item $pinger->stop
326
327 Stop the pinger, if it is running. A pinger can be stopped at any time,
328 after which it's current state is preserved - starting it again will
329 continue where it left off.
330
331 =cut
332
333 1;
334
335 =back
336
337 =head1 AUTHOR
338
339 Marc Lehmann <schmorp@schmorp.de>
340 http://home.schmorp.de/
341
342 =head1 LICENSE
343
344 This software is distributed under the GENERAL PUBLIC LICENSE, version 2
345 or any later version or, at your option, the Artistic License.
346
347 =cut
348