Upgrade to Net::Ping 2.06.
[p5sagit/p5-mst-13.2.git] / lib / Net / Ping.pm
CommitLineData
a0d0e21e 1package Net::Ping;
2
3226bbec 3# $Id: Ping.pm,v 1.5 2001/11/19 09:44:18 rob Exp $
4
5require 5.002;
a0d0e21e 6require Exporter;
7
a3b93737 8use strict;
3226bbec 9use vars qw(@ISA @EXPORT $VERSION
10 $def_timeout $def_proto $max_datasize);
a3b93737 11use FileHandle;
12use Socket qw( SOCK_DGRAM SOCK_STREAM SOCK_RAW PF_INET
3226bbec 13 inet_aton sockaddr_in );
a3b93737 14use Carp;
a79c1648 15
a0d0e21e 16@ISA = qw(Exporter);
a3b93737 17@EXPORT = qw(pingecho);
3226bbec 18$VERSION = 2.06;
a0d0e21e 19
a3b93737 20# Constants
a0d0e21e 21
a3b93737 22$def_timeout = 5; # Default timeout to wait for a reply
23$def_proto = "udp"; # Default protocol to use for pinging
24$max_datasize = 1024; # Maximum data bytes in a packet
a0d0e21e 25
a3b93737 26# Description: The pingecho() subroutine is provided for backward
27# compatibility with the original Net::Ping. It accepts a host
28# name/IP and an optional timeout in seconds. Create a tcp ping
29# object and try pinging the host. The result of the ping is returned.
a0d0e21e 30
a3b93737 31sub pingecho
32{
33 my ($host, # Name or IP number of host to ping
34 $timeout # Optional timeout in seconds
35 ) = @_;
36 my ($p); # A ping object
a0d0e21e 37
a3b93737 38 $p = Net::Ping->new("tcp", $timeout);
39 $p->ping($host); # Going out of scope closes the connection
40}
a0d0e21e 41
a3b93737 42# Description: The new() method creates a new ping object. Optional
43# parameters may be specified for the protocol to use, the timeout in
44# seconds and the size in bytes of additional data which should be
45# included in the packet.
46# After the optional parameters are checked, the data is constructed
47# and a socket is opened if appropriate. The object is returned.
48
49sub new
50{
51 my ($this,
52 $proto, # Optional protocol to use for pinging
53 $timeout, # Optional timeout in seconds
54 $data_size # Optional additional bytes of data
55 ) = @_;
56 my $class = ref($this) || $this;
57 my $self = {};
58 my ($cnt, # Count through data bytes
59 $min_datasize # Minimum data bytes required
60 );
61
62 bless($self, $class);
63
64 $proto = $def_proto unless $proto; # Determine the protocol
3226bbec 65 croak("Protocol for ping must be \"tcp\", \"udp\" or \"icmp\"")
66 unless $proto =~ m/^(tcp|udp|icmp)$/;
a3b93737 67 $self->{"proto"} = $proto;
68
69 $timeout = $def_timeout unless $timeout; # Determine the timeout
70 croak("Default timeout for ping must be greater than 0 seconds")
71 if $timeout <= 0;
72 $self->{"timeout"} = $timeout;
73
74 $min_datasize = ($proto eq "udp") ? 1 : 0; # Determine data size
75 $data_size = $min_datasize unless defined($data_size) && $proto ne "tcp";
76 croak("Data for ping must be from $min_datasize to $max_datasize bytes")
77 if ($data_size < $min_datasize) || ($data_size > $max_datasize);
78 $data_size-- if $self->{"proto"} eq "udp"; # We provide the first byte
79 $self->{"data_size"} = $data_size;
80
81 $self->{"data"} = ""; # Construct data bytes
82 for ($cnt = 0; $cnt < $self->{"data_size"}; $cnt++)
83 {
84 $self->{"data"} .= chr($cnt % 256);
85 }
86
87 $self->{"seq"} = 0; # For counting packets
88 if ($self->{"proto"} eq "udp") # Open a socket
89 {
90 $self->{"proto_num"} = (getprotobyname('udp'))[2] ||
91 croak("Can't udp protocol by name");
92 $self->{"port_num"} = (getservbyname('echo', 'udp'))[2] ||
93 croak("Can't get udp echo port by name");
94 $self->{"fh"} = FileHandle->new();
95 socket($self->{"fh"}, &PF_INET(), &SOCK_DGRAM(),
96 $self->{"proto_num"}) ||
97 croak("udp socket error - $!");
98 }
99 elsif ($self->{"proto"} eq "icmp")
100 {
3226bbec 101 croak("icmp ping requires root privilege") if $>;
a3b93737 102 $self->{"proto_num"} = (getprotobyname('icmp'))[2] ||
103 croak("Can't get icmp protocol by name");
104 $self->{"pid"} = $$ & 0xffff; # Save lower 16 bits of pid
105 $self->{"fh"} = FileHandle->new();
106 socket($self->{"fh"}, &PF_INET(), &SOCK_RAW(), $self->{"proto_num"}) ||
107 croak("icmp socket error - $!");
108 }
3226bbec 109 elsif ($self->{"proto"} eq "tcp") # Just a file handle for now
a3b93737 110 {
111 $self->{"proto_num"} = (getprotobyname('tcp'))[2] ||
112 croak("Can't get tcp protocol by name");
113 $self->{"port_num"} = (getservbyname('echo', 'tcp'))[2] ||
114 croak("Can't get tcp echo port by name");
115 $self->{"fh"} = FileHandle->new();
116 }
117
118
119 return($self);
120}
a0d0e21e 121
a3b93737 122# Description: Ping a host name or IP number with an optional timeout.
123# First lookup the host, and return undef if it is not found. Otherwise
3226bbec 124# perform the specific ping method based on the protocol. Return the
a3b93737 125# result of the ping.
126
127sub ping
128{
129 my ($self,
130 $host, # Name or IP number of host to ping
131 $timeout # Seconds after which ping times out
132 ) = @_;
133 my ($ip, # Packed IP number of $host
134 $ret # The return value
135 );
136
137 croak("Usage: \$p->ping(\$host [, \$timeout])") unless @_ == 2 || @_ == 3;
138 $timeout = $self->{"timeout"} unless $timeout;
139 croak("Timeout must be greater than 0 seconds") if $timeout <= 0;
140
141 $ip = inet_aton($host);
142 return(undef) unless defined($ip); # Does host exist?
143
3226bbec 144 if ($self->{"proto"} eq "udp")
145 {
146 $ret = $self->ping_udp($ip, $timeout);
147 }
148 elsif ($self->{"proto"} eq "icmp")
149 {
150 $ret = $self->ping_icmp($ip, $timeout);
151 }
152 elsif ($self->{"proto"} eq "tcp")
153 {
154 $ret = $self->ping_tcp($ip, $timeout);
155 }
156 else
157 {
158 croak("Unknown protocol \"$self->{proto}\" in ping()");
159 }
160 return($ret);
a3b93737 161}
a0d0e21e 162
a3b93737 163sub ping_icmp
164{
165 my ($self,
166 $ip, # Packed IP number of the host
167 $timeout # Seconds after which ping times out
168 ) = @_;
169
170 my $ICMP_ECHOREPLY = 0; # ICMP packet types
171 my $ICMP_ECHO = 8;
172 my $icmp_struct = "C2 S3 A"; # Structure of a minimal ICMP packet
173 my $subcode = 0; # No ICMP subcode for ECHO and ECHOREPLY
174 my $flags = 0; # No special flags when opening a socket
175 my $port = 0; # No port with ICMP
176
177 my ($saddr, # sockaddr_in with port and ip
178 $checksum, # Checksum of ICMP packet
179 $msg, # ICMP packet to send
180 $len_msg, # Length of $msg
181 $rbits, # Read bits, filehandles for reading
182 $nfound, # Number of ready filehandles found
183 $finish_time, # Time ping should be finished
184 $done, # set to 1 when we are done
185 $ret, # Return value
186 $recv_msg, # Received message including IP header
187 $from_saddr, # sockaddr_in of sender
188 $from_port, # Port packet was sent from
189 $from_ip, # Packed IP of sender
190 $from_type, # ICMP type
191 $from_subcode, # ICMP subcode
192 $from_chk, # ICMP packet checksum
193 $from_pid, # ICMP packet id
194 $from_seq, # ICMP packet sequence
195 $from_msg # ICMP message
196 );
197
198 $self->{"seq"} = ($self->{"seq"} + 1) % 65536; # Increment sequence
199 $checksum = 0; # No checksum for starters
200 $msg = pack($icmp_struct . $self->{"data_size"}, $ICMP_ECHO, $subcode,
201 $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"});
202 $checksum = Net::Ping->checksum($msg);
203 $msg = pack($icmp_struct . $self->{"data_size"}, $ICMP_ECHO, $subcode,
204 $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"});
205 $len_msg = length($msg);
206 $saddr = sockaddr_in($port, $ip);
207 send($self->{"fh"}, $msg, $flags, $saddr); # Send the message
208
209 $rbits = "";
210 vec($rbits, $self->{"fh"}->fileno(), 1) = 1;
8e07c86e 211 $ret = 0;
a3b93737 212 $done = 0;
213 $finish_time = time() + $timeout; # Must be done by this time
214 while (!$done && $timeout > 0) # Keep trying if we have time
215 {
216 $nfound = select($rbits, undef, undef, $timeout); # Wait for packet
217 $timeout = $finish_time - time(); # Get remaining time
218 if (!defined($nfound)) # Hmm, a strange error
219 {
220 $ret = undef;
221 $done = 1;
222 }
223 elsif ($nfound) # Got a packet from somewhere
224 {
225 $recv_msg = "";
226 $from_saddr = recv($self->{"fh"}, $recv_msg, 1500, $flags);
227 ($from_port, $from_ip) = sockaddr_in($from_saddr);
228 ($from_type, $from_subcode, $from_chk,
229 $from_pid, $from_seq, $from_msg) =
230 unpack($icmp_struct . $self->{"data_size"},
231 substr($recv_msg, length($recv_msg) - $len_msg,
232 $len_msg));
233 if (($from_type == $ICMP_ECHOREPLY) &&
234 ($from_ip eq $ip) &&
235 ($from_pid == $self->{"pid"}) && # Does the packet check out?
236 ($from_seq == $self->{"seq"}))
237 {
238 $ret = 1; # It's a winner
239 $done = 1;
240 }
241 }
242 else # Oops, timed out
243 {
244 $done = 1;
245 }
246 }
247 return($ret)
248}
249
250# Description: Do a checksum on the message. Basically sum all of
251# the short words and fold the high order bits into the low order bits.
252
253sub checksum
254{
255 my ($class,
256 $msg # The message to checksum
257 ) = @_;
258 my ($len_msg, # Length of the message
259 $num_short, # The number of short words in the message
260 $short, # One short word
261 $chk # The checksum
262 );
263
264 $len_msg = length($msg);
3226bbec 265 $num_short = $len_msg / 2;
a3b93737 266 $chk = 0;
267 foreach $short (unpack("S$num_short", $msg))
268 {
269 $chk += $short;
270 } # Add the odd byte in
3226bbec 271 $chk += unpack("C", substr($msg, $len_msg - 1, 1)) if $len_msg % 2;
a3b93737 272 $chk = ($chk >> 16) + ($chk & 0xffff); # Fold high into low
273 return(~(($chk >> 16) + $chk) & 0xffff); # Again and complement
274}
275
072620d9 276# Description: Perform a tcp echo ping. Since a tcp connection is
277# host specific, we have to open and close each connection here. We
278# can't just leave a socket open. Because of the robust nature of
279# tcp, it will take a while before it gives up trying to establish a
3226bbec 280# connection. Therefore, we have to set the alarm to break out of the
281# connection sooner if the timeout expires. No data bytes are actually
072620d9 282# sent since the successful establishment of a connection is proof
283# enough of the reachability of the remote host. Also, tcp is
284# expensive and doesn't need our help to add to the overhead.
285
286sub ping_tcp
287{
288 my ($self,
289 $ip, # Packed IP number of the host
290 $timeout # Seconds after which ping times out
072620d9 291 ) = @_;
3226bbec 292 my ($saddr, # sockaddr_in with port and ip
293 $ret # The return value
294 );
072620d9 295
3226bbec 296 socket($self->{"fh"}, &PF_INET(), &SOCK_STREAM(), $self->{"proto_num"}) ||
297 croak("tcp socket error - $!");
298 $saddr = sockaddr_in($self->{"port_num"}, $ip);
072620d9 299
3226bbec 300 $SIG{'ALRM'} = sub { die };
301 alarm($timeout); # Interrupt connect() if we have to
072620d9 302
3226bbec 303 $ret = 0; # Default to unreachable
304 eval {
305 die $! unless connect($self->{"fh"}, $saddr);
306 $ret = 1;
307 };
308 alarm(0);
309 $ret = 1 if $@ =~ /connection refused/i;
310 $self->{"fh"}->close();
311 return($ret);
072620d9 312}
313
a3b93737 314# Description: Perform a udp echo ping. Construct a message of
315# at least the one-byte sequence number and any additional data bytes.
316# Send the message out and wait for a message to come back. If we
317# get a message, make sure all of its parts match. If they do, we are
318# done. Otherwise go back and wait for the message until we run out
319# of time. Return the result of our efforts.
320
321sub ping_udp
322{
323 my ($self,
324 $ip, # Packed IP number of the host
325 $timeout # Seconds after which ping times out
326 ) = @_;
327
328 my $flags = 0; # Nothing special on open
329
330 my ($saddr, # sockaddr_in with port and ip
331 $ret, # The return value
332 $msg, # Message to be echoed
333 $finish_time, # Time ping should be finished
334 $done, # Set to 1 when we are done pinging
335 $rbits, # Read bits, filehandles for reading
336 $nfound, # Number of ready filehandles found
337 $from_saddr, # sockaddr_in of sender
338 $from_msg, # Characters echoed by $host
339 $from_port, # Port message was echoed from
340 $from_ip # Packed IP number of sender
341 );
342
343 $saddr = sockaddr_in($self->{"port_num"}, $ip);
344 $self->{"seq"} = ($self->{"seq"} + 1) % 256; # Increment sequence
345 $msg = chr($self->{"seq"}) . $self->{"data"}; # Add data if any
346 send($self->{"fh"}, $msg, $flags, $saddr); # Send it
347
348 $rbits = "";
349 vec($rbits, $self->{"fh"}->fileno(), 1) = 1;
350 $ret = 0; # Default to unreachable
351 $done = 0;
352 $finish_time = time() + $timeout; # Ping needs to be done by then
353 while (!$done && $timeout > 0)
354 {
355 $nfound = select($rbits, undef, undef, $timeout); # Wait for response
356 $timeout = $finish_time - time(); # Get remaining time
357
358 if (!defined($nfound)) # Hmm, a strange error
359 {
360 $ret = undef;
361 $done = 1;
362 }
363 elsif ($nfound) # A packet is waiting
364 {
365 $from_msg = "";
3226bbec 366 $from_saddr = recv($self->{"fh"}, $from_msg, 1500, $flags);
367 ($from_port, $from_ip) = sockaddr_in($from_saddr);
368 if (($from_ip eq $ip) && # Does the packet check out?
369 ($from_port == $self->{"port_num"}) &&
370 ($from_msg eq $msg))
371 {
372 $ret = 1; # It's a winner
373 $done = 1;
374 }
375 }
a3b93737 376 else # Oops, timed out
377 {
378 $done = 1;
379 }
380 }
381 return($ret);
3226bbec 382}
a0d0e21e 383
a3b93737 384# Description: Close the connection unless we are using the tcp
385# protocol, since it will already be closed.
386
387sub close
388{
389 my ($self) = @_;
390
391 $self->{"fh"}->close() unless $self->{"proto"} eq "tcp";
392}
393
394
a0d0e21e 3951;
8e07c86e 396__END__
397
8e07c86e 398=head1 NAME
399
a3b93737 400Net::Ping - check a remote host for reachability
8e07c86e 401
3226bbec 402$Id: Ping.pm,v 1.5 2001/11/19 09:44:18 rob Exp $
403
8e07c86e 404=head1 SYNOPSIS
405
406 use Net::Ping;
8e07c86e 407
a3b93737 408 $p = Net::Ping->new();
409 print "$host is alive.\n" if $p->ping($host);
410 $p->close();
411
412 $p = Net::Ping->new("icmp");
413 foreach $host (@host_array)
414 {
415 print "$host is ";
416 print "NOT " unless $p->ping($host, 2);
417 print "reachable.\n";
418 sleep(1);
419 }
420 $p->close();
3226bbec 421
a3b93737 422 $p = Net::Ping->new("tcp", 2);
3226bbec 423 # Try connecting to the www port instead of the echo port
424 $p->{port_num} = getservbyname("http", "tcp");
a3b93737 425 while ($stop_time > time())
426 {
427 print "$host not reachable ", scalar(localtime()), "\n"
428 unless $p->ping($host);
429 sleep(300);
430 }
431 undef($p);
3226bbec 432
a3b93737 433 # For backward compatibility
434 print "$host is alive.\n" if pingecho($host);
8e07c86e 435
a3b93737 436=head1 DESCRIPTION
8e07c86e 437
a3b93737 438This module contains methods to test the reachability of remote
439hosts on a network. A ping object is first created with optional
440parameters, a variable number of hosts may be pinged multiple
441times and then the connection is closed.
442
3226bbec 443You may choose one of three different protocols to use for the ping.
444With the "tcp" protocol the ping() method attempts to establish a
445connection to the remote host's echo port. If the connection is
446successfully established, the remote host is considered reachable. No
447data is actually echoed. This protocol does not require any special
448privileges but has higher overhead than the other two protocols.
072620d9 449
3226bbec 450Specifying the "udp" protocol causes the ping() method to send a udp
a3b93737 451packet to the remote host's echo port. If the echoed packet is
452received from the remote host and the received packet contains the
453same data as the packet that was sent, the remote host is considered
454reachable. This protocol does not require any special privileges.
455
3226bbec 456If the "icmp" protocol is specified, the ping() method sends an icmp
457echo message to the remote host, which is what the UNIX ping program
458does. If the echoed message is received from the remote host and
459the echoed information is correct, the remote host is considered
460reachable. Specifying the "icmp" protocol requires that the program
461be run as root or that the program be setuid to root.
edc5bd88 462
a3b93737 463=head2 Functions
464
465=over 4
466
467=item Net::Ping->new([$proto [, $def_timeout [, $bytes]]]);
468
469Create a new ping object. All of the parameters are optional. $proto
470specifies the protocol to use when doing a ping. The current choices
471are "tcp", "udp" or "icmp". The default is "udp".
472
473If a default timeout ($def_timeout) in seconds is provided, it is used
474when a timeout is not given to the ping() method (below). The timeout
475must be greater than 0 and the default, if not specified, is 5 seconds.
476
477If the number of data bytes ($bytes) is given, that many data bytes
478are included in the ping packet sent to the remote host. The number of
479data bytes is ignored if the protocol is "tcp". The minimum (and
480default) number of data bytes is 1 if the protocol is "udp" and 0
481otherwise. The maximum number of data bytes that can be specified is
4821024.
483
484=item $p->ping($host [, $timeout]);
485
486Ping the remote host and wait for a response. $host can be either the
487hostname or the IP number of the remote host. The optional timeout
488must be greater than 0 seconds and defaults to whatever was specified
489when the ping object was created. If the hostname cannot be found or
490there is a problem with the IP number, undef is returned. Otherwise,
4911 is returned if the host is reachable and 0 if it is not. For all
492practical purposes, undef and 0 and can be treated as the same case.
493
494=item $p->close();
495
496Close the network connection for this ping object. The network
497connection is also closed by "undef $p". The network connection is
498automatically closed if the ping object goes out of scope (e.g. $p is
499local to a subroutine and you leave the subroutine).
500
501=item pingecho($host [, $timeout]);
502
503To provide backward compatibility with the previous version of
504Net::Ping, a pingecho() subroutine is available with the same
505functionality as before. pingecho() uses the tcp protocol. The
506return values and parameters are the same as described for the ping()
507method. This subroutine is obsolete and may be removed in a future
508version of Net::Ping.
8e07c86e 509
a3b93737 510=back
8e07c86e 511
3226bbec 512=head1 WARNING
513
514pingecho() or a ping object with the tcp protocol use alarm() to
515implement the timeout. So, don't use alarm() in your program while
516you are using pingecho() or a ping object with the tcp protocol. The
517udp and icmp protocols do not use alarm() to implement the timeout.
518
a3b93737 519=head1 NOTES
8e07c86e 520
a3b93737 521There will be less network overhead (and some efficiency in your
522program) if you specify either the udp or the icmp protocol. The tcp
523protocol will generate 2.5 times or more traffic for each ping than
524either udp or icmp. If many hosts are pinged frequently, you may wish
525to implement a small wait (e.g. 25ms or more) between each ping to
526avoid flooding your network with packets.
8e07c86e 527
a3b93737 528The icmp protocol requires that the program be run as root or that it
3226bbec 529be setuid to root. The tcp and udp protocols do not require special
530privileges, but not all network devices implement the echo protocol
531for tcp or udp.
8e07c86e 532
a3b93737 533Local hosts should normally respond to pings within milliseconds.
534However, on a very congested network it may take up to 3 seconds or
535longer to receive an echo packet from the remote host. If the timeout
536is set too low under these conditions, it will appear that the remote
537host is not reachable (which is almost the truth).
8e07c86e 538
a3b93737 539Reachability doesn't necessarily mean that the remote host is actually
3226bbec 540functioning beyond its ability to echo packets.
8e07c86e 541
a3b93737 542Because of a lack of anything better, this module uses its own
543routines to pack and unpack ICMP packets. It would be better for a
544separate module to be written which understands all of the different
545kinds of ICMP packets.
8e07c86e 546
3226bbec 547=head1 AUTHOR(S)
548
549 Original pingecho():
550 Andreas Karrer (karrer@bernina.ethz.ch)
551 Paul Marquess (pmarquess@bfsec.bt.co.uk)
552
553 Net::Ping base code:
554 Russell Mosemann (mose@ns.ccsn.edu)
555
556 Compatibility porting so ping_tcp()
557 can work with most remote systems:
558 Rob Brown (rob@roobik.com)
559
560=head1 COPYRIGHT
561
562Copyright (c) 2001 Rob Brown. All rights reserved.
563
564Copyright (c) 1996 Russell Mosemann. All rights reserved.
565
566This program is free software; you may redistribute it and/or
567modify it under the same terms as Perl itself.
568
a3b93737 569=cut