ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
(Generate patch)

Comparing AnyEvent-FastPing/FastPing.pm (file contents):
Revision 1.8 by root, Wed Apr 7 14:13:16 2010 UTC vs.
Revision 1.13 by root, Wed Feb 2 19:26:45 2011 UTC

21 21
22=cut 22=cut
23 23
24package AnyEvent::FastPing; 24package AnyEvent::FastPing;
25 25
26use strict; 26use common::sense;
27no warnings;
28 27
29use AnyEvent; 28use AnyEvent;
30 29
31BEGIN { 30BEGIN {
32 our $VERSION = '1.13'; 31 our $VERSION = '2.0';
33 our @ISA = qw(Exporter); 32 our @ISA = qw(Exporter);
34 33
35 require Exporter; 34 require Exporter;
36 #Exporter::export_ok_tags (keys %EXPORT_TAGS); 35 #Exporter::export_ok_tags (keys %EXPORT_TAGS);
37 36
38 require XSLoader; 37 require XSLoader;
39 XSLoader::load (__PACKAGE__, $VERSION); 38 XSLoader::load (__PACKAGE__, $VERSION);
40} 39}
41 40
42our ($THR_REQ_FD, $THR_RES_FD, $ICMP4_FD, $ICMP6_FD); 41our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
43 42
44our $THR_REQ_FH; open $THR_REQ_FH, ">&=$THR_REQ_FD" or die "FATAL: cannot fdopen";
45our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen"; 43our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen";
46 44
47our $THR_REQ_W; 45our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4;
48our $THR_RES_W = AnyEvent->io (fh => $THR_RES_FH, poll => 'r', cb => sub { 46our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6;
49 my $sv = _read_res
50 or return;
51
52 $sv->();
53});
54
55our $THR_REQ_BUF;
56
57sub _send_req($) {
58 $THR_REQ_BUF .= $_[0];
59
60 $THR_REQ_W ||= AnyEvent->io (fh => $THR_REQ_FH, poll => 'w', cb => sub {
61 my $len = syswrite $THR_REQ_FH, $THR_REQ_BUF;
62 substr $THR_REQ_BUF, 0, $len, "";
63
64 undef $THR_REQ_W unless length $THR_REQ_BUF;
65 });
66}
67 47
68=item AnyEvent::FastPing::ipv4_supported 48=item AnyEvent::FastPing::ipv4_supported
69 49
70Returns true if IPv4 is supported in this module and on this system. 50Returns true iff IPv4 is supported in this module and on this system.
71 51
72=item AnyEvent::FastPing::ipv6_supported 52=item AnyEvent::FastPing::ipv6_supported
73 53
74Returns true if IPv6 is supported in this module and on this system. 54Returns true iff IPv6 is supported in this module and on this system.
75 55
76=item AnyEvent::FastPing::icmp4_pktsize 56=item AnyEvent::FastPing::icmp4_pktsize
77 57
78Returns the number of bytes each IPv4 ping packet has. 58Returns the number of octets per IPv4 ping packet (the whole IP packet
59including headers, excluding lower-level headers or trailers such as
60Ethernet).
61
62Can be used to calculate e.g. octets/s from rate ...
63
64 my $octets_per_second = $packets_per_second * AnyEvent::FastPing::icmp4_pktsize;
65
66... or convert kilobit/second to packet rate ...
67
68 my $packets_per_second = $kilobit_per_second
69 * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize);
70
71etc.
79 72
80=item AnyEvent::FastPing::icmp6_pktsize 73=item AnyEvent::FastPing::icmp6_pktsize
81 74
82Returns the number of bytes each IPv4 ping packet has. 75Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.
83 76
84=item AnyEvent::FastPing::icmp_ping [ranges...], $send_interval, $payload, \&callback 77=back
85 78
86Ping the given IPv4 address ranges. Each range is an arrayref of the 79=head1 THE AnyEvent::FastPing CLASS
87form C<[lo, hi, interval]>, where C<lo> and C<hi> are octet strings with
88either 4 octets (for IPv4 addresses) or 16 octets (for IPV6 addresses),
89representing the lowest and highest address to ping (you can convert a
90dotted-quad IPv4 address to this format by using C<inet_aton $address>. The
91range C<interval> is the minimum time in seconds between pings to the
92given range. If omitted, defaults to C<$send_interval>.
93 80
94The C<$send_interval> is the minimum interval between sending any two 81The AnyEvent::FastPing class represents a single "pinger". A "pinger"
95packets and is a way to make an overall rate limit. If omitted, pings will 82comes with its own thread to send packets in the background, a rate-limit
96be sent as fast as possible. 83machinery and separate idle/receive callbacks.
97 84
98The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO 85The recommended workflow (there are others) is this: 1. create a new
99REQUEST ident and sequence numbers (in unspecified order :). 86AnyEvent::FastPing object 2. configure the address lists and ranges to
87ping, also configure an idle callback and optionally a receive callback
883. C<start> the pinger.
100 89
101The request will be queued and all requests will be served by a background 90When the pinger has finished pinging all the configured addresses it will
102thread in order. When all ranges have been pinged, the C<callback> will be 91call the idle callback.
103called.
104 92
105Algorithm: Each range has an associated "next time to send packet" 93The pinging process works like this: every range has a minimum interval
106time. The algorithm loops as long as there are ranges with hosts to be 94between sends, which is used to limit the rate at which hosts in that
107pinged and always serves the range with the most urgent packet send 95range are being pinged. Distinct ranges are independent of each other,
108time. It will at most send one packet every C<$send_interval> seconds. 96which is why there is a per-pinger "global" minimum interval as well.
109 97
110This will ensure that pings to the same range are nicely interleaved with 98The pinger sends pings as fats as possible, while both obeying the pinger
111other ranges - this can help reduce per-subnet bandwidth while maintaining 99rate limit as well as range limits.
112an overall high packet rate.
113 100
114The algorithm to send each packet is O(log n) on the number of ranges, so 101When a range is exhausted, it is removed. When all ranges are exhausted,
115even a large number of ranges (many thousands) is managable. 102the pinger waits another C<max_rtt> seconds and then exits, causing the
116 103idle callback to trigger.
117No storage is allocated per address.
118 104
119Performance: On my 2 GHz Opteron system with a pretty average nvidia 105Performance: On my 2 GHz Opteron system with a pretty average nvidia
120gigabit network card I can ping around 60k to 200k adresses per second, 106gigabit network card I can ping around 60k to 200k adresses per second,
121depending on routing decisions. 107depending on routing decisions.
122 108
123Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and 109Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
12411.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed 11011.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6
1251000 packets/s overall: 111loopback address 5 times as fast as possible. Do not, however, exceed 1000
112packets/s overall. Dump each received reply:
113
114 use AnyEvent::Socket;
115 use AnyEvent::FastPing;
126 116
127 my $done = AnyEvent->condvar; 117 my $done = AnyEvent->condvar;
128 118
129 AnyEvent::FastPing::icmp_ping 119 my $pinger = new AnyEvent::FastPing;
130 [ 120
131 [v10.0.0.1, v10.0.0.15, .01], 121 $pinger->interval (1/1000);
132 [v11.0.0.1, v11.0.255.255, .001], 122 $pinger->max_rtt (0.1); # reasonably fast/reliable network
133 ], 123
134 .001, 0x12345678, 124 $pinger->add_range (v10.0.0.1, v10.0.0.15, 1/100);
135 sub { 125 $pinger->add_range (v11.0.0.1, v11.0.255.255, 1/1000);
136 warn "all ranges pinged\n"; 126 $pinger->add_hosts ([ (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1) x 5 ]);
137 $done->broadcast; 127
128 $pinger->on_recv (sub {
129 for (@{ $_[0] }) {
130 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
138 } 131 }
139 ; 132 });
140 133
134 $pinger->on_idle (sub {
135 print "done\n";
136 undef $pinger;
137 });
138
139 $pinger->start;
141 $done->wait; 140 $done->wait;
142 141
143=cut 142=head2 METHODS
144 143
145sub icmp_ping($$$&) { 144=over 4
146 _send_req _req_icmp_ping @_; 145
146=item $pinger = new AnyEvent::FastPing
147
148Creates a new pinger - right now there can be at most C<65536> pingers in
149a process, although that limit might change to somethind drastically lower
150- you should be stringy with your pinger objects.
151
152=cut
153
154sub new {
155 my ($klass) = @_;
156
157 _new $klass, (rand 65536), (rand 65536), (rand 65536)
147} 158}
148 159
149our $ICMP4_FH; 160our @IDLE_CB;
150our $ICMP4_W = (open $ICMP4_FH, "<&=$ICMP4_FD") && AnyEvent->io (fh => $ICMP4_FH, poll => 'r', cb => \&_recv_icmp4);
151our $ICMP6_FH;
152our $ICMP6_W = (open $ICMP6_FH, "<&=$ICMP6_FD") && AnyEvent->io (fh => $ICMP6_FH, poll => 'r', cb => \&_recv_icmp6);
153 161
154=item AnyEvent::FastPing::register_cb \&cb 162sub DESTROY {
163 undef $IDLE_CB[ &id ];
164 &_free;
165}
155 166
156Register a callback that is called for every received ping reply 167=item $pinger->on_recv ($callback->([[$host, $rtt], ...]))
157(regardless of whether a ping is still in process or not and regardless of
158whether the reply is actually a reply to a ping sent earlier).
159 168
160The code reference gets a single parameter - an arrayref with an 169Registeres a callback to be called for ping replies. If no callback has
161entry for each received packet (replies are being batched for greater 170been registered than ping replies will be ignored, otherwise this module
162efficiency). Each packet is represented by an arrayref with three members: 171calculates the round trip time, in seconds, for each reply and calls this
163the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets 172callback.
164length), the payload as passed to C<icmp_ping> and the round trip time in
165seconds.
166 173
174The callback receives a single argument, which is an array reference
175with an entry for each reply packet (the replies will be batched for
176efficiency). Each member in the array reference is again an array
177reference with exactly two members: the binary host addresss (4 octets for
178IPv4, 16 for IPv6) and the approximate round trip time, in seconds.
179
180The replies will be passed to the callback as soon as they arrive, and
181this callback can be called many times with batches of replies.
182
183The receive callback will be called whenever a suitable reply arrives,
184whether generated by this pinger or not, whether this pinger is started
185or not. The packets will have a unique 64 bit ID to distinguish them from
186other pinger objects and other generators, but this doesn't help against
187malicious replies.
188
189Note that very high packet rates can overwhelm your process, causing
190replies to be dropped (configure your kernel with long receive queues for
191raw sockets if this is a problem).
192
167Example: register a callback which simply dumps the received data. Since 193Example: register a callback which simply dumps the received data.
168the coderef is created on the fly via sub, it would be hard to unregister
169this callback again :)
170 194
171 AnyEvent::FastPing::register_cb sub { 195 use AnyEvent::Socket;
196
197 $pinger->on_recv (sub {
172 for (@{$_[0]}) { 198 for (@{ $_[0] }) {
173 printf "%s %d %g\n", 199 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
174 (4 == length $_->[0] ? inet_ntoa $_->[0] : Socket6::inet_ntop (&AF_INET6, $_->[0])),
175 $_->[2],
176 $_->[1];
177 } 200 }
178 }; 201 };
179 202
180Example: a single ping reply with payload of 1 from C<::1> gets passed 203Example: a single ping reply with payload of 1 from C<::1> gets passed
181like this: 204like this:
182 205
183 [ [
184 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1",
185 "0.000280141830444336",
186 1
187 ] ]
188
189Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of
190C<0x12345678>:
191
192 [ 206 [
193 [ 207 [ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 0.000280141830444336 ]
194 "\177\0\0\1",
195 "0.00015711784362793",
196 305419896
197 ],
198 [
199 "\177\0\0\2",
200 "0.00090184211731",
201 305419896
202 ]
203 ] 208 ]
204 209
205=item AnyEvent::FastPing::unregister_cb \&cb 210Example: ping replies for C<127.0.0.1> and C<127.0.0.2>:
206 211
207Unregister the callback again (make sure you pass the same codereference 212 [
208as to C<register_cb>). 213 [ "\177\0\0\1", 0.00015711784362793 ],
214 [ "\177\0\0\2", 0.00090184211731 ]
215 ]
209 216
210=cut 217=item $pinger->on_idle ($callback->())
211 218
212our @CB; 219Registers a callback to be called when the pinger becomes I<idle>, that
220is, it has been started, has exhausted all ping ranges and waited for
221the C<max_rtt> time. An idle pinger is also stopped, so the callback can
222instantly add new ranges, if it so desires.
213 223
214sub register_cb($) { 224=cut
215 push @CB, $_[0]; 225
226sub on_idle {
227 $IDLE_CB[ &id ] = $_[1];
216} 228}
217 229
218sub unregister_cb($) { 230our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
219 @CB = grep $_ != $_[0], @CB; 231 sysread $THR_RES_FH, my $buf, 8;
220} 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)
240
241Configures the minimum interval between packet sends for this pinger - the
242pinger will not send packets faster than this rate (or atcually 1 / rate),
243even if individual ranges have a lower interval.
244
245A value of C<0> selects the fastests possible speed (currently no faster
246than 1_000_000 packets/s).
247
248=item $pinger->max_rtt ($seconds)
249
250If your idle callback were called instantly after all ranges were
251exhausted and you destroyed the object inside (which is common), then
252there would be no chance to receive some replies, as there would be no
253time fo the packet to travel over the network.
254
255This can be fixed by starting a timer in the idle callback, or more simply
256by selecting a suitable C<max_rtt> value, which should be the maximum time
257you allow a ping packet to travel to its destinazion and back.
258
259The pinger thread automatically waits for this amount of time before becoming idle.
260
261The default is currently C<0.5> seconds, which is usually plenty.
262
263=item $pinger->add_range ($lo, $hi[, $interval])
264
265Ping the IPv4 (or IPv6, but see below) address range, starting at binary
266address C<$lo> and ending at C<$hi> (both C<$lo> and C<$hi> will be
267pinged), generating no more than one ping per C<$interval> seconds (or as
268fast as possible if omitted).
269
270You can convert IP addresses from text to binary form by
271using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>,
272C<Socket6::inet_pton> or any other method that you like :)
273
274The algorithm to select the next address is O(log n) on the number of
275ranges, so even a large number of ranges (many thousands) is managable.
276
277No storage is allocated per address.
278
279Note that, while IPv6 addresses are currently supported, the usefulness of
280this option is extremely limited and might be gone in future versions - if
281you want to ping a number of IPv6 hosts, better specify them individually
282using the C<add_hosts> method.
283
284=item $pinger->add_hosts ([$host...], $interval, $interleave)
285
286Similar to C<add_range>, but uses a list of single addresses instead. The
287list is specified as an array reference as first argument. Each entry in
288the array should be a binary host address, either IPv4 or IPv6. Currently,
289all entries in the list must be either IPv4 B<OR> IPv6, so you have to
290create two host ranges if you have mixed addresses.
291
292Minimum C<$interval> is the same as for C<add_range> and can be left out.
293
294C<$interlave> specifies an increment between addresses: often address
295lists are generated in a way that results in clustering - first all
296addresses from one subnet, then from the next, and so on. To avoid this,
297you can specify an interleave factor. If it is C<1> (the default), then
298every address is pinged in the order specified. If it is C<2>, then only
299every second address will be pinged in the first round, followed by a
300second round with the others. Higher factors will create C<$interleave>
301runs of addresses spaced C<$interleave> indices in the list.
302
303The special value C<0> selects a (hopefully) suitable interleave factor
304automatically - currently C<256> for lists with less than 65536 addresses,
305and the square root of the list length otherwise.
306
307=item $pinger->start
308
309Start the pinger, unless it is running already. While a pinger is running
310you must not modify the pinger. If you want to change a parameter, you
311have to C<stop> the pinger first.
312
313The pinger will automatically stop when destroyed.
314
315=item $pinger->stop
316
317Stop the pinger, if it is running. A pinger can be stopped at any time,
318after which it's current state is preserved - starting it again will
319continue where it left off.
320
321=cut
221 322
2221; 3231;
223 324
224=back 325=back
225 326

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines