ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FPing.pm
Revision: 1.4
Committed: Fri May 4 13:50:02 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.3: +57 -2 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Net::FPing - quickly ping a large number of hosts
4
5 =head1 SYNOPSIS
6
7 use Net::FPing;
8
9 =head1 DESCRIPTION
10
11 This module was written for a signle purpose only: sendinf ICMP EHCO
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 Receiving and processing reply packets is not currently supported by this
19 module.
20
21 =head1 FUNCTIONS
22
23 =over 4
24
25 =cut
26
27 package Net::FPing;
28
29 use strict;
30 no warnings;
31
32 use AnyEvent;
33
34 BEGIN {
35 our $VERSION = '0.01';
36 our @ISA = qw(Exporter);
37
38 require Exporter;
39 #Exporter::export_ok_tags (keys %EXPORT_TAGS);
40
41 require XSLoader;
42 XSLoader::load (__PACKAGE__, $VERSION);
43 }
44
45 our ($THR_REQ_FD, $THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
46
47 our $THR_REQ_FH; open $THR_REQ_FH, ">&=$THR_REQ_FD" or die "FATAL: cannot fdopen";
48 our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen";
49
50 our $THR_REQ_W;
51 our $THR_RES_W = AnyEvent->io (fh => $THR_RES_FH, poll => 'r', cb => sub {
52 my $sv = _read_res
53 or return;
54
55 $sv->();
56 });
57
58 our $THR_REQ_BUF;
59
60 sub _send_req($) {
61 $THR_REQ_BUF .= $_[0];
62
63 $THR_REQ_W ||= AnyEvent->io (fh => $THR_REQ_FH, poll => 'w', cb => sub {
64 my $len = syswrite $THR_REQ_FH, $THR_REQ_BUF;
65 substr $THR_REQ_BUF, 0, $len, "";
66
67 undef $THR_REQ_W unless length $THR_REQ_BUF;
68 });
69 }
70
71 =item Net::FPing::ipv4_supported
72
73 Returns true if IPv4 is supported in this module and on this system.
74
75 =item Net::FPing::ipv6_supported
76
77 Returns true if IPv6 is supported in this module and on this system.
78
79 =item Net::FPing::ipv4_pktsize
80
81 Returns the number of bytes each IPv4 ping packet has.
82
83 =item Net::FPing::ipv6_pktsize
84
85 Returns the number of bytes each IPv4 ping packet has.
86
87 =item Net::FPing::icmp_ping [ranges...], $send_interval, $payload, \&callback
88
89 Ping the given IPv4 address ranges. Each range is an arrayref of the
90 form C<[lo, hi, interval]>, where C<lo> and C<hi> are octet strings with
91 either 4 octets (for IPv4 addresses) or 16 octets (for IPV6 addresses),
92 representing the lowest and highest address to ping (you can convert a
93 dotted-quad IPv4 address to this format by using C<inet_aton $address>. The
94 range C<interval> is the minimum time in seconds between pings to the
95 given range. If omitted, defaults to C<$send_interval>.
96
97 The C<$send_interval> is the minimum interval between sending any two
98 packets and is a way to make an overall rate limit. If omitted, pings will
99 be send as fast as possible.
100
101 The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO
102 REQUEST ident and sequence numbers (in unspecified order :).
103
104 The request will be queued and all requests will be served by a background
105 thread in order. When all ranges have been pinged, the C<callback> will be
106 called.
107
108 Algorithm: Each range has an associated "next time to send packet"
109 time. The algorithm loops as long as there are ranges with hosts to be
110 pinged and always serves the range with the most urgent packet send
111 time. It will at most send one packet every C<$send_interval> seconds. The
112 algorithm to send each packet is O(log n) on the number of ranges, so even
113 a large number of ranges (many thousands) is managable. No storage is
114 allocated per address.
115
116 Performance: On my 2 GHz Opteron system with a pretty average nvidia
117 gigabit network card I can ping around 60k to 200k adresses per second,
118 depending on routing decisions.
119
120 Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
121 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed
122 1000 packets/s overall:
123
124 my $done = AnyEvent->condvar;
125
126 Net::FPing::icmp_ping
127 [v10.0.0.1, v10.0.0.15, .01],
128 [v11.0.0.1, v11.0.255.255, .001],
129 .001, 0x12345678,
130 sub {
131 warn "all ranges pinged\n";
132 $done->broadcast;
133 }
134 ;
135
136 $done->wait;
137
138 =cut
139
140 sub icmp_ping($$$&) {
141 _send_req _req_icmp_ping @_;
142 }
143
144 our $ICMP4_FH;
145 our $ICMP4_W = (open $ICMP4_FH, "<&=$ICMP4_FD") && AnyEvent->io (fh => $ICMP4_FH, poll => 'r', cb => \&_recv_icmp4);
146 our $ICMP6_FH;
147 our $ICMP6_W = (open $ICMP6_FH, "<&=$ICMP6_FD") && AnyEvent->io (fh => $ICMP6_FH, poll => 'r', cb => \&_recv_icmp6);
148
149 =item Net::FPing::register_cb \&cb
150
151 Register a callback that is called for every received ping reply
152 (regardless of whether a ping is still in process or not and regardless of
153 whether the reply is actually a reply ot a ping sent earlier).
154
155 The code reference gets a single parameter - an arrayref with an
156 entry for each received packet (replies are beign batched for greater
157 efficiency). Each packet is represented by an arrayref with three members:
158 the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets
159 length), the payload as passed to C<icmp_ping> and the round trip time in
160 seconds.
161
162 Example: a single ping reply with payload of 1 from C<::1> gets passed
163 like this:
164
165 [ [
166 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1",
167 "0.000280141830444336",
168 1
169 ] ]
170
171 Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of
172 C<0x12345678>:
173
174 [
175 [
176 "\177\0\0\1",
177 "0.00015711784362793",
178 305419896
179 ],
180 [
181 "\177\0\0\2",
182 "0.00090184211731",
183 305419896
184 ]
185 ]
186
187 =item Net::FPing::unregister_cb \&cb
188
189 Unregister the callback again (make sure you pass the same codereference
190 as to C<register_cb>).
191
192 =cut
193
194 our @CB;
195
196 sub register_cb(&) {
197 push @CB, $_[0];
198 }
199
200 sub unregister_cb($) {
201 @CB = grep $_ != $_[0], @CB;
202 }
203
204 1;
205
206 =back
207
208 =head1 BUGS AND SHORTCOMINGS
209
210 - replies are not yet accessible.
211 - ipv6 support has never ever been tested.
212
213 =head1 AUTHOR
214
215 Marc Lehmann <schmorp@schmorp.de>
216 http://home.schmorp.de/
217
218 =head1 AUTHOR
219
220 This software is distributed under the GENERAL PUBLIC LICENSE,
221 version 2 or any later.
222
223 =cut
224