ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.pm
(Generate patch)

Comparing AnyEvent-FastPing/FastPing.pm (file contents):
Revision 1.18 by root, Fri Nov 11 01:18:56 2016 UTC vs.
Revision 1.19 by root, Sat Nov 12 01:20:46 2016 UTC

27use common::sense; 27use common::sense;
28 28
29use AnyEvent; 29use AnyEvent;
30 30
31BEGIN { 31BEGIN {
32 our $VERSION = 2.03; 32 our $VERSION = 2.1;
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
39 XSLoader::load (__PACKAGE__, $VERSION); 39 XSLoader::load (__PACKAGE__, $VERSION);
40} 40}
41 41
42our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD); 42our ($THR_RES_FD, $ICMP4_FD, $ICMP6_FD);
43 43
44our $THR_RES_FH; open $THR_RES_FH, "<&=$THR_RES_FD" or die "FATAL: cannot fdopen"; 44our $THR_RES_FH;
45 45
46our $ICMP4_FH; 46our $ICMP4_FH;
47our $ICMP6_FH; 47our $ICMP6_FH;
48 48
49our @IDLE_CB; 49our @IDLE_CB;
50 50
51AnyEvent::post_detect { 51=item AnyEvent::FastPing::ipv4_supported
52
53Returns true iff IPv4 is supported in this module and on this system.
54
55=item AnyEvent::FastPing::ipv6_supported
56
57Returns true iff IPv6 is supported in this module and on this system.
58
59=item AnyEvent::FastPing::icmp4_pktsize
60
61Returns the number of octets per IPv4 ping packet (the whole IP packet
62including headers, excluding lower-level headers or trailers such as
63Ethernet).
64
65Can 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
74etc.
75
76=item AnyEvent::FastPing::icmp6_pktsize
77
78Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.
79
80=back
81
82=head1 THE AnyEvent::FastPing CLASS
83
84The AnyEvent::FastPing class represents a single "pinger". A "pinger"
85comes with its own thread to send packets in the background, a rate-limit
86machinery and separate idle/receive callbacks.
87
88The recommended workflow (there are others) is this: 1. create a new
89AnyEvent::FastPing object 2. configure the address lists and ranges to
90ping, also configure an idle callback and optionally a receive callback
913. C<start> the pinger.
92
93When the pinger has finished pinging all the configured addresses it will
94call the idle callback.
95
96The pinging process works like this: every range has a minimum interval
97between sends, which is used to limit the rate at which hosts in that
98range are being pinged. Distinct ranges are independent of each other,
99which is why there is a per-pinger "global" minimum interval as well.
100
101The pinger sends pings as fats as possible, while both obeying the pinger
102rate limit as well as range limits.
103
104When a range is exhausted, it is removed. When all ranges are exhausted,
105the pinger waits another C<max_rtt> seconds and then exits, causing the
106idle callback to trigger.
107
108Performance: On my 2 GHz Opteron system with a pretty average nvidia
109gigabit network card I can ping around 60k to 200k addresses per second,
110depending on routing decisions.
111
112Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
11311.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6
114loopback address 5 times as fast as possible. Do not, however, exceed 1000
115packets/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
151Creates a new pinger - right now there can be at most C<65536> pingers in
152a process, although that limit might change to something drastically lower
153- you should be stingy with your pinger objects.
154
155=cut
156
157sub new {
158 _boot;
159
52 our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; 160 our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4;
53 our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; 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";
54 164
55 our $THR_RES_W = AE::io $THR_RES_FH, 0, sub { 165 our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
56 sysread $THR_RES_FH, my $buf, 8; 166 sysread $THR_RES_FH, my $buf, 8;
57 167
58 for my $id (unpack "S*", $buf) { 168 for my $id (unpack "S*", $buf) {
59 _stop_id $id; 169 _stop_id $id;
60 ($IDLE_CB[$id] || sub { })->(); 170 ($IDLE_CB[$id] || sub { })->();
61 } 171 }
62 }; 172 };
63};
64 173
65=item AnyEvent::FastPing::ipv4_supported 174 *new = sub {
66 175 _new shift, (rand 65536), (rand 65536), (rand 65536)
67Returns true iff IPv4 is supported in this module and on this system.
68
69=item AnyEvent::FastPing::ipv6_supported
70
71Returns true iff IPv6 is supported in this module and on this system.
72
73=item AnyEvent::FastPing::icmp4_pktsize
74
75Returns the number of octets per IPv4 ping packet (the whole IP packet
76including headers, excluding lower-level headers or trailers such as
77Ethernet).
78
79Can be used to calculate e.g. octets/s from rate ...
80
81 my $octets_per_second = $packets_per_second * AnyEvent::FastPing::icmp4_pktsize;
82
83... or convert kilobit/second to packet rate ...
84
85 my $packets_per_second = $kilobit_per_second
86 * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize);
87
88etc.
89
90=item AnyEvent::FastPing::icmp6_pktsize
91
92Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.
93
94=back
95
96=head1 THE AnyEvent::FastPing CLASS
97
98The AnyEvent::FastPing class represents a single "pinger". A "pinger"
99comes with its own thread to send packets in the background, a rate-limit
100machinery and separate idle/receive callbacks.
101
102The recommended workflow (there are others) is this: 1. create a new
103AnyEvent::FastPing object 2. configure the address lists and ranges to
104ping, also configure an idle callback and optionally a receive callback
1053. C<start> the pinger.
106
107When the pinger has finished pinging all the configured addresses it will
108call the idle callback.
109
110The pinging process works like this: every range has a minimum interval
111between sends, which is used to limit the rate at which hosts in that
112range are being pinged. Distinct ranges are independent of each other,
113which is why there is a per-pinger "global" minimum interval as well.
114
115The pinger sends pings as fats as possible, while both obeying the pinger
116rate limit as well as range limits.
117
118When a range is exhausted, it is removed. When all ranges are exhausted,
119the pinger waits another C<max_rtt> seconds and then exits, causing the
120idle callback to trigger.
121
122Performance: On my 2 GHz Opteron system with a pretty average nvidia
123gigabit network card I can ping around 60k to 200k addresses per second,
124depending on routing decisions.
125
126Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and
12711.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6
128loopback address 5 times as fast as possible. Do not, however, exceed 1000
129packets/s overall. Also dump each received reply.
130
131 use AnyEvent::Socket;
132 use AnyEvent::FastPing;
133
134 my $done = AnyEvent->condvar;
135
136 my $pinger = new AnyEvent::FastPing;
137
138 $pinger->interval (1/1000);
139 $pinger->max_rtt (0.1); # reasonably fast/reliable network
140
141 $pinger->add_range (v10.0.0.1, v10.0.0.15, 1/100);
142 $pinger->add_range (v11.0.0.1, v11.0.255.255, 1/1000);
143 $pinger->add_hosts ([ (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1) x 5 ]);
144
145 $pinger->on_recv (sub {
146 for (@{ $_[0] }) {
147 printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1];
148 }
149 }); 176 };
150 177
151 $pinger->on_idle (sub { 178 goto &new;
152 print "done\n";
153 undef $pinger;
154 });
155
156 $pinger->start;
157 $done->wait;
158
159=head2 METHODS
160
161=over 4
162
163=item $pinger = new AnyEvent::FastPing
164
165Creates a new pinger - right now there can be at most C<65536> pingers in
166a process, although that limit might change to something drastically lower
167- you should be stingy with your pinger objects.
168
169=cut
170
171sub new {
172 my ($klass) = @_;
173
174 AnyEvent::detect unless defined $AnyEvent::MODEL;
175
176 _new $klass, (rand 65536), (rand 65536), (rand 65536)
177} 179}
178 180
179sub DESTROY { 181sub DESTROY {
180 undef $IDLE_CB[ &id ]; 182 undef $IDLE_CB[ &id ];
181 &_free; 183 &_free;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines