ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FPing.pm
Revision: 1.5
Committed: Fri May 4 15:16:14 2007 UTC (17 years, 3 months ago) by root
Branch: MAIN
Changes since 1.4: +2 -10 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 root 1.3 =head1 FUNCTIONS
19    
20 root 1.1 =over 4
21    
22     =cut
23    
24     package Net::FPing;
25    
26 root 1.3 use strict;
27     no warnings;
28    
29 root 1.1 use AnyEvent;
30    
31     BEGIN {
32 root 1.3 our $VERSION = '0.01';
33     our @ISA = qw(Exporter);
34 root 1.1
35     require Exporter;
36 root 1.3 #Exporter::export_ok_tags (keys %EXPORT_TAGS);
37 root 1.1
38     require XSLoader;
39 root 1.3 XSLoader::load (__PACKAGE__, $VERSION);
40 root 1.1 }
41    
42 root 1.3 our ($THR_REQ_FD, $THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
43    
44 root 1.1 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 root 1.3 our $THR_REQ_BUF;
56 root 1.1
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 root 1.2 =item Net::FPing::ipv4_supported
69    
70     Returns true if IPv4 is supported in this module and on this system.
71    
72     =item Net::FPing::ipv6_supported
73    
74     Returns true if IPv6 is supported in this module and on this system.
75    
76 root 1.5 =item Net::FPing::icmp4_pktsize
77 root 1.2
78     Returns the number of bytes each IPv4 ping packet has.
79    
80 root 1.5 =item Net::FPing::icmp6_pktsize
81 root 1.2
82     Returns the number of bytes each IPv4 ping packet has.
83    
84     =item Net::FPing::icmp_ping [ranges...], $send_interval, $payload, \&callback
85 root 1.1
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 send as fast as possible.
97    
98 root 1.4 The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO
99     REQUEST ident and sequence numbers (in unspecified order :).
100 root 1.1
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. The
109     algorithm to send each packet is O(log n) on the number of ranges, so even
110 root 1.2 a large number of ranges (many thousands) is managable. No storage is
111     allocated per address.
112 root 1.1
113 root 1.3 Performance: On my 2 GHz Opteron system with a pretty average nvidia
114 root 1.1 gigabit network card I can ping around 60k to 200k adresses per second,
115     depending on routing decisions.
116    
117     Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
118     11.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed
119 root 1.2 1000 packets/s overall:
120 root 1.1
121 root 1.3 my $done = AnyEvent->condvar;
122    
123 root 1.2 Net::FPing::icmp_ping
124 root 1.1 [v10.0.0.1, v10.0.0.15, .01],
125     [v11.0.0.1, v11.0.255.255, .001],
126     .001, 0x12345678,
127     sub {
128     warn "all ranges pinged\n";
129 root 1.3 $done->broadcast;
130 root 1.1 }
131     ;
132    
133 root 1.3 $done->wait;
134    
135 root 1.1 =cut
136    
137 root 1.2 sub icmp_ping($$$&) {
138     _send_req _req_icmp_ping @_;
139 root 1.1 }
140    
141     our $ICMP4_FH;
142     our $ICMP4_W = (open $ICMP4_FH, "<&=$ICMP4_FD") && AnyEvent->io (fh => $ICMP4_FH, poll => 'r', cb => \&_recv_icmp4);
143     our $ICMP6_FH;
144     our $ICMP6_W = (open $ICMP6_FH, "<&=$ICMP6_FD") && AnyEvent->io (fh => $ICMP6_FH, poll => 'r', cb => \&_recv_icmp6);
145    
146 root 1.4 =item Net::FPing::register_cb \&cb
147    
148     Register a callback that is called for every received ping reply
149     (regardless of whether a ping is still in process or not and regardless of
150     whether the reply is actually a reply ot a ping sent earlier).
151    
152     The code reference gets a single parameter - an arrayref with an
153     entry for each received packet (replies are beign batched for greater
154     efficiency). Each packet is represented by an arrayref with three members:
155     the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets
156     length), the payload as passed to C<icmp_ping> and the round trip time in
157     seconds.
158    
159     Example: a single ping reply with payload of 1 from C<::1> gets passed
160     like this:
161    
162     [ [
163     "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1",
164     "0.000280141830444336",
165     1
166     ] ]
167    
168     Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of
169     C<0x12345678>:
170    
171     [
172     [
173     "\177\0\0\1",
174     "0.00015711784362793",
175     305419896
176     ],
177     [
178     "\177\0\0\2",
179     "0.00090184211731",
180     305419896
181     ]
182     ]
183    
184     =item Net::FPing::unregister_cb \&cb
185    
186     Unregister the callback again (make sure you pass the same codereference
187     as to C<register_cb>).
188    
189     =cut
190    
191     our @CB;
192    
193     sub register_cb(&) {
194     push @CB, $_[0];
195     }
196    
197     sub unregister_cb($) {
198     @CB = grep $_ != $_[0], @CB;
199     }
200    
201 root 1.2 1;
202 root 1.1
203 root 1.2 =back
204 root 1.1
205     =head1 AUTHOR
206    
207     Marc Lehmann <schmorp@schmorp.de>
208     http://home.schmorp.de/
209    
210     =head1 AUTHOR
211    
212     This software is distributed under the GENERAL PUBLIC LICENSE,
213     version 2 or any later.
214    
215     =cut
216