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