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.13 by root, Wed Feb 2 19:26:45 2011 UTC vs.
Revision 1.19 by root, Sat Nov 12 01:20:46 2016 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines