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, 1 month ago) by root
Branch: MAIN
Changes since 1.4: +2 -10 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 =head1 FUNCTIONS
19
20 =over 4
21
22 =cut
23
24 package Net::FPing;
25
26 use strict;
27 no warnings;
28
29 use AnyEvent;
30
31 BEGIN {
32 our $VERSION = '0.01';
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 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 =item Net::FPing::icmp4_pktsize
77
78 Returns the number of bytes each IPv4 ping packet has.
79
80 =item Net::FPing::icmp6_pktsize
81
82 Returns the number of bytes each IPv4 ping packet has.
83
84 =item Net::FPing::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 send 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. The
109 algorithm to send each packet is O(log n) on the number of ranges, so even
110 a large number of ranges (many thousands) is managable. No storage is
111 allocated per address.
112
113 Performance: On my 2 GHz Opteron system with a pretty average nvidia
114 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 1000 packets/s overall:
120
121 my $done = AnyEvent->condvar;
122
123 Net::FPing::icmp_ping
124 [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 $done->broadcast;
130 }
131 ;
132
133 $done->wait;
134
135 =cut
136
137 sub icmp_ping($$$&) {
138 _send_req _req_icmp_ping @_;
139 }
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 =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 1;
202
203 =back
204
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