This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
change#16723 broke the ioctl() return value on platforms
[perl5.git] / lib / Net / Ping.pm
CommitLineData
a0d0e21e
LW
1package Net::Ping;
2
b124990b 3require 5.002;
a0d0e21e
LW
4require Exporter;
5
a3b93737 6use strict;
b124990b 7use vars qw(@ISA @EXPORT $VERSION
9539e94f
JH
8 $def_timeout $def_proto $def_factor
9 $max_datasize $pingstring $hires $source_verify $syn_forking);
f569508e
HS
10use Fcntl qw( F_GETFL F_SETFL O_NONBLOCK );
11use Socket qw( SOCK_DGRAM SOCK_STREAM SOCK_RAW PF_INET SOL_SOCKET
e82f584b 12 inet_aton inet_ntoa sockaddr_in );
9539e94f 13use POSIX qw( ECONNREFUSED ECONNRESET EINPROGRESS EAGAIN WNOHANG );
f569508e 14use FileHandle;
a3b93737 15use Carp;
a79c1648 16
a0d0e21e 17@ISA = qw(Exporter);
a3b93737 18@EXPORT = qw(pingecho);
9539e94f 19$VERSION = "2.30";
a0d0e21e 20
a3b93737 21# Constants
a0d0e21e 22
a3b93737 23$def_timeout = 5; # Default timeout to wait for a reply
a5a165b1 24$def_proto = "tcp"; # Default protocol to use for pinging
9539e94f 25$def_factor = 1.2; # Default exponential backoff rate.
a3b93737 26$max_datasize = 1024; # Maximum data bytes in a packet
b124990b
JH
27# The data we exchange with the server for the stream protocol
28$pingstring = "pingschwingping!\n";
5d20095f 29$source_verify = 1; # Default is to verify source endpoint
f569508e 30$syn_forking = 0;
a0d0e21e 31
ef73e1db
JH
32if ($^O =~ /Win32/i) {
33 # Hack to avoid this Win32 spewage:
34 # Your vendor has not defined POSIX macro ECONNREFUSED
35 *ECONNREFUSED = sub {10061;}; # "Unknown Error" Special Win32 Response?
f569508e 36 $syn_forking = 1;
ef73e1db
JH
37};
38
f569508e
HS
39# h2ph "asm/socket.h"
40# require "asm/socket.ph";
41sub SO_BINDTODEVICE {25;}
42
a3b93737
RM
43# Description: The pingecho() subroutine is provided for backward
44# compatibility with the original Net::Ping. It accepts a host
45# name/IP and an optional timeout in seconds. Create a tcp ping
46# object and try pinging the host. The result of the ping is returned.
a0d0e21e 47
a3b93737
RM
48sub pingecho
49{
e82f584b
JH
50 my ($host, # Name or IP number of host to ping
51 $timeout # Optional timeout in seconds
52 ) = @_;
53 my ($p); # A ping object
a0d0e21e 54
e82f584b
JH
55 $p = Net::Ping->new("tcp", $timeout);
56 $p->ping($host); # Going out of scope closes the connection
a3b93737 57}
a0d0e21e 58
a3b93737
RM
59# Description: The new() method creates a new ping object. Optional
60# parameters may be specified for the protocol to use, the timeout in
61# seconds and the size in bytes of additional data which should be
62# included in the packet.
63# After the optional parameters are checked, the data is constructed
64# and a socket is opened if appropriate. The object is returned.
65
66sub new
67{
e82f584b
JH
68 my ($this,
69 $proto, # Optional protocol to use for pinging
70 $timeout, # Optional timeout in seconds
f569508e
HS
71 $data_size, # Optional additional bytes of data
72 $device, # Optional device to use
e82f584b
JH
73 ) = @_;
74 my $class = ref($this) || $this;
75 my $self = {};
76 my ($cnt, # Count through data bytes
77 $min_datasize # Minimum data bytes required
78 );
79
80 bless($self, $class);
81
82 $proto = $def_proto unless $proto; # Determine the protocol
f569508e
HS
83 croak('Protocol for ping must be "icmp", "udp", "tcp", "syn", "stream", or "external"')
84 unless $proto =~ m/^(icmp|udp|tcp|syn|stream|external)$/;
e82f584b
JH
85 $self->{"proto"} = $proto;
86
87 $timeout = $def_timeout unless $timeout; # Determine the timeout
88 croak("Default timeout for ping must be greater than 0 seconds")
89 if $timeout <= 0;
90 $self->{"timeout"} = $timeout;
91
f569508e
HS
92 $self->{"device"} = $device;
93
e82f584b
JH
94 $min_datasize = ($proto eq "udp") ? 1 : 0; # Determine data size
95 $data_size = $min_datasize unless defined($data_size) && $proto ne "tcp";
96 croak("Data for ping must be from $min_datasize to $max_datasize bytes")
97 if ($data_size < $min_datasize) || ($data_size > $max_datasize);
98 $data_size-- if $self->{"proto"} eq "udp"; # We provide the first byte
99 $self->{"data_size"} = $data_size;
100
101 $self->{"data"} = ""; # Construct data bytes
102 for ($cnt = 0; $cnt < $self->{"data_size"}; $cnt++)
103 {
104 $self->{"data"} .= chr($cnt % 256);
105 }
106
107 $self->{"local_addr"} = undef; # Don't bind by default
9539e94f 108 $self->{"retrans"} = $def_factor; # Default exponential backoff rate
c94ff782 109 $self->{"econnrefused"} = undef; # Default Connection refused behavior
f569508e 110
e82f584b
JH
111 $self->{"seq"} = 0; # For counting packets
112 if ($self->{"proto"} eq "udp") # Open a socket
113 {
114 $self->{"proto_num"} = (getprotobyname('udp'))[2] ||
115 croak("Can't udp protocol by name");
116 $self->{"port_num"} = (getservbyname('echo', 'udp'))[2] ||
117 croak("Can't get udp echo port by name");
118 $self->{"fh"} = FileHandle->new();
119 socket($self->{"fh"}, PF_INET, SOCK_DGRAM,
120 $self->{"proto_num"}) ||
121 croak("udp socket error - $!");
f569508e
HS
122 if ($self->{'device'}) {
123 setsockopt($self->{"fh"}, SOL_SOCKET, SO_BINDTODEVICE(), pack("Z*", $self->{'device'}))
124 or croak "error binding to device $self->{'device'} $!";
125 }
e82f584b
JH
126 }
127 elsif ($self->{"proto"} eq "icmp")
128 {
f569508e 129 croak("icmp ping requires root privilege") if ($> and $^O ne 'VMS' and $^O ne 'cygwin');
e82f584b
JH
130 $self->{"proto_num"} = (getprotobyname('icmp'))[2] ||
131 croak("Can't get icmp protocol by name");
132 $self->{"pid"} = $$ & 0xffff; # Save lower 16 bits of pid
133 $self->{"fh"} = FileHandle->new();
134 socket($self->{"fh"}, PF_INET, SOCK_RAW, $self->{"proto_num"}) ||
135 croak("icmp socket error - $!");
f569508e
HS
136 if ($self->{'device'}) {
137 setsockopt($self->{"fh"}, SOL_SOCKET, SO_BINDTODEVICE(), pack("Z*", $self->{'device'}))
138 or croak "error binding to device $self->{'device'} $!";
139 }
e82f584b
JH
140 }
141 elsif ($self->{"proto"} eq "tcp" || $self->{"proto"} eq "stream")
142 {
143 $self->{"proto_num"} = (getprotobyname('tcp'))[2] ||
144 croak("Can't get tcp protocol by name");
145 $self->{"port_num"} = (getservbyname('echo', 'tcp'))[2] ||
146 croak("Can't get tcp echo port by name");
147 $self->{"fh"} = FileHandle->new();
148 }
f569508e
HS
149 elsif ($self->{"proto"} eq "syn")
150 {
151 $self->{"proto_num"} = (getprotobyname('tcp'))[2] ||
152 croak("Can't get tcp protocol by name");
153 $self->{"port_num"} = (getservbyname('echo', 'tcp'))[2] ||
154 croak("Can't get tcp echo port by name");
155 if ($syn_forking) {
156 $self->{"fork_rd"} = FileHandle->new();
157 $self->{"fork_wr"} = FileHandle->new();
158 pipe($self->{"fork_rd"}, $self->{"fork_wr"});
159 $self->{"fh"} = FileHandle->new();
69c74a9c
HS
160 $self->{"good"} = {};
161 $self->{"bad"} = {};
f569508e
HS
162 } else {
163 $self->{"wbits"} = "";
164 $self->{"bad"} = {};
165 }
166 $self->{"syn"} = {};
167 $self->{"stop_time"} = 0;
168 }
169 elsif ($self->{"proto"} eq "external")
170 {
171 # No preliminary work needs to be done.
172 }
e82f584b
JH
173
174 return($self);
a3b93737 175}
a0d0e21e 176
49afa5f6
JH
177# Description: Set the local IP address from which pings will be sent.
178# For ICMP and UDP pings, this calls bind() on the already-opened socket;
179# for TCP pings, just saves the address to be used when the socket is
180# opened. Returns non-zero if successful; croaks on error.
181sub bind
182{
e82f584b
JH
183 my ($self,
184 $local_addr # Name or IP number of local interface
185 ) = @_;
186 my ($ip # Packed IP number of $local_addr
187 );
188
189 croak("Usage: \$p->bind(\$local_addr)") unless @_ == 2;
190 croak("already bound") if defined($self->{"local_addr"}) &&
191 ($self->{"proto"} eq "udp" || $self->{"proto"} eq "icmp");
192
193 $ip = inet_aton($local_addr);
194 croak("nonexistent local address $local_addr") unless defined($ip);
195 $self->{"local_addr"} = $ip; # Only used if proto is tcp
196
197 if ($self->{"proto"} eq "udp" || $self->{"proto"} eq "icmp")
198 {
199 CORE::bind($self->{"fh"}, sockaddr_in(0, $ip)) ||
200 croak("$self->{'proto'} bind error - $!");
201 }
202 elsif ($self->{"proto"} ne "tcp")
203 {
204 croak("Unknown protocol \"$self->{proto}\" in bind()");
205 }
206
207 return 1;
208}
49afa5f6 209
49afa5f6 210
15d96390
JH
211# Description: Allow UDP source endpoint comparision to be
212# skipped for those remote interfaces that do
213# not response from the same endpoint.
214
215sub source_verify
216{
217 my $self = shift;
5d20095f
JH
218 $source_verify = 1 unless defined
219 ($source_verify = ((defined $self) && (ref $self)) ? shift() : $self);
15d96390
JH
220}
221
c94ff782
JH
222# Description: Set whether or not the connect
223# behavior should enforce remote service
224# availability as well as reachability.
f569508e 225
c94ff782 226sub service_check
f569508e
HS
227{
228 my $self = shift;
c94ff782
JH
229 $self->{"econnrefused"} = 1 unless defined
230 ($self->{"econnrefused"} = shift());
231}
232
233sub tcp_service_check
234{
235 service_check(@_);
f569508e
HS
236}
237
9539e94f
JH
238# Description: Set exponential backoff for retransmission.
239# Should be > 1 to retain exponential properties.
240# If set to 0, retransmissions are disabled.
241
242sub retrans
243{
244 my $self = shift;
245 $self->{"retrans"} = shift;
246}
247
e82f584b
JH
248# Description: allows the module to use milliseconds as returned by
249# the Time::HiRes module
49afa5f6 250
e82f584b
JH
251$hires = 0;
252sub hires
253{
254 my $self = shift;
255 $hires = 1 unless defined
256 ($hires = ((defined $self) && (ref $self)) ? shift() : $self);
257 require Time::HiRes if $hires;
49afa5f6
JH
258}
259
e82f584b
JH
260sub time
261{
262 return $hires ? Time::HiRes::time() : CORE::time();
263}
49afa5f6 264
9c36735d
JH
265# Description: Sets or clears the O_NONBLOCK flag on a file handle.
266sub socket_blocking_mode
267{
268 my ($self,
269 $fh, # the file handle whose flags are to be modified
270 $block) = @_; # if true then set the blocking
271 # mode (clear O_NONBLOCK), otherwise
272 # set the non-blocking mode (set O_NONBLOCK)
273
274 my $flags;
275 if ($flags = fcntl($fh, F_GETFL, 0)) {
276 $flags = $block ? ($flags & ~O_NONBLOCK) : ($flags | O_NONBLOCK);
277 if (!fcntl($fh, F_SETFL, $flags)) {
278 croak("fcntl F_SETFL: $!");
279 }
280 } else {
281 croak("fcntl F_GETFL: $!");
282 }
283}
284
a3b93737
RM
285# Description: Ping a host name or IP number with an optional timeout.
286# First lookup the host, and return undef if it is not found. Otherwise
b124990b 287# perform the specific ping method based on the protocol. Return the
a3b93737
RM
288# result of the ping.
289
290sub ping
291{
e82f584b
JH
292 my ($self,
293 $host, # Name or IP number of host to ping
294 $timeout, # Seconds after which ping times out
295 ) = @_;
296 my ($ip, # Packed IP number of $host
297 $ret, # The return value
298 $ping_time, # When ping began
299 );
300
301 croak("Usage: \$p->ping(\$host [, \$timeout])") unless @_ == 2 || @_ == 3;
302 $timeout = $self->{"timeout"} unless $timeout;
303 croak("Timeout must be greater than 0 seconds") if $timeout <= 0;
304
305 $ip = inet_aton($host);
c94ff782 306 return () unless defined($ip); # Does host exist?
e82f584b
JH
307
308 # Dispatch to the appropriate routine.
309 $ping_time = &time();
310 if ($self->{"proto"} eq "external") {
311 $ret = $self->ping_external($ip, $timeout);
312 }
313 elsif ($self->{"proto"} eq "udp") {
314 $ret = $self->ping_udp($ip, $timeout);
315 }
316 elsif ($self->{"proto"} eq "icmp") {
317 $ret = $self->ping_icmp($ip, $timeout);
318 }
319 elsif ($self->{"proto"} eq "tcp") {
320 $ret = $self->ping_tcp($ip, $timeout);
321 }
322 elsif ($self->{"proto"} eq "stream") {
323 $ret = $self->ping_stream($ip, $timeout);
f569508e
HS
324 }
325 elsif ($self->{"proto"} eq "syn") {
326 $ret = $self->ping_syn($host, $ip, $ping_time, $ping_time+$timeout);
e82f584b 327 } else {
787ecdfa 328 croak("Unknown protocol \"$self->{proto}\" in ping()");
e82f584b
JH
329 }
330
331 return wantarray ? ($ret, &time() - $ping_time, inet_ntoa($ip)) : $ret;
787ecdfa
JH
332}
333
334# Uses Net::Ping::External to do an external ping.
335sub ping_external {
336 my ($self,
337 $ip, # Packed IP number of the host
338 $timeout # Seconds after which ping times out
339 ) = @_;
340
b124990b
JH
341 eval { require Net::Ping::External; }
342 or croak('Protocol "external" not supported on your system: Net::Ping::External not found');
787ecdfa 343 return Net::Ping::External::ping(ip => $ip, timeout => $timeout);
a3b93737 344}
a0d0e21e 345
49afa5f6
JH
346use constant ICMP_ECHOREPLY => 0; # ICMP packet types
347use constant ICMP_ECHO => 8;
9c36735d 348use constant ICMP_STRUCT => "C2 n3 A"; # Structure of a minimal ICMP packet
49afa5f6
JH
349use constant SUBCODE => 0; # No ICMP subcode for ECHO and ECHOREPLY
350use constant ICMP_FLAGS => 0; # No special flags for send or recv
351use constant ICMP_PORT => 0; # No port with ICMP
352
a3b93737
RM
353sub ping_icmp
354{
e82f584b
JH
355 my ($self,
356 $ip, # Packed IP number of the host
357 $timeout # Seconds after which ping times out
358 ) = @_;
359
360 my ($saddr, # sockaddr_in with port and ip
361 $checksum, # Checksum of ICMP packet
362 $msg, # ICMP packet to send
363 $len_msg, # Length of $msg
364 $rbits, # Read bits, filehandles for reading
365 $nfound, # Number of ready filehandles found
366 $finish_time, # Time ping should be finished
367 $done, # set to 1 when we are done
368 $ret, # Return value
369 $recv_msg, # Received message including IP header
370 $from_saddr, # sockaddr_in of sender
371 $from_port, # Port packet was sent from
372 $from_ip, # Packed IP of sender
373 $from_type, # ICMP type
374 $from_subcode, # ICMP subcode
375 $from_chk, # ICMP packet checksum
376 $from_pid, # ICMP packet id
377 $from_seq, # ICMP packet sequence
378 $from_msg # ICMP message
379 );
380
381 $self->{"seq"} = ($self->{"seq"} + 1) % 65536; # Increment sequence
382 $checksum = 0; # No checksum for starters
383 $msg = pack(ICMP_STRUCT . $self->{"data_size"}, ICMP_ECHO, SUBCODE,
384 $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"});
385 $checksum = Net::Ping->checksum($msg);
386 $msg = pack(ICMP_STRUCT . $self->{"data_size"}, ICMP_ECHO, SUBCODE,
387 $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"});
388 $len_msg = length($msg);
389 $saddr = sockaddr_in(ICMP_PORT, $ip);
9c36735d
JH
390 $self->{"from_ip"} = undef;
391 $self->{"from_type"} = undef;
392 $self->{"from_subcode"} = undef;
e82f584b
JH
393 send($self->{"fh"}, $msg, ICMP_FLAGS, $saddr); # Send the message
394
395 $rbits = "";
396 vec($rbits, $self->{"fh"}->fileno(), 1) = 1;
397 $ret = 0;
398 $done = 0;
399 $finish_time = &time() + $timeout; # Must be done by this time
400 while (!$done && $timeout > 0) # Keep trying if we have time
401 {
9539e94f 402 $nfound = select((my $rout=$rbits), undef, undef, $timeout); # Wait for packet
e82f584b
JH
403 $timeout = $finish_time - &time(); # Get remaining time
404 if (!defined($nfound)) # Hmm, a strange error
a3b93737 405 {
e82f584b
JH
406 $ret = undef;
407 $done = 1;
408 }
409 elsif ($nfound) # Got a packet from somewhere
410 {
411 $recv_msg = "";
9539e94f
JH
412 $from_pid = -1;
413 $from_seq = -1;
e82f584b
JH
414 $from_saddr = recv($self->{"fh"}, $recv_msg, 1500, ICMP_FLAGS);
415 ($from_port, $from_ip) = sockaddr_in($from_saddr);
9c36735d 416 ($from_type, $from_subcode) = unpack("C2", substr($recv_msg, 20, 2));
9539e94f
JH
417 if ($from_type == ICMP_ECHOREPLY) {
418 ($from_pid, $from_seq) = unpack("n3", substr($recv_msg, 24, 4))
419 if length $recv_msg >= 28;
9c36735d 420 } else {
9539e94f
JH
421 ($from_pid, $from_seq) = unpack("n3", substr($recv_msg, 52, 4))
422 if length $recv_msg >= 56;
9c36735d
JH
423 }
424 $self->{"from_ip"} = $from_ip;
425 $self->{"from_type"} = $from_type;
426 $self->{"from_subcode"} = $from_subcode;
427 if (($from_pid == $self->{"pid"}) && # Does the packet check out?
428 ($from_seq == $self->{"seq"})) {
429 if ($from_type == ICMP_ECHOREPLY){
430 $ret = 1;
431 }
e82f584b
JH
432 $done = 1;
433 }
9c36735d 434 } else { # Oops, timed out
e82f584b
JH
435 $done = 1;
436 }
437 }
438 return $ret;
a3b93737
RM
439}
440
9c36735d
JH
441sub icmp_result {
442 my ($self) = @_;
443 my $ip = $self->{"from_ip"} || "";
444 $ip = "\0\0\0\0" unless 4 == length $ip;
445 return (inet_ntoa($ip),($self->{"from_type"} || 0), ($self->{"from_subcode"} || 0));
446}
447
a3b93737
RM
448# Description: Do a checksum on the message. Basically sum all of
449# the short words and fold the high order bits into the low order bits.
450
451sub checksum
452{
e82f584b
JH
453 my ($class,
454 $msg # The message to checksum
455 ) = @_;
456 my ($len_msg, # Length of the message
457 $num_short, # The number of short words in the message
458 $short, # One short word
459 $chk # The checksum
460 );
461
462 $len_msg = length($msg);
463 $num_short = int($len_msg / 2);
464 $chk = 0;
9c36735d 465 foreach $short (unpack("n$num_short", $msg))
e82f584b
JH
466 {
467 $chk += $short;
468 } # Add the odd byte in
469 $chk += (unpack("C", substr($msg, $len_msg - 1, 1)) << 8) if $len_msg % 2;
470 $chk = ($chk >> 16) + ($chk & 0xffff); # Fold high into low
471 return(~(($chk >> 16) + $chk) & 0xffff); # Again and complement
a3b93737
RM
472}
473
787ecdfa 474
b124990b
JH
475# Description: Perform a tcp echo ping. Since a tcp connection is
476# host specific, we have to open and close each connection here. We
477# can't just leave a socket open. Because of the robust nature of
478# tcp, it will take a while before it gives up trying to establish a
479# connection. Therefore, we use select() on a non-blocking socket to
480# check against our timeout. No data bytes are actually
481# sent since the successful establishment of a connection is proof
482# enough of the reachability of the remote host. Also, tcp is
483# expensive and doesn't need our help to add to the overhead.
484
485sub ping_tcp
787ecdfa 486{
e82f584b
JH
487 my ($self,
488 $ip, # Packed IP number of the host
489 $timeout # Seconds after which ping times out
490 ) = @_;
491 my ($ret # The return value
492 );
493
9c36735d 494 $! = 0;
e82f584b 495 $ret = $self -> tcp_connect( $ip, $timeout);
c94ff782 496 if (!$self->{"econnrefused"} &&
f569508e
HS
497 $! == ECONNREFUSED) {
498 $ret = 1; # "Connection refused" means reachable
499 }
e82f584b
JH
500 $self->{"fh"}->close();
501 return $ret;
787ecdfa
JH
502}
503
b124990b 504sub tcp_connect
787ecdfa 505{
e82f584b
JH
506 my ($self,
507 $ip, # Packed IP number of the host
508 $timeout # Seconds after which connect times out
509 ) = @_;
510 my ($saddr); # Packed IP and Port
b124990b 511
e82f584b 512 $saddr = sockaddr_in($self->{"port_num"}, $ip);
b124990b 513
e82f584b 514 my $ret = 0; # Default to unreachable
b124990b 515
e82f584b
JH
516 my $do_socket = sub {
517 socket($self->{"fh"}, PF_INET, SOCK_STREAM, $self->{"proto_num"}) ||
518 croak("tcp socket error - $!");
519 if (defined $self->{"local_addr"} &&
520 !CORE::bind($self->{"fh"}, sockaddr_in(0, $self->{"local_addr"}))) {
521 croak("tcp bind error - $!");
522 }
f569508e
HS
523 if ($self->{'device'}) {
524 setsockopt($self->{"fh"}, SOL_SOCKET, SO_BINDTODEVICE(), pack("Z*", $self->{'device'}))
525 or croak("error binding to device $self->{'device'} $!");
526 }
e82f584b
JH
527 };
528 my $do_connect = sub {
9c36735d
JH
529 $self->{"ip"} = $ip;
530 return ($ret = connect($self->{"fh"}, $saddr));
e82f584b 531 };
9c36735d
JH
532 my $do_connect_nb = sub {
533 # Set O_NONBLOCK property on filehandle
534 $self->socket_blocking_mode($self->{"fh"}, 0);
535
536 # start the connection attempt
537 if (!connect($self->{"fh"}, $saddr)) {
538 if ($! == ECONNREFUSED) {
c94ff782
JH
539 $ret = 1 unless $self->{"econnrefused"};
540 } elsif ($! != EINPROGRESS) {
9c36735d 541 # EINPROGRESS is the expected error code after a connect()
c94ff782
JH
542 # on a non-blocking socket. But if the kernel immediately
543 # determined that this connect() will never work,
544 # Simply respond with "unreachable" status.
545 # (This can occur on some platforms with errno
546 # EHOSTUNREACH or ENETUNREACH.)
547 return 0;
548 } else {
549 # Got the expected EINPROGRESS.
550 # Just wait for connection completion...
9c36735d
JH
551 my ($wbits, $wout);
552 $wout = $wbits = "";
553 vec($wbits, $self->{"fh"}->fileno, 1) = 1;
554
555 my $nfound = select(undef, ($wout = $wbits), undef, $timeout);
556 warn("select: $!") unless defined $nfound;
557
558 if ($nfound && vec($wout, $self->{"fh"}->fileno, 1)) {
559 # the socket is ready for writing so the connection
560 # attempt completed. test whether the connection
561 # attempt was successful or not
562
563 if (getpeername($self->{"fh"})) {
564 # Connection established to remote host
565 $ret = 1;
566 } else {
567 # TCP ACK will never come from this host
568 # because there was an error connecting.
e82f584b 569
9c36735d
JH
570 # This should set $! to the correct error.
571 my $char;
572 sysread($self->{"fh"},$char,1);
573 $! = ECONNREFUSED if ($! == EAGAIN && $^O =~ /cygwin/i);
e82f584b 574
c94ff782 575 $ret = 1 if (!$self->{"econnrefused"}
9c36735d
JH
576 && $! == ECONNREFUSED);
577 }
578 } else {
579 # the connection attempt timed out
580 }
581 }
582 } else {
583 # Connection established to remote host
584 $ret = 1;
585 }
586
587 # Unset O_NONBLOCK property on filehandle
588 $self->socket_blocking_mode($self->{"fh"}, 1);
589 $self->{"ip"} = $ip;
590 return $ret;
591 };
592
593 if ($syn_forking) {
594 # Buggy Winsock API doesn't allow nonblocking connect.
e82f584b
JH
595 # Hence, if our OS is Windows, we need to create a separate
596 # process to do the blocking connect attempt.
597
598 $| = 1; # Clear buffer prior to fork to prevent duplicate flushing.
9c36735d
JH
599 $self->{'tcp_chld'} = fork;
600 if (!$self->{'tcp_chld'}) {
601 if (!defined $self->{'tcp_chld'}) {
e82f584b 602 # Fork did not work
9c36735d 603 warn "Fork error: $!";
e82f584b 604 return 0;
b124990b 605 }
b124990b
JH
606 &{ $do_socket }();
607
e82f584b 608 # Try a slow blocking connect() call
9c36735d 609 # and report the status to the parent.
e82f584b
JH
610 if ( &{ $do_connect }() ) {
611 $self->{"fh"}->close();
612 # No error
613 exit 0;
b124990b 614 } else {
e82f584b
JH
615 # Pass the error status to the parent
616 exit $!;
b124990b 617 }
e82f584b 618 }
b124990b 619
e82f584b
JH
620 &{ $do_socket }();
621
622 my $patience = &time() + $timeout;
623
9c36735d
JH
624 my ($child, $child_errno);
625 $? = 0; $child_errno = 0;
e82f584b
JH
626 # Wait up to the timeout
627 # And clean off the zombie
628 do {
9c36735d
JH
629 $child = waitpid($self->{'tcp_chld'}, &WNOHANG());
630 $child_errno = $? >> 8;
e82f584b 631 select(undef, undef, undef, 0.1);
9c36735d
JH
632 } while &time() < $patience && $child != $self->{'tcp_chld'};
633
634 if ($child == $self->{'tcp_chld'}) {
635 if ($self->{"proto"} eq "stream") {
636 # We need the socket connected here, in parent
637 # Should be safe to connect because the child finished
638 # within the timeout
639 &{ $do_connect }();
640 }
e82f584b
JH
641 } else {
642 # Time must have run out.
e82f584b 643 # Put that choking client out of its misery
9c36735d 644 kill "KILL", $self->{'tcp_chld'};
e82f584b 645 # Clean off the zombie
9c36735d 646 waitpid($self->{'tcp_chld'}, 0);
e82f584b 647 $ret = 0;
b124990b 648 }
9c36735d
JH
649 delete $self->{'tcp_chld'};
650 $! = $child_errno;
651 } else {
e82f584b
JH
652 # Otherwise don't waste the resources to fork
653
654 &{ $do_socket }();
655
9c36735d 656 &{ $do_connect_nb }();
e82f584b 657 }
787ecdfa 658
e82f584b 659 return $ret;
787ecdfa
JH
660}
661
9c36735d
JH
662sub DESTROY {
663 my $self = shift;
664 if ($self->{'proto'} eq 'tcp' &&
665 $self->{'tcp_chld'}) {
666 # Put that choking client out of its misery
667 kill "KILL", $self->{'tcp_chld'};
668 # Clean off the zombie
669 waitpid($self->{'tcp_chld'}, 0);
670 }
671}
672
787ecdfa
JH
673# This writes the given string to the socket and then reads it
674# back. It returns 1 on success, 0 on failure.
675sub tcp_echo
676{
e82f584b
JH
677 my $self = shift;
678 my $timeout = shift;
679 my $pingstring = shift;
680
681 my $ret = undef;
682 my $time = &time();
683 my $wrstr = $pingstring;
684 my $rdstr = "";
685
686 eval <<'EOM';
687 do {
688 my $rin = "";
689 vec($rin, $self->{"fh"}->fileno(), 1) = 1;
690
691 my $rout = undef;
692 if($wrstr) {
693 $rout = "";
694 vec($rout, $self->{"fh"}->fileno(), 1) = 1;
695 }
696
697 if(select($rin, $rout, undef, ($time + $timeout) - &time())) {
698
699 if($rout && vec($rout,$self->{"fh"}->fileno(),1)) {
9c36735d 700 my $num = syswrite($self->{"fh"}, $wrstr, length $wrstr);
e82f584b
JH
701 if($num) {
702 # If it was a partial write, update and try again.
703 $wrstr = substr($wrstr,$num);
704 } else {
705 # There was an error.
706 $ret = 0;
707 }
708 }
709
710 if(vec($rin,$self->{"fh"}->fileno(),1)) {
711 my $reply;
712 if(sysread($self->{"fh"},$reply,length($pingstring)-length($rdstr))) {
713 $rdstr .= $reply;
714 $ret = 1 if $rdstr eq $pingstring;
715 } else {
716 # There was an error.
717 $ret = 0;
718 }
719 }
720
721 }
722 } until &time() > ($time + $timeout) || defined($ret);
787ecdfa
JH
723EOM
724
e82f584b 725 return $ret;
787ecdfa
JH
726}
727
787ecdfa 728
787ecdfa 729
787ecdfa
JH
730
731# Description: Perform a stream ping. If the tcp connection isn't
732# already open, it opens it. It then sends some data and waits for
733# a reply. It leaves the stream open on exit.
734
735sub ping_stream
736{
e82f584b
JH
737 my ($self,
738 $ip, # Packed IP number of the host
739 $timeout # Seconds after which ping times out
740 ) = @_;
072620d9 741
e82f584b
JH
742 # Open the stream if it's not already open
743 if(!defined $self->{"fh"}->fileno()) {
744 $self->tcp_connect($ip, $timeout) or return 0;
745 }
787ecdfa 746
e82f584b
JH
747 croak "tried to switch servers while stream pinging"
748 if $self->{"ip"} ne $ip;
749
750 return $self->tcp_echo($timeout, $pingstring);
787ecdfa
JH
751}
752
753# Description: opens the stream. You would do this if you want to
754# separate the overhead of opening the stream from the first ping.
755
756sub open
757{
e82f584b
JH
758 my ($self,
759 $host, # Host or IP address
760 $timeout # Seconds after which open times out
761 ) = @_;
762
763 my ($ip); # Packed IP number of the host
764 $ip = inet_aton($host);
765 $timeout = $self->{"timeout"} unless $timeout;
766
767 if($self->{"proto"} eq "stream") {
768 if(defined($self->{"fh"}->fileno())) {
769 croak("socket is already open");
770 } else {
771 $self->tcp_connect($ip, $timeout);
b124990b 772 }
e82f584b 773 }
072620d9
SB
774}
775
b124990b 776
a3b93737
RM
777# Description: Perform a udp echo ping. Construct a message of
778# at least the one-byte sequence number and any additional data bytes.
779# Send the message out and wait for a message to come back. If we
780# get a message, make sure all of its parts match. If they do, we are
781# done. Otherwise go back and wait for the message until we run out
782# of time. Return the result of our efforts.
783
49afa5f6 784use constant UDP_FLAGS => 0; # Nothing special on send or recv
a3b93737
RM
785sub ping_udp
786{
e82f584b
JH
787 my ($self,
788 $ip, # Packed IP number of the host
789 $timeout # Seconds after which ping times out
790 ) = @_;
791
792 my ($saddr, # sockaddr_in with port and ip
793 $ret, # The return value
794 $msg, # Message to be echoed
795 $finish_time, # Time ping should be finished
9539e94f
JH
796 $flush, # Whether socket needs to be disconnected
797 $connect, # Whether socket needs to be connected
e82f584b
JH
798 $done, # Set to 1 when we are done pinging
799 $rbits, # Read bits, filehandles for reading
800 $nfound, # Number of ready filehandles found
801 $from_saddr, # sockaddr_in of sender
802 $from_msg, # Characters echoed by $host
803 $from_port, # Port message was echoed from
804 $from_ip # Packed IP number of sender
805 );
806
807 $saddr = sockaddr_in($self->{"port_num"}, $ip);
808 $self->{"seq"} = ($self->{"seq"} + 1) % 256; # Increment sequence
809 $msg = chr($self->{"seq"}) . $self->{"data"}; # Add data if any
9539e94f
JH
810
811 if ($self->{"connected"}) {
812 if ($self->{"connected"} ne $saddr) {
813 # Still connected to wrong destination.
814 # Need to flush out the old one.
815 $flush = 1;
816 }
817 } else {
818 # Not connected yet.
819 # Need to connect() before send()
820 $connect = 1;
821 }
822
c94ff782
JH
823 # Have to connect() and send() instead of sendto()
824 # in order to pick up on the ECONNREFUSED setting
825 # from recv() or double send() errno as utilized in
826 # the concept by rdw @ perlmonks. See:
827 # http://perlmonks.thepen.com/42898.html
9539e94f
JH
828 if ($flush) {
829 # Need to socket() again to flush the descriptor
830 # This will disconnect from the old saddr.
831 socket($self->{"fh"}, PF_INET, SOCK_DGRAM,
832 $self->{"proto_num"});
833 }
834 # Connect the socket if it isn't already connected
835 # to the right destination.
836 if ($flush || $connect) {
837 connect($self->{"fh"}, $saddr); # Tie destination to socket
838 $self->{"connected"} = $saddr;
839 }
c94ff782 840 send($self->{"fh"}, $msg, UDP_FLAGS); # Send it
e82f584b
JH
841
842 $rbits = "";
843 vec($rbits, $self->{"fh"}->fileno(), 1) = 1;
844 $ret = 0; # Default to unreachable
845 $done = 0;
c94ff782 846 my $retrans = 0.01;
9539e94f 847 my $factor = $self->{"retrans"};
e82f584b
JH
848 $finish_time = &time() + $timeout; # Ping needs to be done by then
849 while (!$done && $timeout > 0)
850 {
9539e94f
JH
851 if ($factor > 1)
852 {
853 $timeout = $retrans if $timeout > $retrans;
854 $retrans*= $factor; # Exponential backoff
855 }
856 $nfound = select((my $rout=$rbits), undef, undef, $timeout); # Wait for response
c94ff782 857 my $why = $!;
e82f584b
JH
858 $timeout = $finish_time - &time(); # Get remaining time
859
860 if (!defined($nfound)) # Hmm, a strange error
a3b93737 861 {
e82f584b
JH
862 $ret = undef;
863 $done = 1;
a3b93737 864 }
e82f584b
JH
865 elsif ($nfound) # A packet is waiting
866 {
867 $from_msg = "";
c94ff782
JH
868 $from_saddr = recv($self->{"fh"}, $from_msg, 1500, UDP_FLAGS);
869 if (!$from_saddr) {
870 # For example an unreachable host will make recv() fail.
871 if (!$self->{"econnrefused"} &&
9539e94f
JH
872 ($! == ECONNREFUSED ||
873 $! == ECONNRESET)) {
c94ff782
JH
874 # "Connection refused" means reachable
875 # Good, continue
876 $ret = 1;
877 }
e82f584b 878 $done = 1;
c94ff782
JH
879 } else {
880 ($from_port, $from_ip) = sockaddr_in($from_saddr);
881 if (!$source_verify ||
882 (($from_ip eq $ip) && # Does the packet check out?
883 ($from_port == $self->{"port_num"}) &&
884 ($from_msg eq $msg)))
885 {
886 $ret = 1; # It's a winner
887 $done = 1;
888 }
e82f584b
JH
889 }
890 }
c94ff782 891 elsif ($timeout <= 0) # Oops, timed out
e82f584b
JH
892 {
893 $done = 1;
894 }
c94ff782
JH
895 else
896 {
897 # Send another in case the last one dropped
898 if (send($self->{"fh"}, $msg, UDP_FLAGS)) {
899 # Another send worked? The previous udp packet
900 # must have gotten lost or is still in transit.
901 # Hopefully this new packet will arrive safely.
902 } else {
903 if (!$self->{"econnrefused"} &&
904 $! == ECONNREFUSED) {
905 # "Connection refused" means reachable
906 # Good, continue
907 $ret = 1;
908 }
909 $done = 1;
910 }
911 }
e82f584b 912 }
a5a165b1 913 return $ret;
b124990b 914}
a0d0e21e 915
f569508e
HS
916# Description: Send a TCP SYN packet to host specified.
917sub ping_syn
918{
919 my $self = shift;
920 my $host = shift;
921 my $ip = shift;
922 my $start_time = shift;
923 my $stop_time = shift;
924
925 if ($syn_forking) {
926 return $self->ping_syn_fork($host, $ip, $start_time, $stop_time);
927 }
928
929 my $fh = FileHandle->new();
930 my $saddr = sockaddr_in($self->{"port_num"}, $ip);
931
932 # Create TCP socket
933 if (!socket ($fh, PF_INET, SOCK_STREAM, $self->{"proto_num"})) {
934 croak("tcp socket error - $!");
935 }
936
937 if (defined $self->{"local_addr"} &&
938 !CORE::bind($fh, sockaddr_in(0, $self->{"local_addr"}))) {
939 croak("tcp bind error - $!");
940 }
941
942 if ($self->{'device'}) {
943 setsockopt($fh, SOL_SOCKET, SO_BINDTODEVICE(), pack("Z*", $self->{'device'}))
944 or croak("error binding to device $self->{'device'} $!");
945 }
946
947 # Set O_NONBLOCK property on filehandle
9c36735d 948 $self->socket_blocking_mode($fh, 0);
f569508e
HS
949
950 # Attempt the non-blocking connect
951 # by just sending the TCP SYN packet
952 if (connect($fh, $saddr)) {
953 # Non-blocking, yet still connected?
69c74a9c
HS
954 # Must have connected very quickly,
955 # or else it wasn't very non-blocking.
956 #warn "WARNING: Nonblocking connect connected anyway? ($^O)";
957 } else {
f569508e 958 # Error occurred connecting.
69c74a9c
HS
959 if ($! == EINPROGRESS) {
960 # The connection is just still in progress.
961 # This is the expected condition.
962 } else {
963 # Just save the error and continue on.
964 # The ack() can check the status later.
f569508e 965 $self->{"bad"}->{$host} = $!;
f569508e
HS
966 }
967 }
968
969 my $entry = [ $host, $ip, $fh, $start_time, $stop_time ];
970 $self->{"syn"}->{$fh->fileno} = $entry;
971 if ($self->{"stop_time"} < $stop_time) {
972 $self->{"stop_time"} = $stop_time;
973 }
974 vec($self->{"wbits"}, $fh->fileno, 1) = 1;
975
976 return 1;
977}
978
979sub ping_syn_fork {
980 my ($self, $host, $ip, $start_time, $stop_time) = @_;
981
982 # Buggy Winsock API doesn't allow nonblocking connect.
983 # Hence, if our OS is Windows, we need to create a separate
984 # process to do the blocking connect attempt.
985 my $pid = fork();
986 if (defined $pid) {
987 if ($pid) {
988 # Parent process
989 my $entry = [ $host, $ip, $pid, $start_time, $stop_time ];
990 $self->{"syn"}->{$pid} = $entry;
991 if ($self->{"stop_time"} < $stop_time) {
992 $self->{"stop_time"} = $stop_time;
993 }
994 } else {
995 # Child process
996 my $saddr = sockaddr_in($self->{"port_num"}, $ip);
997
998 # Create TCP socket
999 if (!socket ($self->{"fh"}, PF_INET, SOCK_STREAM, $self->{"proto_num"})) {
1000 croak("tcp socket error - $!");
1001 }
1002
1003 if (defined $self->{"local_addr"} &&
1004 !CORE::bind($self->{"fh"}, sockaddr_in(0, $self->{"local_addr"}))) {
1005 croak("tcp bind error - $!");
1006 }
1007
1008 if ($self->{'device'}) {
1009 setsockopt($self->{"fh"}, SOL_SOCKET, SO_BINDTODEVICE(), pack("Z*", $self->{'device'}))
1010 or croak("error binding to device $self->{'device'} $!");
1011 }
1012
1013 $!=0;
1014 # Try to connect (could take a long time)
1015 connect($self->{"fh"}, $saddr);
1016 # Notify parent of connect error status
1017 my $err = $!+0;
1018 my $wrstr = "$$ $err";
9c36735d
JH
1019 # Force to 16 chars including \n
1020 $wrstr .= " "x(15 - length $wrstr). "\n";
1021 syswrite($self->{"fork_wr"}, $wrstr, length $wrstr);
f569508e
HS
1022 exit;
1023 }
1024 } else {
1025 # fork() failed?
1026 die "fork: $!";
1027 }
1028 return 1;
1029}
1030
1031# Description: Wait for TCP ACK from host specified
1032# from ping_syn above. If no host is specified, wait
1033# for TCP ACK from any of the hosts in the SYN queue.
1034sub ack
1035{
1036 my $self = shift;
1037
1038 if ($self->{"proto"} eq "syn") {
1039 if ($syn_forking) {
1040 my @answer = $self->ack_unfork(shift);
1041 return wantarray ? @answer : $answer[0];
1042 }
1043 my $wbits = "";
1044 my $stop_time = 0;
1045 if (my $host = shift) {
1046 # Host passed as arg
1047 if (exists $self->{"bad"}->{$host}) {
c94ff782 1048 if (!$self->{"econnrefused"} &&
69c74a9c
HS
1049 $self->{"bad"}->{ $host } &&
1050 (($! = ECONNREFUSED)>0) &&
1051 $self->{"bad"}->{ $host } eq "$!") {
1052 # "Connection refused" means reachable
1053 # Good, continue
1054 } else {
1055 # ECONNREFUSED means no good
1056 return ();
1057 }
f569508e
HS
1058 }
1059 my $host_fd = undef;
1060 foreach my $fd (keys %{ $self->{"syn"} }) {
1061 my $entry = $self->{"syn"}->{$fd};
1062 if ($entry->[0] eq $host) {
1063 $host_fd = $fd;
1064 $stop_time = $entry->[4]
1065 || croak("Corrupted SYN entry for [$host]");
1066 last;
1067 }
1068 }
1069 croak("ack called on [$host] without calling ping first!")
1070 unless defined $host_fd;
1071 vec($wbits, $host_fd, 1) = 1;
1072 } else {
1073 # No $host passed so scan all hosts
1074 # Use the latest stop_time
1075 $stop_time = $self->{"stop_time"};
1076 # Use all the bits
1077 $wbits = $self->{"wbits"};
1078 }
1079
9c36735d 1080 while ($wbits !~ /^\0*\z/) {
f569508e
HS
1081 my $timeout = $stop_time - &time();
1082 # Force a minimum of 10 ms timeout.
69c74a9c
HS
1083 $timeout = 0.01 if $timeout <= 0.01;
1084
1085 my $winner_fd = undef;
1086 my $wout = $wbits;
1087 my $fd = 0;
1088 # Do "bad" fds from $wbits first
9c36735d 1089 while ($wout !~ /^\0*\z/) {
69c74a9c
HS
1090 if (vec($wout, $fd, 1)) {
1091 # Wipe it from future scanning.
1092 vec($wout, $fd, 1) = 0;
1093 if (my $entry = $self->{"syn"}->{$fd}) {
1094 if ($self->{"bad"}->{ $entry->[0] }) {
1095 $winner_fd = $fd;
1096 last;
1097 }
1098 }
1099 }
1100 $fd++;
1101 }
1102
1103 if (defined($winner_fd) or my $nfound = select(undef, ($wout=$wbits), undef, $timeout)) {
1104 if (defined $winner_fd) {
1105 $fd = $winner_fd;
1106 } else {
1107 # Done waiting for one of the ACKs
1108 $fd = 0;
1109 # Determine which one
9c36735d 1110 while ($wout !~ /^\0*\z/ &&
69c74a9c
HS
1111 !vec($wout, $fd, 1)) {
1112 $fd++;
1113 }
f569508e
HS
1114 }
1115 if (my $entry = $self->{"syn"}->{$fd}) {
69c74a9c
HS
1116 # Wipe it from future scanning.
1117 delete $self->{"syn"}->{$fd};
1118 vec($self->{"wbits"}, $fd, 1) = 0;
1119 vec($wbits, $fd, 1) = 0;
c94ff782 1120 if (!$self->{"econnrefused"} &&
69c74a9c
HS
1121 $self->{"bad"}->{ $entry->[0] } &&
1122 (($! = ECONNREFUSED)>0) &&
1123 $self->{"bad"}->{ $entry->[0] } eq "$!") {
1124 # "Connection refused" means reachable
1125 # Good, continue
1126 } elsif (getpeername($entry->[2])) {
f569508e 1127 # Connection established to remote host
69c74a9c 1128 # Good, continue
f569508e
HS
1129 } else {
1130 # TCP ACK will never come from this host
1131 # because there was an error connecting.
1132
f569508e
HS
1133 # This should set $! to the correct error.
1134 my $char;
9c36735d 1135 sysread($entry->[2],$char,1);
f569508e
HS
1136 # Store the excuse why the connection failed.
1137 $self->{"bad"}->{$entry->[0]} = $!;
c94ff782 1138 if (!$self->{"econnrefused"} &&
69c74a9c
HS
1139 (($! == ECONNREFUSED) ||
1140 ($! == EAGAIN && $^O =~ /cygwin/i))) {
f569508e 1141 # "Connection refused" means reachable
69c74a9c
HS
1142 # Good, continue
1143 } else {
1144 # No good, try the next socket...
1145 next;
f569508e 1146 }
f569508e 1147 }
69c74a9c
HS
1148 # Everything passed okay, return the answer
1149 return wantarray ?
1150 ($entry->[0], &time() - $entry->[3], inet_ntoa($entry->[1]))
1151 : $entry->[0];
f569508e
HS
1152 } else {
1153 warn "Corrupted SYN entry: unknown fd [$fd] ready!";
1154 vec($wbits, $fd, 1) = 0;
1155 vec($self->{"wbits"}, $fd, 1) = 0;
1156 }
1157 } elsif (defined $nfound) {
1158 # Timed out waiting for ACK
1159 foreach my $fd (keys %{ $self->{"syn"} }) {
1160 if (vec($wbits, $fd, 1)) {
1161 my $entry = $self->{"syn"}->{$fd};
1162 $self->{"bad"}->{$entry->[0]} = "Timed out";
1163 vec($wbits, $fd, 1) = 0;
1164 vec($self->{"wbits"}, $fd, 1) = 0;
1165 delete $self->{"syn"}->{$fd};
1166 }
1167 }
1168 } else {
1169 # Weird error occurred with select()
1170 warn("select: $!");
1171 $self->{"syn"} = {};
1172 $wbits = "";
1173 }
1174 }
1175 }
1176 return ();
1177}
1178
1179sub ack_unfork {
69c74a9c 1180 my ($self,$host) = @_;
f569508e 1181 my $stop_time = $self->{"stop_time"};
69c74a9c 1182 if ($host) {
f569508e 1183 # Host passed as arg
69c74a9c
HS
1184 if (my $entry = $self->{"good"}->{$host}) {
1185 delete $self->{"good"}->{$host};
1186 return ($entry->[0], &time() - $entry->[3], inet_ntoa($entry->[1]));
1187 }
f569508e
HS
1188 }
1189
1190 my $rbits = "";
1191 my $timeout;
69c74a9c 1192
f569508e
HS
1193 if (keys %{ $self->{"syn"} }) {
1194 # Scan all hosts that are left
1195 vec($rbits, fileno($self->{"fork_rd"}), 1) = 1;
1196 $timeout = $stop_time - &time();
69c74a9c
HS
1197 # Force a minimum of 10 ms timeout.
1198 $timeout = 0.01 if $timeout < 0.01;
f569508e
HS
1199 } else {
1200 # No hosts left to wait for
1201 $timeout = 0;
1202 }
1203
1204 if ($timeout > 0) {
69c74a9c
HS
1205 my $nfound;
1206 while ( keys %{ $self->{"syn"} } and
1207 $nfound = select((my $rout=$rbits), undef, undef, $timeout)) {
f569508e 1208 # Done waiting for one of the ACKs
9c36735d 1209 if (!sysread($self->{"fork_rd"}, $_, 16)) {
f569508e
HS
1210 # Socket closed, which means all children are done.
1211 return ();
1212 }
1213 my ($pid, $how) = split;
1214 if ($pid) {
1215 # Flush the zombie
1216 waitpid($pid, 0);
1217 if (my $entry = $self->{"syn"}->{$pid}) {
1218 # Connection attempt to remote host is done
1219 delete $self->{"syn"}->{$pid};
1220 if (!$how || # If there was no error connecting
c94ff782 1221 (!$self->{"econnrefused"} &&
f569508e 1222 $how == ECONNREFUSED)) { # "Connection refused" means reachable
69c74a9c
HS
1223 if ($host && $entry->[0] ne $host) {
1224 # A good connection, but not the host we need.
1225 # Move it from the "syn" hash to the "good" hash.
1226 $self->{"good"}->{$entry->[0]} = $entry;
1227 # And wait for the next winner
1228 next;
1229 }
f569508e
HS
1230 return ($entry->[0], &time() - $entry->[3], inet_ntoa($entry->[1]));
1231 }
1232 } else {
1233 # Should never happen
1234 die "Unknown ping from pid [$pid]";
1235 }
1236 } else {
1237 die "Empty response from status socket?";
1238 }
69c74a9c
HS
1239 }
1240 if (defined $nfound) {
f569508e
HS
1241 # Timed out waiting for ACK status
1242 } else {
1243 # Weird error occurred with select()
1244 warn("select: $!");
1245 }
1246 }
1247 if (my @synners = keys %{ $self->{"syn"} }) {
1248 # Kill all the synners
1249 kill 9, @synners;
1250 foreach my $pid (@synners) {
1251 # Wait for the deaths to finish
1252 # Then flush off the zombie
1253 waitpid($pid, 0);
1254 }
1255 }
1256 $self->{"syn"} = {};
1257 return ();
1258}
1259
1260# Description: Tell why the ack() failed
1261sub nack {
1262 my $self = shift;
1263 my $host = shift || croak('Usage> nack($failed_ack_host)');
1264 return $self->{"bad"}->{$host} || undef;
1265}
1266
1267# Description: Close the connection.
a3b93737
RM
1268
1269sub close
1270{
e82f584b 1271 my ($self) = @_;
a3b93737 1272
f569508e
HS
1273 if ($self->{"proto"} eq "syn") {
1274 delete $self->{"syn"};
1275 } elsif ($self->{"proto"} eq "tcp") {
1276 # The connection will already be closed
1277 } else {
1278 $self->{"fh"}->close();
1279 }
a3b93737
RM
1280}
1281
1282
a0d0e21e 12831;
8e07c86e
AD
1284__END__
1285
8e07c86e
AD
1286=head1 NAME
1287
a3b93737 1288Net::Ping - check a remote host for reachability
8e07c86e
AD
1289
1290=head1 SYNOPSIS
1291
1292 use Net::Ping;
8e07c86e 1293
a3b93737
RM
1294 $p = Net::Ping->new();
1295 print "$host is alive.\n" if $p->ping($host);
1296 $p->close();
1297
1298 $p = Net::Ping->new("icmp");
49afa5f6 1299 $p->bind($my_addr); # Specify source interface of pings
a3b93737
RM
1300 foreach $host (@host_array)
1301 {
1302 print "$host is ";
1303 print "NOT " unless $p->ping($host, 2);
1304 print "reachable.\n";
1305 sleep(1);
1306 }
1307 $p->close();
b124990b 1308
a3b93737 1309 $p = Net::Ping->new("tcp", 2);
b124990b
JH
1310 # Try connecting to the www port instead of the echo port
1311 $p->{port_num} = getservbyname("http", "tcp");
a3b93737
RM
1312 while ($stop_time > time())
1313 {
1314 print "$host not reachable ", scalar(localtime()), "\n"
1315 unless $p->ping($host);
1316 sleep(300);
1317 }
1318 undef($p);
b124990b 1319
f569508e
HS
1320 # Like tcp protocol, but with many hosts
1321 $p = Net::Ping->new("syn");
1322 $p->{port_num} = getservbyname("http", "tcp");
1323 foreach $host (@host_array) {
1324 $p->ping($host);
1325 }
1326 while (($host,$rtt,$ip) = $p->ack) {
1327 print "HOST: $host [$ip] ACKed in $rtt seconds.\n";
1328 }
1329
e82f584b
JH
1330 # High precision syntax (requires Time::HiRes)
1331 $p = Net::Ping->new();
1332 $p->hires();
1333 ($ret, $duration, $ip) = $p->ping($host, 5.5);
1334 printf("$host [ip: $ip] is alive (packet return time: %.2f ms)\n", 1000 * $duration)
1335 if $ret;
1336 $p->close();
1337
a3b93737
RM
1338 # For backward compatibility
1339 print "$host is alive.\n" if pingecho($host);
8e07c86e 1340
a3b93737 1341=head1 DESCRIPTION
8e07c86e 1342
a3b93737
RM
1343This module contains methods to test the reachability of remote
1344hosts on a network. A ping object is first created with optional
1345parameters, a variable number of hosts may be pinged multiple
1346times and then the connection is closed.
1347
f569508e
HS
1348You may choose one of six different protocols to use for the
1349ping. The "tcp" protocol is the default. Note that a live remote host
b124990b 1350may still fail to be pingable by one or more of these protocols. For
f569508e 1351example, www.microsoft.com is generally alive but not "icmp" pingable.
787ecdfa 1352
b124990b
JH
1353With the "tcp" protocol the ping() method attempts to establish a
1354connection to the remote host's echo port. If the connection is
1355successfully established, the remote host is considered reachable. No
1356data is actually echoed. This protocol does not require any special
9c36735d 1357privileges but has higher overhead than the "udp" and "icmp" protocols.
072620d9 1358
b124990b 1359Specifying the "udp" protocol causes the ping() method to send a udp
a3b93737
RM
1360packet to the remote host's echo port. If the echoed packet is
1361received from the remote host and the received packet contains the
1362same data as the packet that was sent, the remote host is considered
1363reachable. This protocol does not require any special privileges.
b124990b 1364It should be borne in mind that, for a udp ping, a host
787ecdfa 1365will be reported as unreachable if it is not running the
b124990b
JH
1366appropriate echo service. For Unix-like systems see L<inetd(8)>
1367for more information.
787ecdfa 1368
b124990b
JH
1369If the "icmp" protocol is specified, the ping() method sends an icmp
1370echo message to the remote host, which is what the UNIX ping program
1371does. If the echoed message is received from the remote host and
1372the echoed information is correct, the remote host is considered
1373reachable. Specifying the "icmp" protocol requires that the program
1374be run as root or that the program be setuid to root.
787ecdfa 1375
b124990b
JH
1376If the "external" protocol is specified, the ping() method attempts to
1377use the C<Net::Ping::External> module to ping the remote host.
1378C<Net::Ping::External> interfaces with your system's default C<ping>
1379utility to perform the ping, and generally produces relatively
787ecdfa
JH
1380accurate results. If C<Net::Ping::External> if not installed on your
1381system, specifying the "external" protocol will result in an error.
edc5bd88 1382
f569508e
HS
1383If the "syn" protocol is specified, the ping() method will only
1384send a TCP SYN packet to the remote host then immediately return.
1385If the syn packet was sent successfully, it will return a true value,
1386otherwise it will return false. NOTE: Unlike the other protocols,
1387the return value does NOT determine if the remote host is alive or
1388not since the full TCP three-way handshake may not have completed
1389yet. The remote host is only considered reachable if it receives
1390a TCP ACK within the timeout specifed. To begin waiting for the
1391ACK packets, use the ack() method as explained below. Use the
1392"syn" protocol instead the "tcp" protocol to determine reachability
1393of multiple destinations simultaneously by sending parallel TCP
1394SYN packets. It will not block while testing each remote host.
1395demo/fping is provided in this distribution to demonstrate the
1396"syn" protocol as an example.
1397This protocol does not require any special privileges.
1398
a3b93737
RM
1399=head2 Functions
1400
1401=over 4
1402
f569508e 1403=item Net::Ping->new([$proto [, $def_timeout [, $bytes [, $device ]]]]);
a3b93737
RM
1404
1405Create a new ping object. All of the parameters are optional. $proto
1406specifies the protocol to use when doing a ping. The current choices
f569508e
HS
1407are "tcp", "udp", "icmp", "stream", "syn", or "external".
1408The default is "tcp".
a3b93737
RM
1409
1410If a default timeout ($def_timeout) in seconds is provided, it is used
1411when a timeout is not given to the ping() method (below). The timeout
1412must be greater than 0 and the default, if not specified, is 5 seconds.
1413
1414If the number of data bytes ($bytes) is given, that many data bytes
1415are included in the ping packet sent to the remote host. The number of
1416data bytes is ignored if the protocol is "tcp". The minimum (and
1417default) number of data bytes is 1 if the protocol is "udp" and 0
1418otherwise. The maximum number of data bytes that can be specified is
14191024.
1420
f569508e
HS
1421If $device is given, this device is used to bind the source endpoint
1422before sending the ping packet. I beleive this only works with
1423superuser privileges and with udp and icmp protocols at this time.
1424
5d20095f
JH
1425=item $p->ping($host [, $timeout]);
1426
1427Ping the remote host and wait for a response. $host can be either the
1428hostname or the IP number of the remote host. The optional timeout
1429must be greater than 0 seconds and defaults to whatever was specified
1430when the ping object was created. Returns a success flag. If the
1431hostname cannot be found or there is a problem with the IP number, the
1432success flag returned will be undef. Otherwise, the success flag will
1433be 1 if the host is reachable and 0 if it is not. For most practical
1434purposes, undef and 0 and can be treated as the same case. In array
f569508e
HS
1435context, the elapsed time as well as the string form of the ip the
1436host resolved to are also returned. The elapsed time value will
5d20095f
JH
1437be a float, as retuned by the Time::HiRes::time() function, if hires()
1438has been previously called, otherwise it is returned as an integer.
1439
15d96390
JH
1440=item $p->source_verify( { 0 | 1 } );
1441
1442Allows source endpoint verification to be enabled or disabled.
1443This is useful for those remote destinations with multiples
1444interfaces where the response may not originate from the same
1445endpoint that the original destination endpoint was sent to.
5d20095f 1446This only affects udp and icmp protocol pings.
15d96390
JH
1447
1448This is enabled by default.
1449
c94ff782 1450=item $p->service_check( { 0 | 1 } );
f569508e 1451
c94ff782 1452Set whether or not the connect behavior should enforce
f569508e
HS
1453remote service availability as well as reachability. Normally,
1454if the remote server reported ECONNREFUSED, it must have been
1455reachable because of the status packet that it reported.
1456With this option enabled, the full three-way tcp handshake
1457must have been established successfully before it will
1458claim it is reachable. NOTE: It still does nothing more
1459than connect and disconnect. It does not speak any protocol
1460(i.e., HTTP or FTP) to ensure the remote server is sane in
1461any way. The remote server CPU could be grinding to a halt
1462and unresponsive to any clients connecting, but if the kernel
1463throws the ACK packet, it is considered alive anyway. To
1464really determine if the server is responding well would be
1465application specific and is beyond the scope of Net::Ping.
c94ff782
JH
1466For udp protocol, enabling this option demands that the
1467remote server replies with the same udp data that it was sent
1468as defined by the udp echo service.
f569508e 1469
c94ff782 1470This affects the "udp", "tcp", and "syn" protocols.
f569508e
HS
1471
1472This is disabled by default.
1473
c94ff782
JH
1474=item $p->tcp_service_check( { 0 | 1 } );
1475
1476Depricated method, but does the same as service_check() method.
1477
e82f584b
JH
1478=item $p->hires( { 0 | 1 } );
1479
1480Causes this module to use Time::HiRes module, allowing milliseconds
1481to be returned by subsequent calls to ping().
1482
15d96390
JH
1483This is disabled by default.
1484
49afa5f6
JH
1485=item $p->bind($local_addr);
1486
1487Sets the source address from which pings will be sent. This must be
1488the address of one of the interfaces on the local host. $local_addr
1489may be specified as a hostname or as a text IP address such as
1490"192.168.1.1".
1491
1492If the protocol is set to "tcp", this method may be called any
1493number of times, and each call to the ping() method (below) will use
1494the most recent $local_addr. If the protocol is "icmp" or "udp",
1495then bind() must be called at most once per object, and (if it is
1496called at all) must be called before the first call to ping() for that
1497object.
1498
b124990b
JH
1499=item $p->open($host);
1500
f569508e 1501When you are using the "stream" protocol, this call pre-opens the
b124990b
JH
1502tcp socket. It's only necessary to do this if you want to
1503provide a different timeout when creating the connection, or
1504remove the overhead of establishing the connection from the
1505first ping. If you don't call C<open()>, the connection is
1506automatically opened the first time C<ping()> is called.
787ecdfa
JH
1507This call simply does nothing if you are using any protocol other
1508than stream.
1509
f569508e
HS
1510=item $p->ack( [ $host ] );
1511
1512When using the "syn" protocol, use this method to determine
1513the reachability of the remote host. This method is meant
1514to be called up to as many times as ping() was called. Each
1515call returns the host (as passed to ping()) that came back
1516with the TCP ACK. The order in which the hosts are returned
1517may not necessarily be the same order in which they were
1518SYN queued using the ping() method. If the timeout is
1519reached before the TCP ACK is received, or if the remote
1520host is not listening on the port attempted, then the TCP
1521connection will not be established and ack() will return
1522undef. In list context, the host, the ack time, and the
1523dotted ip string will be returned instead of just the host.
1524If the optional $host argument is specified, the return
1525value will be partaining to that host only.
1526This call simply does nothing if you are using any protocol
1527other than syn.
1528
1529=item $p->nack( $failed_ack_host );
1530
1531The reason that host $failed_ack_host did not receive a
1532valid ACK. Useful to find out why when ack( $fail_ack_host )
1533returns a false value.
1534
a3b93737
RM
1535=item $p->close();
1536
1537Close the network connection for this ping object. The network
1538connection is also closed by "undef $p". The network connection is
1539automatically closed if the ping object goes out of scope (e.g. $p is
1540local to a subroutine and you leave the subroutine).
1541
1542=item pingecho($host [, $timeout]);
1543
1544To provide backward compatibility with the previous version of
1545Net::Ping, a pingecho() subroutine is available with the same
1546functionality as before. pingecho() uses the tcp protocol. The
1547return values and parameters are the same as described for the ping()
1548method. This subroutine is obsolete and may be removed in a future
1549version of Net::Ping.
8e07c86e 1550
a3b93737 1551=back
8e07c86e 1552
a3b93737 1553=head1 NOTES
8e07c86e 1554
a3b93737
RM
1555There will be less network overhead (and some efficiency in your
1556program) if you specify either the udp or the icmp protocol. The tcp
1557protocol will generate 2.5 times or more traffic for each ping than
1558either udp or icmp. If many hosts are pinged frequently, you may wish
1559to implement a small wait (e.g. 25ms or more) between each ping to
1560avoid flooding your network with packets.
8e07c86e 1561
a3b93737 1562The icmp protocol requires that the program be run as root or that it
787ecdfa
JH
1563be setuid to root. The other protocols do not require special
1564privileges, but not all network devices implement tcp or udp echo.
8e07c86e 1565
a3b93737
RM
1566Local hosts should normally respond to pings within milliseconds.
1567However, on a very congested network it may take up to 3 seconds or
1568longer to receive an echo packet from the remote host. If the timeout
1569is set too low under these conditions, it will appear that the remote
1570host is not reachable (which is almost the truth).
8e07c86e 1571
a3b93737 1572Reachability doesn't necessarily mean that the remote host is actually
787ecdfa
JH
1573functioning beyond its ability to echo packets. tcp is slightly better
1574at indicating the health of a system than icmp because it uses more
1575of the networking stack to respond.
8e07c86e 1576
a3b93737
RM
1577Because of a lack of anything better, this module uses its own
1578routines to pack and unpack ICMP packets. It would be better for a
1579separate module to be written which understands all of the different
1580kinds of ICMP packets.
8e07c86e 1581
5d20095f
JH
1582=head1 INSTALL
1583
1584The latest source tree is available via cvs:
1585
f569508e 1586 cvs -z3 -q -d :pserver:anonymous@cvs.roobik.com.:/usr/local/cvsroot/freeware checkout Net-Ping
5d20095f
JH
1587 cd Net-Ping
1588
1589The tarball can be created as follows:
1590
1591 perl Makefile.PL ; make ; make dist
1592
1593The latest Net::Ping release can be found at CPAN:
1594
1595 $CPAN/modules/by-module/Net/
1596
15971) Extract the tarball
1598
1599 gtar -zxvf Net-Ping-xxxx.tar.gz
1600 cd Net-Ping-xxxx
1601
16022) Build:
1603
1604 make realclean
1605 perl Makefile.PL
1606 make
1607 make test
1608
16093) Install
1610
1611 make install
1612
1613Or install it RPM Style:
1614
1615 rpm -ta SOURCES/Net-Ping-xxxx.tar.gz
1616
1617 rpm -ih RPMS/noarch/perl-Net-Ping-xxxx.rpm
1618
c94ff782
JH
1619=head1 BUGS
1620
1621For a list of known issues, visit:
1622
1623https://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-Ping
1624
1625To report a new bug, visit:
1626
1627https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-Ping
1628
49afa5f6 1629=head1 AUTHORS
b124990b 1630
e82f584b 1631 Current maintainer:
49afa5f6 1632 bbb@cpan.org (Rob Brown)
b124990b 1633
e82f584b
JH
1634 External protocol:
1635 colinm@cpan.org (Colin McMillen)
1636
b124990b
JH
1637 Stream protocol:
1638 bronson@trestle.com (Scott Bronson)
1639
1640 Original pingecho():
1641 karrer@bernina.ethz.ch (Andreas Karrer)
1642 pmarquess@bfsec.bt.co.uk (Paul Marquess)
1643
1644 Original Net::Ping author:
1645 mose@ns.ccsn.edu (Russell Mosemann)
1646
b124990b
JH
1647=head1 COPYRIGHT
1648
9c36735d 1649Copyright (c) 2002-2003, Rob Brown. All rights reserved.
49afa5f6 1650
e82f584b 1651Copyright (c) 2001, Colin McMillen. All rights reserved.
b124990b
JH
1652
1653This program is free software; you may redistribute it and/or
1654modify it under the same terms as Perl itself.
1655
9539e94f 1656$Id: Ping.pm,v 1.81 2003/04/18 04:16:03 rob Exp $
c94ff782 1657
a3b93737 1658=cut