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.18 by root, Fri Nov 11 01:18:56 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.03;
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
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; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen";
44 45
46our $ICMP4_FH;
47our $ICMP6_FH;
48
49our @IDLE_CB;
50
51AnyEvent::post_detect {
45our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; 52 our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4;
46our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; 53 our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6;
54
55 our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
56 sysread $THR_RES_FH, my $buf, 8;
57
58 for my $id (unpack "S*", $buf) {
59 _stop_id $id;
60 ($IDLE_CB[$id] || sub { })->();
61 }
62 };
63};
47 64
48=item AnyEvent::FastPing::ipv4_supported 65=item AnyEvent::FastPing::ipv4_supported
49 66
50Returns true iff IPv4 is supported in this module and on this system. 67Returns true iff IPv4 is supported in this module and on this system.
51 68
101When a range is exhausted, it is removed. When all ranges are exhausted, 118When 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 119the pinger waits another C<max_rtt> seconds and then exits, causing the
103idle callback to trigger. 120idle callback to trigger.
104 121
105Performance: On my 2 GHz Opteron system with a pretty average nvidia 122Performance: On my 2 GHz Opteron system with a pretty average nvidia
106gigabit network card I can ping around 60k to 200k adresses per second, 123gigabit network card I can ping around 60k to 200k addresses per second,
107depending on routing decisions. 124depending on routing decisions.
108 125
109Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and 126Example: 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 12711.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 128loopback address 5 times as fast as possible. Do not, however, exceed 1000
112packets/s overall. Dump each received reply: 129packets/s overall. Also dump each received reply.
113 130
114 use AnyEvent::Socket; 131 use AnyEvent::Socket;
115 use AnyEvent::FastPing; 132 use AnyEvent::FastPing;
116 133
117 my $done = AnyEvent->condvar; 134 my $done = AnyEvent->condvar;
144=over 4 161=over 4
145 162
146=item $pinger = new AnyEvent::FastPing 163=item $pinger = new AnyEvent::FastPing
147 164
148Creates a new pinger - right now there can be at most C<65536> pingers in 165Creates 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 166a process, although that limit might change to something drastically lower
150- you should be stringy with your pinger objects. 167- you should be stingy with your pinger objects.
151 168
152=cut 169=cut
153 170
154sub new { 171sub new {
155 my ($klass) = @_; 172 my ($klass) = @_;
156 173
174 AnyEvent::detect unless defined $AnyEvent::MODEL;
175
157 _new $klass, (rand 65536), (rand 65536), (rand 65536) 176 _new $klass, (rand 65536), (rand 65536), (rand 65536)
158} 177}
159
160our @IDLE_CB;
161 178
162sub DESTROY { 179sub DESTROY {
163 undef $IDLE_CB[ &id ]; 180 undef $IDLE_CB[ &id ];
164 &_free; 181 &_free;
165} 182}
166 183
167=item $pinger->on_recv ($callback->([[$host, $rtt], ...])) 184=item $pinger->on_recv ($callback->([[$host, $rtt], ...]))
168 185
169Registeres a callback to be called for ping replies. If no callback has 186Registers a callback to be called for ping replies. If no callback has
170been registered than ping replies will be ignored, otherwise this module 187been registered than ping replies will be ignored, otherwise this module
171calculates the round trip time, in seconds, for each reply and calls this 188calculates the round trip time, in seconds, for each reply and calls this
172callback. 189callback.
173 190
174The callback receives a single argument, which is an array reference 191The callback receives a single argument, which is an array reference
175with an entry for each reply packet (the replies will be batched for 192with an entry for each reply packet (the replies will be batched for
176efficiency). Each member in the array reference is again an array 193efficiency). Each member in the array reference is again an array
177reference with exactly two members: the binary host addresss (4 octets for 194reference with exactly two members: the binary host address (4 octets for
178IPv4, 16 for IPv6) and the approximate round trip time, in seconds. 195IPv4, 16 for IPv6) and the approximate round trip time, in seconds.
179 196
180The replies will be passed to the callback as soon as they arrive, and 197The replies will be passed to the callback as soon as they arrive, and
181this callback can be called many times with batches of replies. 198this callback can be called many times with batches of replies.
182 199
196 213
197 $pinger->on_recv (sub { 214 $pinger->on_recv (sub {
198 for (@{ $_[0] }) { 215 for (@{ $_[0] }) {
199 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; 216 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
200 } 217 }
201 }; 218 });
202 219
203Example: a single ping reply with payload of 1 from C<::1> gets passed 220Example: a single ping reply with payload of 1 from C<::1> gets passed
204like this: 221like this:
205 222
206 [ 223 [
225 242
226sub on_idle { 243sub on_idle {
227 $IDLE_CB[ &id ] = $_[1]; 244 $IDLE_CB[ &id ] = $_[1];
228} 245}
229 246
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) 247=item $pinger->interval ($seconds)
240 248
241Configures the minimum interval between packet sends for this pinger - the 249Configures the minimum interval between packet sends for this pinger - the
242pinger will not send packets faster than this rate (or atcually 1 / rate), 250pinger will not send packets faster than this rate (or actually 1 / rate),
243even if individual ranges have a lower interval. 251even if individual ranges have a lower interval.
244 252
245A value of C<0> selects the fastests possible speed (currently no faster 253A value of C<0> selects the fastest possible speed (currently no faster
246than 1_000_000 packets/s). 254than 1_000_000 packets/s).
247 255
248=item $pinger->max_rtt ($seconds) 256=item $pinger->max_rtt ($seconds)
249 257
250If your idle callback were called instantly after all ranges were 258If your idle callback were called instantly after all ranges were
251exhausted and you destroyed the object inside (which is common), then 259exhausted and you destroyed the object inside (which is common), then
252there would be no chance to receive some replies, as there would be no 260there would be no chance to receive some replies, as there would be no
253time fo the packet to travel over the network. 261time of the packet to travel over the network.
254 262
255This can be fixed by starting a timer in the idle callback, or more simply 263This 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 264by 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. 265you allow a ping packet to travel to its destination and back.
258 266
259The pinger thread automatically waits for this amount of time before becoming idle. 267The pinger thread automatically waits for this amount of time before becoming idle.
260 268
261The default is currently C<0.5> seconds, which is usually plenty. 269The default is currently C<0.5> seconds, which is usually plenty.
262 270
270You can convert IP addresses from text to binary form by 278You can convert IP addresses from text to binary form by
271using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>, 279using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>,
272C<Socket6::inet_pton> or any other method that you like :) 280C<Socket6::inet_pton> or any other method that you like :)
273 281
274The algorithm to select the next address is O(log n) on the number of 282The 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. 283ranges, so even a large number of ranges (many thousands) is manageable.
276 284
277No storage is allocated per address. 285No storage is allocated per address.
278 286
279Note that, while IPv6 addresses are currently supported, the usefulness of 287Note that, while IPv6 addresses are currently supported, the usefulness of
280this option is extremely limited and might be gone in future versions - if 288this option is extremely limited and might be gone in future versions - if
283 291
284=item $pinger->add_hosts ([$host...], $interval, $interleave) 292=item $pinger->add_hosts ([$host...], $interval, $interleave)
285 293
286Similar to C<add_range>, but uses a list of single addresses instead. The 294Similar 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 295list 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, 296the 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 297addresses are IPv4 addresses, then a compact IPv4-only format will be used
290create two host ranges if you have mixed addresses. 298to store the list internally.
291 299
292Minimum C<$interval> is the same as for C<add_range> and can be left out. 300Minimum C<$interval> is the same as for C<add_range> and can be left out.
293 301
294C<$interlave> specifies an increment between addresses: often address 302C<$interlave> specifies an increment between addresses: often address
295lists are generated in a way that results in clustering - first all 303lists are generated in a way that results in clustering - first all

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines