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