From: Jarkko Hietaniemi Date: Wed, 26 Dec 2001 20:56:09 +0000 (+0000) Subject: Upgrade to Net::Ping 2.10. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=49afa5f6a0c89badde3e7bcd8ece054574377201;p=p5sagit%2Fp5-mst-13.2.git Upgrade to Net::Ping 2.10. p4raw-id: //depot/perl@13897 --- diff --git a/lib/Net/Ping.pm b/lib/Net/Ping.pm index c3673b1..642338c 100644 --- a/lib/Net/Ping.pm +++ b/lib/Net/Ping.pm @@ -1,6 +1,6 @@ package Net::Ping; -# $Id: Ping.pm,v 1.13 2001/12/07 02:18:44 rob Exp $ +# $Id: Ping.pm,v 1.15 2001/12/26 20:55:55 rob Exp $ require 5.002; require Exporter; @@ -15,7 +15,7 @@ use Carp; @ISA = qw(Exporter); @EXPORT = qw(pingecho); -$VERSION = 2.09; +$VERSION = "2.10"; # Constants @@ -86,6 +86,8 @@ sub new $self->{"data"} .= chr($cnt % 256); } + $self->{"local_addr"} = undef; # Don't bind by default + $self->{"seq"} = 0; # For counting packets if ($self->{"proto"} eq "udp") # Open a socket { @@ -94,7 +96,7 @@ sub new $self->{"port_num"} = (getservbyname('echo', 'udp'))[2] || croak("Can't get udp echo port by name"); $self->{"fh"} = FileHandle->new(); - socket($self->{"fh"}, &PF_INET(), &SOCK_DGRAM(), + socket($self->{"fh"}, PF_INET, SOCK_DGRAM, $self->{"proto_num"}) || croak("udp socket error - $!"); } @@ -105,7 +107,7 @@ sub new croak("Can't get icmp protocol by name"); $self->{"pid"} = $$ & 0xffff; # Save lower 16 bits of pid $self->{"fh"} = FileHandle->new(); - socket($self->{"fh"}, &PF_INET(), &SOCK_RAW(), $self->{"proto_num"}) || + socket($self->{"fh"}, PF_INET, SOCK_RAW, $self->{"proto_num"}) || croak("icmp socket error - $!"); } elsif ($self->{"proto"} eq "tcp" || $self->{"proto"} eq "stream") @@ -117,10 +119,43 @@ sub new $self->{"fh"} = FileHandle->new(); } - return($self); } +# Description: Set the local IP address from which pings will be sent. +# For ICMP and UDP pings, this calls bind() on the already-opened socket; +# for TCP pings, just saves the address to be used when the socket is +# opened. Returns non-zero if successful; croaks on error. +sub bind +{ + my ($self, + $local_addr # Name or IP number of local interface + ) = @_; + my ($ip # Packed IP number of $local_addr + ); + + croak("Usage: \$p->bind(\$local_addr)") unless @_ == 2; + croak("already bound") if defined($self->{"local_addr"}) && + ($self->{"proto"} eq "udp" || $self->{"proto"} eq "icmp"); + + $ip = inet_aton($local_addr); + croak("nonexistent local address $local_addr") unless defined($ip); + $self->{"local_addr"} = $ip; # Only used if proto is tcp + + if ($self->{"proto"} eq "udp" || $self->{"proto"} eq "icmp") + { + CORE::bind($self->{"fh"}, sockaddr_in(0, $ip)) || + croak("$self->{'proto'} bind error - $!"); + } + elsif ($self->{"proto"} ne "tcp") + { + croak("Unknown protocol \"$self->{proto}\" in bind()"); + } + + return 1; +} + + # Description: Ping a host name or IP number with an optional timeout. # First lookup the host, and return undef if it is not found. Otherwise # perform the specific ping method based on the protocol. Return the @@ -165,6 +200,13 @@ sub ping_external { return Net::Ping::External::ping(ip => $ip, timeout => $timeout); } +use constant ICMP_ECHOREPLY => 0; # ICMP packet types +use constant ICMP_ECHO => 8; +use constant ICMP_STRUCT => "C2 S3 A"; # Structure of a minimal ICMP packet +use constant SUBCODE => 0; # No ICMP subcode for ECHO and ECHOREPLY +use constant ICMP_FLAGS => 0; # No special flags for send or recv +use constant ICMP_PORT => 0; # No port with ICMP + sub ping_icmp { my ($self, @@ -172,13 +214,6 @@ sub ping_icmp $timeout # Seconds after which ping times out ) = @_; - my $ICMP_ECHOREPLY = 0; # ICMP packet types - my $ICMP_ECHO = 8; - my $icmp_struct = "C2 S3 A"; # Structure of a minimal ICMP packet - my $subcode = 0; # No ICMP subcode for ECHO and ECHOREPLY - my $flags = 0; # No special flags when opening a socket - my $port = 0; # No port with ICMP - my ($saddr, # sockaddr_in with port and ip $checksum, # Checksum of ICMP packet $msg, # ICMP packet to send @@ -202,14 +237,14 @@ sub ping_icmp $self->{"seq"} = ($self->{"seq"} + 1) % 65536; # Increment sequence $checksum = 0; # No checksum for starters - $msg = pack($icmp_struct . $self->{"data_size"}, $ICMP_ECHO, $subcode, + $msg = pack(ICMP_STRUCT . $self->{"data_size"}, ICMP_ECHO, SUBCODE, $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"}); $checksum = Net::Ping->checksum($msg); - $msg = pack($icmp_struct . $self->{"data_size"}, $ICMP_ECHO, $subcode, + $msg = pack(ICMP_STRUCT . $self->{"data_size"}, ICMP_ECHO, SUBCODE, $checksum, $self->{"pid"}, $self->{"seq"}, $self->{"data"}); $len_msg = length($msg); - $saddr = sockaddr_in($port, $ip); - send($self->{"fh"}, $msg, $flags, $saddr); # Send the message + $saddr = sockaddr_in(ICMP_PORT, $ip); + send($self->{"fh"}, $msg, ICMP_FLAGS, $saddr); # Send the message $rbits = ""; vec($rbits, $self->{"fh"}->fileno(), 1) = 1; @@ -228,14 +263,14 @@ sub ping_icmp elsif ($nfound) # Got a packet from somewhere { $recv_msg = ""; - $from_saddr = recv($self->{"fh"}, $recv_msg, 1500, $flags); + $from_saddr = recv($self->{"fh"}, $recv_msg, 1500, ICMP_FLAGS); ($from_port, $from_ip) = sockaddr_in($from_saddr); ($from_type, $from_subcode, $from_chk, $from_pid, $from_seq, $from_msg) = - unpack($icmp_struct . $self->{"data_size"}, + unpack(ICMP_STRUCT . $self->{"data_size"}, substr($recv_msg, length($recv_msg) - $len_msg, $len_msg)); - if (($from_type == $ICMP_ECHOREPLY) && + if (($from_type == ICMP_ECHOREPLY) && ($from_ip eq $ip) && ($from_pid == $self->{"pid"}) && # Does the packet check out? ($from_seq == $self->{"seq"})) @@ -318,8 +353,12 @@ sub tcp_connect my $ret = 0; # Default to unreachable my $do_socket = sub { - socket($self->{"fh"}, &PF_INET(), &SOCK_STREAM(), $self->{"proto_num"}) || + socket($self->{"fh"}, PF_INET, SOCK_STREAM, $self->{"proto_num"}) || croak("tcp socket error - $!"); + if (defined $self->{"local_addr"} && + !CORE::bind($self->{"fh"}, sockaddr_in(0, $self->{"local_addr"}))) { + croak("tcp bind error - $!"); + } }; my $do_connect = sub { eval { @@ -513,6 +552,8 @@ sub open # done. Otherwise go back and wait for the message until we run out # of time. Return the result of our efforts. +use constant UDP_FLAGS => 0; # Nothing special on send or recv + sub ping_udp { my ($self, @@ -520,8 +561,6 @@ sub ping_udp $timeout # Seconds after which ping times out ) = @_; - my $flags = 0; # Nothing special on open - my ($saddr, # sockaddr_in with port and ip $ret, # The return value $msg, # Message to be echoed @@ -538,7 +577,7 @@ sub ping_udp $saddr = sockaddr_in($self->{"port_num"}, $ip); $self->{"seq"} = ($self->{"seq"} + 1) % 256; # Increment sequence $msg = chr($self->{"seq"}) . $self->{"data"}; # Add data if any - send($self->{"fh"}, $msg, $flags, $saddr); # Send it + send($self->{"fh"}, $msg, UDP_FLAGS, $saddr); # Send it $rbits = ""; vec($rbits, $self->{"fh"}->fileno(), 1) = 1; @@ -558,7 +597,7 @@ sub ping_udp elsif ($nfound) # A packet is waiting { $from_msg = ""; - $from_saddr = recv($self->{"fh"}, $from_msg, 1500, $flags) + $from_saddr = recv($self->{"fh"}, $from_msg, 1500, UDP_FLAGS) or last; # For example an unreachable host will make recv() fail. ($from_port, $from_ip) = sockaddr_in($from_saddr); if (($from_ip eq $ip) && # Does the packet check out? @@ -595,7 +634,7 @@ __END__ Net::Ping - check a remote host for reachability -$Id: Ping.pm,v 1.13 2001/12/07 02:18:44 rob Exp $ +$Id: Ping.pm,v 1.15 2001/12/26 20:55:55 rob Exp $ =head1 SYNOPSIS @@ -606,6 +645,7 @@ $Id: Ping.pm,v 1.13 2001/12/07 02:18:44 rob Exp $ $p->close(); $p = Net::Ping->new("icmp"); + $p->bind($my_addr); # Specify source interface of pings foreach $host (@host_array) { print "$host is "; @@ -692,6 +732,20 @@ default) number of data bytes is 1 if the protocol is "udp" and 0 otherwise. The maximum number of data bytes that can be specified is 1024. +=item $p->bind($local_addr); + +Sets the source address from which pings will be sent. This must be +the address of one of the interfaces on the local host. $local_addr +may be specified as a hostname or as a text IP address such as +"192.168.1.1". + +If the protocol is set to "tcp", this method may be called any +number of times, and each call to the ping() method (below) will use +the most recent $local_addr. If the protocol is "icmp" or "udp", +then bind() must be called at most once per object, and (if it is +called at all) must be called before the first call to ping() for that +object. + =item $p->ping($host [, $timeout]); Ping the remote host and wait for a response. $host can be either the @@ -778,10 +832,11 @@ routines to pack and unpack ICMP packets. It would be better for a separate module to be written which understands all of the different kinds of ICMP packets. -=head1 AUTHOR(S) +=head1 AUTHORS - Current maintainer Net::Ping base code: + Current maintainers: colinm@cpan.org (Colin McMillen) + bbb@cpan.org (Rob Brown) Stream protocol: bronson@trestle.com (Scott Bronson) @@ -793,12 +848,10 @@ kinds of ICMP packets. Original Net::Ping author: mose@ns.ccsn.edu (Russell Mosemann) - Compatibility porting: - bbb@cpan.org (Rob Brown) - =head1 COPYRIGHT Copyright (c) 2001, Colin McMillen. All rights reserved. + Copyright (c) 2001, Rob Brown. All rights reserved. This program is free software; you may redistribute it and/or diff --git a/lib/Net/Ping/CHANGES b/lib/Net/Ping/CHANGES index fb327f1..143de04 100644 --- a/lib/Net/Ping/CHANGES +++ b/lib/Net/Ping/CHANGES @@ -1,6 +1,14 @@ CHANGES ------- +2.10 Dec 26 12:00 2001 + - Added bind() function useful for clients with multiple + network interfaces performing the ping check thanks to + sethb@clarkhill.com (Seth Blumberg). + - Execution optimizations for several constants (Seth). + - More test changes in case Socket module is not available + (Jarkko Hietaniemi). + 2.09 Dec 06 19:00 2001 - Documental and test changes only. - No functional changes. diff --git a/lib/Net/Ping/t/100_load.t b/lib/Net/Ping/t/100_load.t index eff67e3..de84247 100644 --- a/lib/Net/Ping/t/100_load.t +++ b/lib/Net/Ping/t/100_load.t @@ -4,10 +4,10 @@ ######################### We start with some black magic to print on failure. BEGIN { - unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; - exit; - } + unless (eval "require Socket") { + print "1..0 \# Skip: no Socket\n"; + exit; + } } use Test; diff --git a/lib/Net/Ping/t/110_icmp_inst.t b/lib/Net/Ping/t/110_icmp_inst.t index c358dac..c617135 100644 --- a/lib/Net/Ping/t/110_icmp_inst.t +++ b/lib/Net/Ping/t/110_icmp_inst.t @@ -2,10 +2,10 @@ # Root access is required to actually perform icmp testing. BEGIN { - unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; - exit; - } + unless (eval "require Socket") { + print "1..0 \# Skip: no Socket\n"; + exit; + } } use Test; diff --git a/lib/Net/Ping/t/120_udp_inst.t b/lib/Net/Ping/t/120_udp_inst.t index e4a39e4..0dc64ad 100644 --- a/lib/Net/Ping/t/120_udp_inst.t +++ b/lib/Net/Ping/t/120_udp_inst.t @@ -2,10 +2,10 @@ # I do not know of any servers that support udp echo anymore. BEGIN { - unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; - exit; - } + unless (eval "require Socket") { + print "1..0 \# Skip: no Socket\n"; + exit; + } } use Test; diff --git a/lib/Net/Ping/t/130_tcp_inst.t b/lib/Net/Ping/t/130_tcp_inst.t index a7cc1d2..af6ddaa 100644 --- a/lib/Net/Ping/t/130_tcp_inst.t +++ b/lib/Net/Ping/t/130_tcp_inst.t @@ -1,10 +1,10 @@ # Test to make sure object can be instantiated for tcp protocol. BEGIN { - unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; - exit; - } + unless (eval "require Socket") { + print "1..0 \# Skip: no Socket\n"; + exit; + } } use Test; diff --git a/lib/Net/Ping/t/140_stream_inst.t b/lib/Net/Ping/t/140_stream_inst.t index db35a88..ce1b9e6 100644 --- a/lib/Net/Ping/t/140_stream_inst.t +++ b/lib/Net/Ping/t/140_stream_inst.t @@ -1,10 +1,10 @@ # Test to make sure object can be instantiated for stream protocol. BEGIN { - unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; - exit; - } + unless (eval "require Socket") { + print "1..0 \# Skip: no Socket\n"; + exit; + } } use Test; diff --git a/lib/Net/Ping/t/200_ping_tcp.t b/lib/Net/Ping/t/200_ping_tcp.t index f257b0d..6fbd78b 100644 --- a/lib/Net/Ping/t/200_ping_tcp.t +++ b/lib/Net/Ping/t/200_ping_tcp.t @@ -8,7 +8,7 @@ BEGIN { @INC = qw(../lib); } unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; + print "1..0 \# Skip: no Socket\n"; exit; } } diff --git a/lib/Net/Ping/t/300_ping_stream.t b/lib/Net/Ping/t/300_ping_stream.t index 381e08b..b60a500 100644 --- a/lib/Net/Ping/t/300_ping_stream.t +++ b/lib/Net/Ping/t/300_ping_stream.t @@ -8,7 +8,7 @@ BEGIN { @INC = qw(../lib); } unless (eval "require Socket") { - print "1..0 # Skip: no Socket\n"; + print "1..0 \# Skip: no Socket\n"; exit; } } @@ -57,3 +57,8 @@ service echo server = /bin/cat disable = no } + +Or if you are using inetd, before restarting, add +this line to your /etc/inetd.conf: + +echo stream tcp nowait root internal