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