ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
Revision: 1.8
Committed: Wed Apr 7 14:13:16 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-1_13
Changes since 1.7: +15 -2 lines
Log Message:
rel-1_13

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