RFC: Net/Ping

Hi all,

This is a fairly simple Ruby version of ‘ping’, based somewhat on the Perl module of the same name.
Please let me know what you think and if there are any obvious problems.

I haven’t implemented an ICMP ping yet, mainly because it’s a pain and you have to be root to use it
anyway. Any help in that area is appreciated, though.

Oh, and before anyone complains about a lack of options, see “Unix Network Programming”, p.661 and note
the authors comments about “feature creep”. :slight_smile:

Regards,

Dan

require "socket"
require “timeout”

module Net
class Ping
attr_accessor :host, :port, :time, :data, :exception
def initialize(host,port=nil,time=5)
@host = host
@port = port || Socket.getservbyname(“echo”)
@time = time
@data = "ping"
end
end

···

##########################################################################

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 PingTCP < Ping
def ping
begin
timeout(@time){
begin
t = TCPSocket.new(@host,@port)
rescue
@exception = $!
t.close unless t.nil?
return false
else
t.close
return true
end
}
rescue
@exception = $!
return false
end
end
end

##########################################################################

With a UDP ping, send a simple text string and check the return string.

If they match, assume success.

##########################################################################
class PingUDP < Ping

  def ping
     u = UDPSocket.open
     a = []
     begin
        timeout(@time){
           u.connect(@host,@port)
           u.send(@data,0)
           a = u.recvfrom(64)
        }
        if a[0] != @data
           return false
        end
     rescue
        @exception = $!
        return false
     else
        return true
     end
  end

end

##################################

Use your system’s ping command

##################################
class PingExternal < Ping
require "open3"
def ping
input, output, error = ""
timeout(@timeout){
input,output,error = Open3.popen3(“ping -c 1 #{@host}”)
}
e = error.gets
unless e.nil?
@exception = e
return false
else
return true
end
end
end

end

=begin
= Description
net/ping - A simple version of “ping” using Ruby
= Synopsis
require ‘net/ping’

check with udp or tcp ping

t = Net::PingTCP.new(host)
u = Net::PingUDP.new(host)
e = Net::PingExternal.new(host)

if t.ping
puts "Host is alive"
else
puts “Couldn’t connect to host: " + t.exception
end
= Ping Classes
— PingTCP
Attempts to open a connection using TCPSocket. A successful open means
the ping was successful.
— PingUDP
Attempts to open a connection using UDPSocket and sends a small string. If
the return string matches, the ping was successful.
— PingExternal
Uses the ‘open3’ module and calls your system’s local ‘ping’ command. If
nothing is sent to stderr, the ping was successful.
= Class Methods
— new(host,port=7,timeout=5)
Creates a new Ping object of the appropriate type
= Instance Methods
— ping
Returns one of two values - true or false. If you want to know why it
failed, you can check the ‘exception’ attribute.
= Instance Attributes
— host
Reset the host
— port
Set the port number to open socket connections on. The default is 7 (or
whatever your ‘echo’ port is set to).
— data
The string sent in UDP connections. The default is “ping”.
— timeout
The amount of time before the timeout module raises a TimeoutError
exception during connection attempts.
— exception
If an exception is raised, it is caught and stored in this attribute. It
is not raised in your code.
= FAQ
"Why don’t you return exceptions if a connection fails?” - Because ping is
only meant to return one of two things - success or failure. It’s very
simple. If you want to find out why the ping failed, you can check the
’exception’ attribute.
= Known Bugs
None that I’m aware of. If you find any, please let me know!
= Future Plans
Add an PingICMP class (help wanted)
= Author
Daniel J. Berger
djberg96 at hotmail dot com
=end