ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
Revision: 1.10
Committed: Sat Jan 29 23:55:37 2011 UTC (13 years, 3 months ago) by root
Branch: MAIN
CVS Tags: rel-1_15
Changes since 1.9: +3 -5 lines
Log Message:
1.15

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