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, 3 months ago) by root
Branch: MAIN
Changes since 1.3: +57 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.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 root 1.3 =head1 FUNCTIONS
22    
23 root 1.1 =over 4
24    
25     =cut
26    
27     package Net::FPing;
28    
29 root 1.3 use strict;
30     no warnings;
31    
32 root 1.1 use AnyEvent;
33    
34     BEGIN {
35 root 1.3 our $VERSION = '0.01';
36     our @ISA = qw(Exporter);
37 root 1.1
38     require Exporter;
39 root 1.3 #Exporter::export_ok_tags (keys %EXPORT_TAGS);
40 root 1.1
41     require XSLoader;
42 root 1.3 XSLoader::load (__PACKAGE__, $VERSION);
43 root 1.1 }
44    
45 root 1.3 our ($THR_REQ_FD, $THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
46    
47 root 1.1 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 root 1.3 our $THR_REQ_BUF;
59 root 1.1
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 root 1.2 =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 root 1.1
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 root 1.4 The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO
102     REQUEST ident and sequence numbers (in unspecified order :).
103 root 1.1
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 root 1.2 a large number of ranges (many thousands) is managable. No storage is
114     allocated per address.
115 root 1.1
116 root 1.3 Performance: On my 2 GHz Opteron system with a pretty average nvidia
117 root 1.1 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 root 1.2 1000 packets/s overall:
123 root 1.1
124 root 1.3 my $done = AnyEvent->condvar;
125    
126 root 1.2 Net::FPing::icmp_ping
127 root 1.1 [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 root 1.3 $done->broadcast;
133 root 1.1 }
134     ;
135    
136 root 1.3 $done->wait;
137    
138 root 1.1 =cut
139    
140 root 1.2 sub icmp_ping($$$&) {
141     _send_req _req_icmp_ping @_;
142 root 1.1 }
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 root 1.4 =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 root 1.2 1;
205 root 1.1
206 root 1.2 =back
207 root 1.1
208 root 1.2 =head1 BUGS AND SHORTCOMINGS
209 root 1.1
210 root 1.2 - replies are not yet accessible.
211     - ipv6 support has never ever been tested.
212 root 1.1
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