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