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

# Content
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 This module was written for a single purpose only: sending ICMP ECHO
12 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 our $VERSION = '1.13';
33 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 be sent as fast as possible.
97
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 entry for each received packet (replies are being batched for greater
162 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 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 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 sub register_cb($) {
215 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 Marc Lehmann <schmorp@schmorp.de>
229 http://home.schmorp.de/
230
231 =head1 LICENSE
232
233 This software is distributed under the GENERAL PUBLIC LICENSE, version 2
234 or any later version or, at your option, the Artistic License.
235
236 =cut
237