ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
Revision: 1.16
Committed: Sun Feb 6 00:23:45 2011 UTC (13 years, 3 months ago) by root
Branch: MAIN
CVS Tags: rel-2_01
Changes since 1.15: +1 -1 lines
Log Message:
2.01

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