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