ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
Revision: 1.11
Committed: Mon Jan 31 05:35:48 2011 UTC (13 years, 3 months ago) by root
Branch: MAIN
Changes since 1.10: +49 -27 lines
Log Message:
halfway?

File Contents

# User Rev Content
1 root 1.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 root 1.2 This module was written for a single purpose only: sending ICMP ECHO
12 root 1.1 REQUEST packets as quickly as possible to a large number of hosts
13     (thousands to millions).
14    
15     It employs a sending thread and is fully event-driven (using AnyEvent), so
16     you have to run an event model supported by AnyEvent to use this module.
17    
18     =head1 FUNCTIONS
19    
20     =over 4
21    
22     =cut
23    
24     package AnyEvent::FastPing;
25    
26 root 1.9 use common::sense;
27 root 1.1
28     use AnyEvent;
29    
30     BEGIN {
31 root 1.11 our $VERSION = '2.0';
32 root 1.1 our @ISA = qw(Exporter);
33    
34     require Exporter;
35     #Exporter::export_ok_tags (keys %EXPORT_TAGS);
36    
37     require XSLoader;
38     XSLoader::load (__PACKAGE__, $VERSION);
39     }
40    
41 root 1.11 our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
42 root 1.1
43     our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen";
44    
45 root 1.11 our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4;
46     our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6;
47 root 1.1
48     =item AnyEvent::FastPing::ipv4_supported
49    
50     Returns true if IPv4 is supported in this module and on this system.
51    
52     =item AnyEvent::FastPing::ipv6_supported
53    
54     Returns true if IPv6 is supported in this module and on this system.
55    
56     =item AnyEvent::FastPing::icmp4_pktsize
57    
58     Returns the number of bytes each IPv4 ping packet has.
59    
60     =item AnyEvent::FastPing::icmp6_pktsize
61    
62     Returns the number of bytes each IPv4 ping packet has.
63    
64 root 1.11 =cut
65    
66     sub new {
67     my ($klass) = @_;
68    
69     _new $klass, (rand 65536), (rand 65536), (rand 65536)
70     }
71    
72     our @IDLE_CB;
73    
74     sub DESTROY {
75     undef $IDLE_CB[ &id ];
76     &_free;
77     }
78    
79     sub on_idle {
80     $IDLE_CB[ &id ] = $_[1];
81     }
82    
83     our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
84     sysread $THR_RES_FH, my $buf, 8;
85    
86     for my $id (unpack "S*", $buf) {
87     _stop_id $id;
88     ($IDLE_CB[$id] || sub { })->();
89     }
90     };
91    
92     for(1..10) {
93     my $p = new AnyEvent::FastPing;#d#
94     $p->interval (0);
95     $p->max_rtt (0.5);
96     #$p->add_range (v127.0.0.1, v127.255.255.254, 0);
97     $p->add_range (v1.0.0.1, v1.255.255.254, 0);
98     $p->on_idle (my $cv = AE::cv);
99     my $cnt;
100     $p->on_recv (sub {
101     $cnt++;
102     });
103     $p->start;
104     $cv->recv;
105     warn $cnt;
106     }
107    
108 root 1.1 =item AnyEvent::FastPing::icmp_ping [ranges...], $send_interval, $payload, \&callback
109    
110     Ping the given IPv4 address ranges. Each range is an arrayref of the
111     form C<[lo, hi, interval]>, where C<lo> and C<hi> are octet strings with
112     either 4 octets (for IPv4 addresses) or 16 octets (for IPV6 addresses),
113     representing the lowest and highest address to ping (you can convert a
114     dotted-quad IPv4 address to this format by using C<inet_aton $address>. The
115     range C<interval> is the minimum time in seconds between pings to the
116     given range. If omitted, defaults to C<$send_interval>.
117    
118     The C<$send_interval> is the minimum interval between sending any two
119     packets and is a way to make an overall rate limit. If omitted, pings will
120 root 1.5 be sent as fast as possible.
121 root 1.1
122     The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO
123     REQUEST ident and sequence numbers (in unspecified order :).
124    
125     The request will be queued and all requests will be served by a background
126     thread in order. When all ranges have been pinged, the C<callback> will be
127     called.
128    
129     Algorithm: Each range has an associated "next time to send packet"
130     time. The algorithm loops as long as there are ranges with hosts to be
131     pinged and always serves the range with the most urgent packet send
132     time. It will at most send one packet every C<$send_interval> seconds.
133    
134     This will ensure that pings to the same range are nicely interleaved with
135     other ranges - this can help reduce per-subnet bandwidth while maintaining
136     an overall high packet rate.
137    
138     The algorithm to send each packet is O(log n) on the number of ranges, so
139     even a large number of ranges (many thousands) is managable.
140    
141     No storage is allocated per address.
142    
143     Performance: On my 2 GHz Opteron system with a pretty average nvidia
144     gigabit network card I can ping around 60k to 200k adresses per second,
145     depending on routing decisions.
146    
147     Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
148     11.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed
149     1000 packets/s overall:
150    
151     my $done = AnyEvent->condvar;
152    
153     AnyEvent::FastPing::icmp_ping
154     [
155     [v10.0.0.1, v10.0.0.15, .01],
156     [v11.0.0.1, v11.0.255.255, .001],
157     ],
158     .001, 0x12345678,
159     sub {
160     warn "all ranges pinged\n";
161     $done->broadcast;
162     }
163     ;
164    
165     $done->wait;
166    
167     =cut
168    
169     sub icmp_ping($$$&) {
170 root 1.11 # _send_req _req_icmp_ping @_;
171 root 1.1 }
172    
173     =item AnyEvent::FastPing::register_cb \&cb
174    
175     Register a callback that is called for every received ping reply
176     (regardless of whether a ping is still in process or not and regardless of
177     whether the reply is actually a reply to a ping sent earlier).
178    
179     The code reference gets a single parameter - an arrayref with an
180 root 1.6 entry for each received packet (replies are being batched for greater
181 root 1.1 efficiency). Each packet is represented by an arrayref with three members:
182     the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets
183     length), the payload as passed to C<icmp_ping> and the round trip time in
184     seconds.
185    
186 root 1.8 Example: register a callback which simply dumps the received data. Since
187     the coderef is created on the fly via sub, it would be hard to unregister
188     this callback again :)
189    
190     AnyEvent::FastPing::register_cb sub {
191     for (@{$_[0]}) {
192     printf "%s %d %g\n",
193     (4 == length $_->[0] ? inet_ntoa $_->[0] : Socket6::inet_ntop (&AF_INET6, $_->[0])),
194     $_->[2],
195     $_->[1];
196     }
197     };
198    
199 root 1.1 Example: a single ping reply with payload of 1 from C<::1> gets passed
200     like this:
201    
202     [ [
203     "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1",
204     "0.000280141830444336",
205     1
206     ] ]
207    
208     Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of
209     C<0x12345678>:
210    
211     [
212     [
213     "\177\0\0\1",
214     "0.00015711784362793",
215     305419896
216     ],
217     [
218     "\177\0\0\2",
219     "0.00090184211731",
220     305419896
221     ]
222     ]
223    
224     =item AnyEvent::FastPing::unregister_cb \&cb
225    
226     Unregister the callback again (make sure you pass the same codereference
227     as to C<register_cb>).
228    
229     =cut
230    
231     our @CB;
232    
233 root 1.8 sub register_cb($) {
234 root 1.1 push @CB, $_[0];
235     }
236    
237     sub unregister_cb($) {
238     @CB = grep $_ != $_[0], @CB;
239     }
240    
241     1;
242    
243     =back
244    
245     =head1 AUTHOR
246    
247 root 1.4 Marc Lehmann <schmorp@schmorp.de>
248     http://home.schmorp.de/
249 root 1.1
250 root 1.4 =head1 LICENSE
251 root 1.1
252 root 1.4 This software is distributed under the GENERAL PUBLIC LICENSE, version 2
253     or any later version or, at your option, the Artistic License.
254 root 1.1
255     =cut
256