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