… | |
… | |
10 | |
10 | |
11 | This module was written for a single purpose only: sending ICMP ECHO |
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 |
12 | REQUEST packets as quickly as possible to a large number of hosts |
13 | (thousands to millions). |
13 | (thousands to millions). |
14 | |
14 | |
15 | It employs a sending thread and is fully event-driven (using AnyEvent), so |
15 | It employs a separate thread and is fully event-driven (using AnyEvent), |
16 | you have to run an event model supported by AnyEvent to use this module. |
16 | so you have to run an event model supported by AnyEvent to use this |
|
|
17 | module. |
17 | |
18 | |
18 | =head1 FUNCTIONS |
19 | =head1 FUNCTIONS |
19 | |
20 | |
20 | =over 4 |
21 | =over 4 |
21 | |
22 | |
22 | =cut |
23 | =cut |
23 | |
24 | |
24 | package AnyEvent::FastPing; |
25 | package AnyEvent::FastPing; |
25 | |
26 | |
26 | use strict; |
27 | use common::sense; |
27 | no warnings; |
|
|
28 | |
28 | |
29 | use AnyEvent; |
29 | use AnyEvent; |
30 | |
30 | |
31 | BEGIN { |
31 | BEGIN { |
32 | our $VERSION = '1.11'; |
32 | our $VERSION = '2.0'; |
33 | our @ISA = qw(Exporter); |
33 | our @ISA = qw(Exporter); |
34 | |
34 | |
35 | require Exporter; |
35 | require Exporter; |
36 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
36 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
37 | |
37 | |
38 | require XSLoader; |
38 | require XSLoader; |
39 | XSLoader::load (__PACKAGE__, $VERSION); |
39 | XSLoader::load (__PACKAGE__, $VERSION); |
40 | } |
40 | } |
41 | |
41 | |
42 | our ($THR_REQ_FD, $THR_RES_FD, $ICMP4_FD, $ICMP6_FD); |
42 | our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD); |
43 | |
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"; |
44 | our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen"; |
46 | |
45 | |
47 | our $THR_REQ_W; |
46 | our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; |
48 | our $THR_RES_W = AnyEvent->io (fh => $THR_RES_FH, poll => 'r', cb => sub { |
47 | our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; |
49 | my $sv = _read_res |
|
|
50 | or return; |
|
|
51 | |
48 | |
52 | $sv->(); |
49 | =item AnyEvent::FastPing::ipv4_supported |
53 | }); |
|
|
54 | |
50 | |
55 | our $THR_REQ_BUF; |
51 | Returns true iff IPv4 is supported in this module and on this system. |
56 | |
52 | |
57 | sub _send_req($) { |
53 | =item AnyEvent::FastPing::ipv6_supported |
58 | $THR_REQ_BUF .= $_[0]; |
|
|
59 | |
54 | |
60 | $THR_REQ_W ||= AnyEvent->io (fh => $THR_REQ_FH, poll => 'w', cb => sub { |
55 | Returns true iff IPv6 is supported in this module and on this system. |
61 | my $len = syswrite $THR_REQ_FH, $THR_REQ_BUF; |
|
|
62 | substr $THR_REQ_BUF, 0, $len, ""; |
|
|
63 | |
56 | |
64 | undef $THR_REQ_W unless length $THR_REQ_BUF; |
57 | =item AnyEvent::FastPing::icmp4_pktsize |
|
|
58 | |
|
|
59 | Returns the number of octets per IPv4 ping packet (the whole IP packet |
|
|
60 | including headers, excluding lower-level headers or trailers such as |
|
|
61 | Ethernet). |
|
|
62 | |
|
|
63 | Can be used to calculate e.g. octets/s from rate ... |
|
|
64 | |
|
|
65 | my $octets_per_second = $packets_per_second * AnyEvent::FastPing::icmp4_pktsize; |
|
|
66 | |
|
|
67 | ... or convert kilobit/second to packet rate ... |
|
|
68 | |
|
|
69 | my $packets_per_second = $kilobit_per_second |
|
|
70 | * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize); |
|
|
71 | |
|
|
72 | etc. |
|
|
73 | |
|
|
74 | =item AnyEvent::FastPing::icmp6_pktsize |
|
|
75 | |
|
|
76 | Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6. |
|
|
77 | |
|
|
78 | =back |
|
|
79 | |
|
|
80 | =head1 THE AnyEvent::FastPing CLASS |
|
|
81 | |
|
|
82 | The AnyEvent::FastPing class represents a single "pinger". A "pinger" |
|
|
83 | comes with its own thread to send packets in the background, a rate-limit |
|
|
84 | machinery and separate idle/receive callbacks. |
|
|
85 | |
|
|
86 | The recommended workflow (there are others) is this: 1. create a new |
|
|
87 | AnyEvent::FastPing object 2. configure the address lists and ranges to |
|
|
88 | ping, also configure an idle callback and optionally a receive callback |
|
|
89 | 3. C<start> the pinger. |
|
|
90 | |
|
|
91 | When the pinger has finished pinging all the configured addresses it will |
|
|
92 | call the idle callback. |
|
|
93 | |
|
|
94 | The pinging process works like this: every range has a minimum interval |
|
|
95 | between sends, which is used to limit the rate at which hosts in that |
|
|
96 | range are being pinged. Distinct ranges are independent of each other, |
|
|
97 | which is why there is a per-pinger "global" minimum interval as well. |
|
|
98 | |
|
|
99 | The pinger sends pings as fats as possible, while both obeying the pinger |
|
|
100 | rate limit as well as range limits. |
|
|
101 | |
|
|
102 | When a range is exhausted, it is removed. When all ranges are exhausted, |
|
|
103 | the pinger waits another C<max_rtt> seconds and then exits, causing the |
|
|
104 | idle callback to trigger. |
|
|
105 | |
|
|
106 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
|
|
107 | gigabit network card I can ping around 60k to 200k addresses per second, |
|
|
108 | depending on routing decisions. |
|
|
109 | |
|
|
110 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
|
|
111 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6 |
|
|
112 | loopback address 5 times as fast as possible. Do not, however, exceed 1000 |
|
|
113 | packets/s overall. Also dump each received reply. |
|
|
114 | |
|
|
115 | use AnyEvent::Socket; |
|
|
116 | use AnyEvent::FastPing; |
|
|
117 | |
|
|
118 | my $done = AnyEvent->condvar; |
|
|
119 | |
|
|
120 | my $pinger = new AnyEvent::FastPing; |
|
|
121 | |
|
|
122 | $pinger->interval (1/1000); |
|
|
123 | $pinger->max_rtt (0.1); # reasonably fast/reliable network |
|
|
124 | |
|
|
125 | $pinger->add_range (v10.0.0.1, v10.0.0.15, 1/100); |
|
|
126 | $pinger->add_range (v11.0.0.1, v11.0.255.255, 1/1000); |
|
|
127 | $pinger->add_hosts ([ (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1) x 5 ]); |
|
|
128 | |
|
|
129 | $pinger->on_recv (sub { |
|
|
130 | for (@{ $_[0] }) { |
|
|
131 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
|
|
132 | } |
65 | }); |
133 | }); |
|
|
134 | |
|
|
135 | $pinger->on_idle (sub { |
|
|
136 | print "done\n"; |
|
|
137 | undef $pinger; |
|
|
138 | }); |
|
|
139 | |
|
|
140 | $pinger->start; |
|
|
141 | $done->wait; |
|
|
142 | |
|
|
143 | =head2 METHODS |
|
|
144 | |
|
|
145 | =over 4 |
|
|
146 | |
|
|
147 | =item $pinger = new AnyEvent::FastPing |
|
|
148 | |
|
|
149 | Creates a new pinger - right now there can be at most C<65536> pingers in |
|
|
150 | a process, although that limit might change to something drastically lower |
|
|
151 | - you should be stingy with your pinger objects. |
|
|
152 | |
|
|
153 | =cut |
|
|
154 | |
|
|
155 | sub new { |
|
|
156 | my ($klass) = @_; |
|
|
157 | |
|
|
158 | _new $klass, (rand 65536), (rand 65536), (rand 65536) |
66 | } |
159 | } |
67 | |
160 | |
68 | =item AnyEvent::FastPing::ipv4_supported |
161 | our @IDLE_CB; |
69 | |
162 | |
70 | Returns true if IPv4 is supported in this module and on this system. |
163 | sub DESTROY { |
|
|
164 | undef $IDLE_CB[ &id ]; |
|
|
165 | &_free; |
|
|
166 | } |
71 | |
167 | |
72 | =item AnyEvent::FastPing::ipv6_supported |
168 | =item $pinger->on_recv ($callback->([[$host, $rtt], ...])) |
73 | |
169 | |
74 | Returns true if IPv6 is supported in this module and on this system. |
170 | Registers a callback to be called for ping replies. If no callback has |
|
|
171 | been registered than ping replies will be ignored, otherwise this module |
|
|
172 | calculates the round trip time, in seconds, for each reply and calls this |
|
|
173 | callback. |
75 | |
174 | |
76 | =item AnyEvent::FastPing::icmp4_pktsize |
175 | The callback receives a single argument, which is an array reference |
|
|
176 | with an entry for each reply packet (the replies will be batched for |
|
|
177 | efficiency). Each member in the array reference is again an array |
|
|
178 | reference with exactly two members: the binary host address (4 octets for |
|
|
179 | IPv4, 16 for IPv6) and the approximate round trip time, in seconds. |
77 | |
180 | |
78 | Returns the number of bytes each IPv4 ping packet has. |
181 | The replies will be passed to the callback as soon as they arrive, and |
|
|
182 | this callback can be called many times with batches of replies. |
79 | |
183 | |
80 | =item AnyEvent::FastPing::icmp6_pktsize |
184 | The receive callback will be called whenever a suitable reply arrives, |
|
|
185 | whether generated by this pinger or not, whether this pinger is started |
|
|
186 | or not. The packets will have a unique 64 bit ID to distinguish them from |
|
|
187 | other pinger objects and other generators, but this doesn't help against |
|
|
188 | malicious replies. |
81 | |
189 | |
82 | Returns the number of bytes each IPv4 ping packet has. |
190 | Note that very high packet rates can overwhelm your process, causing |
|
|
191 | replies to be dropped (configure your kernel with long receive queues for |
|
|
192 | raw sockets if this is a problem). |
83 | |
193 | |
84 | =item AnyEvent::FastPing::icmp_ping [ranges...], $send_interval, $payload, \&callback |
194 | Example: register a callback which simply dumps the received data. |
85 | |
195 | |
86 | Ping the given IPv4 address ranges. Each range is an arrayref of the |
196 | use AnyEvent::Socket; |
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 | |
197 | |
94 | The C<$send_interval> is the minimum interval between sending any two |
198 | $pinger->on_recv (sub { |
95 | packets and is a way to make an overall rate limit. If omitted, pings will |
199 | for (@{ $_[0] }) { |
96 | be sent as fast as possible. |
200 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
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. |
|
|
109 | |
|
|
110 | This will ensure that pings to the same range are nicely interleaved with |
|
|
111 | other ranges - this can help reduce per-subnet bandwidth while maintaining |
|
|
112 | an overall high packet rate. |
|
|
113 | |
|
|
114 | The algorithm to send each packet is O(log n) on the number of ranges, so |
|
|
115 | even a large number of ranges (many thousands) is managable. |
|
|
116 | |
|
|
117 | No storage is allocated per address. |
|
|
118 | |
|
|
119 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
|
|
120 | gigabit network card I can ping around 60k to 200k adresses per second, |
|
|
121 | depending on routing decisions. |
|
|
122 | |
|
|
123 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
|
|
124 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed |
|
|
125 | 1000 packets/s overall: |
|
|
126 | |
|
|
127 | my $done = AnyEvent->condvar; |
|
|
128 | |
|
|
129 | AnyEvent::FastPing::icmp_ping |
|
|
130 | [ |
|
|
131 | [v10.0.0.1, v10.0.0.15, .01], |
|
|
132 | [v11.0.0.1, v11.0.255.255, .001], |
|
|
133 | ], |
|
|
134 | .001, 0x12345678, |
|
|
135 | sub { |
|
|
136 | warn "all ranges pinged\n"; |
|
|
137 | $done->broadcast; |
|
|
138 | } |
201 | } |
139 | ; |
202 | }); |
140 | |
|
|
141 | $done->wait; |
|
|
142 | |
|
|
143 | =cut |
|
|
144 | |
|
|
145 | sub icmp_ping($$$&) { |
|
|
146 | _send_req _req_icmp_ping @_; |
|
|
147 | } |
|
|
148 | |
|
|
149 | our $ICMP4_FH; |
|
|
150 | our $ICMP4_W = (open $ICMP4_FH, "<&=$ICMP4_FD") && AnyEvent->io (fh => $ICMP4_FH, poll => 'r', cb => \&_recv_icmp4); |
|
|
151 | our $ICMP6_FH; |
|
|
152 | our $ICMP6_W = (open $ICMP6_FH, "<&=$ICMP6_FD") && AnyEvent->io (fh => $ICMP6_FH, poll => 'r', cb => \&_recv_icmp6); |
|
|
153 | |
|
|
154 | =item AnyEvent::FastPing::register_cb \&cb |
|
|
155 | |
|
|
156 | Register a callback that is called for every received ping reply |
|
|
157 | (regardless of whether a ping is still in process or not and regardless of |
|
|
158 | whether the reply is actually a reply to a ping sent earlier). |
|
|
159 | |
|
|
160 | The code reference gets a single parameter - an arrayref with an |
|
|
161 | entry for each received packet (replies are beign batched for greater |
|
|
162 | efficiency). Each packet is represented by an arrayref with three members: |
|
|
163 | the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets |
|
|
164 | length), the payload as passed to C<icmp_ping> and the round trip time in |
|
|
165 | seconds. |
|
|
166 | |
203 | |
167 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
204 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
168 | like this: |
205 | like this: |
169 | |
206 | |
170 | [ [ |
|
|
171 | "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", |
|
|
172 | "0.000280141830444336", |
|
|
173 | 1 |
|
|
174 | ] ] |
|
|
175 | |
|
|
176 | Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of |
|
|
177 | C<0x12345678>: |
|
|
178 | |
|
|
179 | [ |
207 | [ |
180 | [ |
208 | [ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 0.000280141830444336 ] |
181 | "\177\0\0\1", |
|
|
182 | "0.00015711784362793", |
|
|
183 | 305419896 |
|
|
184 | ], |
|
|
185 | [ |
|
|
186 | "\177\0\0\2", |
|
|
187 | "0.00090184211731", |
|
|
188 | 305419896 |
|
|
189 | ] |
|
|
190 | ] |
209 | ] |
191 | |
210 | |
192 | =item AnyEvent::FastPing::unregister_cb \&cb |
211 | Example: ping replies for C<127.0.0.1> and C<127.0.0.2>: |
193 | |
212 | |
194 | Unregister the callback again (make sure you pass the same codereference |
213 | [ |
195 | as to C<register_cb>). |
214 | [ "\177\0\0\1", 0.00015711784362793 ], |
|
|
215 | [ "\177\0\0\2", 0.00090184211731 ] |
|
|
216 | ] |
196 | |
217 | |
197 | =cut |
218 | =item $pinger->on_idle ($callback->()) |
198 | |
219 | |
199 | our @CB; |
220 | Registers a callback to be called when the pinger becomes I<idle>, that |
|
|
221 | is, it has been started, has exhausted all ping ranges and waited for |
|
|
222 | the C<max_rtt> time. An idle pinger is also stopped, so the callback can |
|
|
223 | instantly add new ranges, if it so desires. |
200 | |
224 | |
201 | sub register_cb(&) { |
225 | =cut |
202 | push @CB, $_[0]; |
226 | |
|
|
227 | sub on_idle { |
|
|
228 | $IDLE_CB[ &id ] = $_[1]; |
203 | } |
229 | } |
204 | |
230 | |
205 | sub unregister_cb($) { |
231 | our $THR_RES_W = AE::io $THR_RES_FH, 0, sub { |
206 | @CB = grep $_ != $_[0], @CB; |
232 | sysread $THR_RES_FH, my $buf, 8; |
207 | } |
233 | |
|
|
234 | for my $id (unpack "S*", $buf) { |
|
|
235 | _stop_id $id; |
|
|
236 | ($IDLE_CB[$id] || sub { })->(); |
|
|
237 | } |
|
|
238 | }; |
|
|
239 | |
|
|
240 | =item $pinger->interval ($seconds) |
|
|
241 | |
|
|
242 | Configures the minimum interval between packet sends for this pinger - the |
|
|
243 | pinger will not send packets faster than this rate (or actually 1 / rate), |
|
|
244 | even if individual ranges have a lower interval. |
|
|
245 | |
|
|
246 | A value of C<0> selects the fastest possible speed (currently no faster |
|
|
247 | than 1_000_000 packets/s). |
|
|
248 | |
|
|
249 | =item $pinger->max_rtt ($seconds) |
|
|
250 | |
|
|
251 | If your idle callback were called instantly after all ranges were |
|
|
252 | exhausted and you destroyed the object inside (which is common), then |
|
|
253 | there would be no chance to receive some replies, as there would be no |
|
|
254 | time of the packet to travel over the network. |
|
|
255 | |
|
|
256 | This can be fixed by starting a timer in the idle callback, or more simply |
|
|
257 | by selecting a suitable C<max_rtt> value, which should be the maximum time |
|
|
258 | you allow a ping packet to travel to its destination and back. |
|
|
259 | |
|
|
260 | The pinger thread automatically waits for this amount of time before becoming idle. |
|
|
261 | |
|
|
262 | The default is currently C<0.5> seconds, which is usually plenty. |
|
|
263 | |
|
|
264 | =item $pinger->add_range ($lo, $hi[, $interval]) |
|
|
265 | |
|
|
266 | Ping the IPv4 (or IPv6, but see below) address range, starting at binary |
|
|
267 | address C<$lo> and ending at C<$hi> (both C<$lo> and C<$hi> will be |
|
|
268 | pinged), generating no more than one ping per C<$interval> seconds (or as |
|
|
269 | fast as possible if omitted). |
|
|
270 | |
|
|
271 | You can convert IP addresses from text to binary form by |
|
|
272 | using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>, |
|
|
273 | C<Socket6::inet_pton> or any other method that you like :) |
|
|
274 | |
|
|
275 | The algorithm to select the next address is O(log n) on the number of |
|
|
276 | ranges, so even a large number of ranges (many thousands) is manageable. |
|
|
277 | |
|
|
278 | No storage is allocated per address. |
|
|
279 | |
|
|
280 | Note that, while IPv6 addresses are currently supported, the usefulness of |
|
|
281 | this option is extremely limited and might be gone in future versions - if |
|
|
282 | you want to ping a number of IPv6 hosts, better specify them individually |
|
|
283 | using the C<add_hosts> method. |
|
|
284 | |
|
|
285 | =item $pinger->add_hosts ([$host...], $interval, $interleave) |
|
|
286 | |
|
|
287 | Similar to C<add_range>, but uses a list of single addresses instead. The |
|
|
288 | list is specified as an array reference as first argument. Each entry in |
|
|
289 | the array should be a binary host address, either IPv4 or IPv6. If all |
|
|
290 | addresses are IPv4 addresses, then a compact IPv4-only format will be used |
|
|
291 | to store the list internally. |
|
|
292 | |
|
|
293 | Minimum C<$interval> is the same as for C<add_range> and can be left out. |
|
|
294 | |
|
|
295 | C<$interlave> specifies an increment between addresses: often address |
|
|
296 | lists are generated in a way that results in clustering - first all |
|
|
297 | addresses from one subnet, then from the next, and so on. To avoid this, |
|
|
298 | you can specify an interleave factor. If it is C<1> (the default), then |
|
|
299 | every address is pinged in the order specified. If it is C<2>, then only |
|
|
300 | every second address will be pinged in the first round, followed by a |
|
|
301 | second round with the others. Higher factors will create C<$interleave> |
|
|
302 | runs of addresses spaced C<$interleave> indices in the list. |
|
|
303 | |
|
|
304 | The special value C<0> selects a (hopefully) suitable interleave factor |
|
|
305 | automatically - currently C<256> for lists with less than 65536 addresses, |
|
|
306 | and the square root of the list length otherwise. |
|
|
307 | |
|
|
308 | =item $pinger->start |
|
|
309 | |
|
|
310 | Start the pinger, unless it is running already. While a pinger is running |
|
|
311 | you must not modify the pinger. If you want to change a parameter, you |
|
|
312 | have to C<stop> the pinger first. |
|
|
313 | |
|
|
314 | The pinger will automatically stop when destroyed. |
|
|
315 | |
|
|
316 | =item $pinger->stop |
|
|
317 | |
|
|
318 | Stop the pinger, if it is running. A pinger can be stopped at any time, |
|
|
319 | after which it's current state is preserved - starting it again will |
|
|
320 | continue where it left off. |
|
|
321 | |
|
|
322 | =cut |
208 | |
323 | |
209 | 1; |
324 | 1; |
210 | |
325 | |
211 | =back |
326 | =back |
212 | |
327 | |