103 lines
2.8 KiB
Ruby
103 lines
2.8 KiB
Ruby
|
require File.join(File.dirname(__FILE__), 'ping')
|
||
|
|
||
|
# The Net module serves as a namespace only.
|
||
|
module Net
|
||
|
|
||
|
# With a TCP ping simply try to open a connection. If we are successful,
|
||
|
# assume success. In either case close the connection to be polite.
|
||
|
#
|
||
|
class Ping::TCP < Ping
|
||
|
@@service_check = false
|
||
|
|
||
|
# Returns whether or not Errno::ECONNREFUSED is considered a successful
|
||
|
# ping. The default is false.
|
||
|
#
|
||
|
def self.service_check
|
||
|
@@service_check
|
||
|
end
|
||
|
|
||
|
# Sets whether or not an Errno::ECONNREFUSED should be considered a
|
||
|
# successful ping.
|
||
|
#
|
||
|
def self.service_check=(bool)
|
||
|
unless bool.kind_of?(TrueClass) || bool.kind_of?(FalseClass)
|
||
|
raise ArgumentError, 'argument must be true or false'
|
||
|
end
|
||
|
@@service_check = bool
|
||
|
end
|
||
|
|
||
|
# This method attempts to ping a host and port using a TCPSocket with
|
||
|
# the host, port and timeout values passed in the constructor. Returns
|
||
|
# true if successful, or false otherwise.
|
||
|
#
|
||
|
# Note that, by default, an Errno::ECONNREFUSED return result will be
|
||
|
# considered a failed ping. See the documentation for the
|
||
|
# Ping::TCP.service_check= method if you wish to change this behavior.
|
||
|
#
|
||
|
def ping(host=@host)
|
||
|
super(host)
|
||
|
|
||
|
bool = false
|
||
|
start_time = Time.now
|
||
|
|
||
|
# Failure here most likely means bad host, so just bail.
|
||
|
begin
|
||
|
addr = Socket.getaddrinfo(host, port)
|
||
|
rescue SocketError => err
|
||
|
@exception = err
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
begin
|
||
|
# Where addr[0][0] is likely AF_INET.
|
||
|
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
||
|
|
||
|
# This may not be entirely necessary
|
||
|
sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||
|
|
||
|
begin
|
||
|
# Where addr[0][3] is an IP address
|
||
|
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
|
||
|
rescue Errno::EINPROGRESS
|
||
|
# No-op, continue below
|
||
|
rescue Exception => err
|
||
|
# Something has gone horribly wrong
|
||
|
@exception = err
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
resp = IO.select(nil, [sock], nil, timeout)
|
||
|
|
||
|
# Assume ECONNREFUSED at this point
|
||
|
if resp.nil?
|
||
|
if @@service_check
|
||
|
bool = true
|
||
|
else
|
||
|
@exception = Errno::ECONNREFUSED
|
||
|
end
|
||
|
else
|
||
|
bool = true
|
||
|
end
|
||
|
ensure
|
||
|
sock.close if sock
|
||
|
end
|
||
|
|
||
|
# There is no duration if the ping failed
|
||
|
@duration = Time.now - start_time if bool
|
||
|
|
||
|
bool
|
||
|
end
|
||
|
|
||
|
alias ping? ping
|
||
|
alias pingecho ping
|
||
|
|
||
|
# Class method aliases. DEPRECATED.
|
||
|
class << self
|
||
|
alias econnrefused service_check
|
||
|
alias econnrefused= service_check=
|
||
|
alias ecr service_check
|
||
|
alias ecr= service_check=
|
||
|
end
|
||
|
end
|
||
|
end
|