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

# 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 common::sense;
27
28 use AnyEvent;
29
30 BEGIN {
31 our $VERSION = '1.15';
32 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 our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
48 my $sv = _read_res
49 or return;
50
51 $sv->();
52 };
53
54 our $THR_REQ_BUF;
55
56 sub _send_req($) {
57 $THR_REQ_BUF .= $_[0];
58
59 $THR_REQ_W ||= AE::io $THR_REQ_FH, 1, sub {
60 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 };
65 }
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 be sent as fast as possible.
96
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 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
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 entry for each received packet (replies are being batched for greater
159 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 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 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 sub register_cb($) {
212 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 Marc Lehmann <schmorp@schmorp.de>
226 http://home.schmorp.de/
227
228 =head1 LICENSE
229
230 This software is distributed under the GENERAL PUBLIC LICENSE, version 2
231 or any later version or, at your option, the Artistic License.
232
233 =cut
234