Skip to content
Browse files

Initial conversion to git.

  • Loading branch information...
0 parents commit 18e6e23f572577cf21fe8279fa34fd4771b7d7da @djberg96 committed Jan 5, 2010
178 CHANGES
@@ -0,0 +1,178 @@
+== 1.3.2 - 21-Sep-2009
+* Doing a 'require "net/ping"' was not automatically loading the
+ Net::Ping::WMI class on MS Windows. This has been fixed. Thanks go to
+ Joseph M. for the spot.
+* Removed all $LOAD_PATH mangling for both the library and tests.
+* Fixed a bug in the Net::Ping::HTTP class where a failed redirect did
+ not set the @exception and @warning instance variables properly.
+* The PingStatus struct returned by Net::Ping::WMI is now frozen.
+* The test-unit library was switched from a runtime dependency to a
+ development dependency.
+* Added the :gem Rake task that builds a gem.
+* Updated the :gem_install task to use the :gem task as a prerequisite.
+* Updated the dependencies for MS Windows.
+* The Rake test tasks are now more Rakish, e.g. test:tcp instead of test_tcp.
+* Renamed example file names to avoid any potential confusion with actual
+ test files.
+
+== 1.3.1 - 22-Jul-2009
+* Removed class aliases, e.g. use Ping::External, not PingExternal.
+* Minor code change to eliminate a warning that popped up in 1.9.x.
+* The win32-open3 library is removed as a dependency for Ruby 1.9.x.
+* Changed license to Artistic 2.0.
+* Some gemspec and README updates.
+
+== 1.3.0 - 19-May-2009
+* Added the Ping::WMI class for MS Windows. This class encapsulates the
+ Win32_PingStatus WMI class. Unlike other ping methods, this one returns
+ a struct that contains various bits of information.
+* The Net::Ping::External class now ensures that handles opened by the open3
+ call are closed. Thanks go to Nick S. Kanakakorn for the spot and a
+ preliminary patch.
+* The Net::Ping::ICMP class now explicitly closes the socket if the call to
+ the Socket.pack_sockaddr_in method fails.
+* Some documentation updates.
+
+== 1.2.3 - 13-Jan-2008
+* Fixed a bug in the checksum private method where it would die on odd data
+ sizes. Thanks go to Jake Douglas for the spot.
+* A Socket.get_sockaddr_in call in the Ping::ICMP class is no longer included
+ as part of the overall ping time. Thanks go again to Jake Douglas for
+ the spot.
+* Added data_size tests to the Ping::ICMP test suite.
+* Renamed and updated the test files. The test-unit 2.x gem is now a
+ prerequisite as a result.
+
+== 1.2.2 - 22-Jan-2008
+* Bug fix for Ping::External where it was not honoring the timeout value.
+ Thanks go to Chris Morris for the spot and the patch.
+* Bug fix for Ping::External where non-English output could cause false
+ positives on MS Windows Vista or later. This library now requires the
+ windows-pr library on MS Windows systems as a result.
+* Added the Ping::UDP.service_check and Ping::UDP.service_check= class
+ methods. This method controls whether or not Errno::ECONNREFUSED or
+ Errno::ECONNRESET are considered successful pings or not.
+* The Ping::HTTP class no longer uses the resolv-replace library on MS Windows
+ because it was (ironically) causing timeouts.
+* Changed the Ping::TCP.econnrefused method to Ping::TCP.service_check. I
+ changed it because I now use a similar method in Ping::UDP, but that handles
+ more than Errno::ECONNREFUSED. An alias is provided to provide backwards
+ compatibility, but it is considered deprecated and will be removed in the
+ 1.3.0 release.
+* Removed the install.rb file. The Rakefile now handles installation.
+
+== 1.2.1 - 6-Apr-2007
+* For the Ping::External class, if a ping attempt results in 100% packet loss
+ it is now considered a failed ping, regardless of whether or not an error
+ was sent to stdout.
+* Fixed the Ping::External class for OS X.
+* Added a Rakefile. Installation and testing should now be run via Rake tasks.
+* Minor fix for the Ping::ICMP class where I had accidentally dup'd some
+ aliases. This was harmless, but did cause warnings with -w.
+
+== 1.2.0 - 5-Dec-2006
+* Internal reorganization - each class now lives in its own file.
+* Added the Ping::ICMP class. Thanks go to Jos Backus for contributing a
+ large part of the code.
+* The host argument is now optional in the constructor. You can now specify
+ it in the ping method instead. Note that it must be specified in one place
+ or the other.
+* Each PingXXX class is now Ping::XXX instead. However, class name aliases
+ have been setup for backwards compatibility for now.
+* The constructor for each Ping types now yields self.
+* Added the pingecho alias for the ping method for each Ping type.
+* Added the Ping::HTTP#follow_redirect accessor.
+* The Ping::HTTP#ping method now honors the timeout value.
+* The Ping::HTTP class now follows redirects automatically, though this is
+ configurable with the follow_redirect accessor.
+* The Ping::TCP.ecr and Ping::TCP.ecr= methods are now true class method
+ aliases (they were just wrappers previously).
+* The Ping::UDP class now enforces a 64 character limit on data that can be
+ sent on a udp ping.
+* Updated the gemspec. Specifically, MS Windows now has a dependency on
+ the win32-open3 package.
+* Added inline rdoc.
+
+== 1.1.1 - 15-Jun-2006
+* Fixed a bug in PingTCP (bad variable name). Thanks go to Anoop Chandran
+ for the spot.
+* Minor variable name refactoring.
+* Minor test updates.
+
+== 1.1.0 - 17-Jul-2005
+* Fixed a bug in the PingHTTP#ping method where I was accidentally passing
+ the timeout value instead of the port number as the third argument to
+ Net::HTTP.get_response.
+* The PingHTTP.new method now has a default port of 80.
+* Minor doc update for PingHTTP.new.
+
+== 1.0.1 - 22-Jun-2005
+* Bug fix for the install.rb file. The gem is unaffected.
+
+== 1.0.0 - 14-Jun-2005
+* Renamed project from net-pingsimple to just net-ping.
+* Added a PingHTTP subclass.
+* Moved project to RubyForge.
+* Added a gemspec.
+
+== 0.3.1 - 9-Apr-2005
+* Updated PingExternal to use win32/open3 on Win32 platforms.
+* Minor error handling change for the PingSimple.econnrefused= method. It now
+ raises an ArgumentError if any values other than true or false are passed.
+* PingSimple#warning and PingSimple#exception are now read-only methods.
+* The warning and exception attributes are now reset to nil between each call
+ to ping.
+* The data and data= methods are now unique to the PingUDP class.
+* The time and time= methods have been changed to timeout and timeout=,
+ respectively.
+* Removed the pingsimple.rd and pingsimple.html files. The pingsimple.txt file
+ has been reorganized and is now rdoc friendly.
+* Added a few sample programs under the 'examples' directory.
+* Some minor test updates and changes.
+* Removed the INSTALL file. That information is now in the README file.
+* Now requires Ruby 1.8.0 or later.
+
+== 0.3.0 - 12-Feb-2004
+* Fixed ping string for PingExternal class based on platform. The old
+ string was really only good for Linux and *BSD.
+* Added Win32 support (requires win32_popen package).
+* Added warranty info.
+
+== 0.2.3 - 12-Aug-2003
+* Fixed a bug in PingExternal that could consume file descriptors if used in a loop
+* Added some initialization to avoid -w warnings
+* Removed VERSION() class method. Use the constant instead
+* Modified test suite slightly
+* Moved rd2 docs to doc directory
+
+== 0.2.2 - 3-Apr-2003
+* Fixed handling of stdout in PingExternal
+
+== 0.2.1 - 27-Mar-2003
+* Fixed major bug with PingExternal class with regards to down hosts
+* Exceptions and warnings from PingExternal are now chomp'd
+* Modified test suite
+* Doc updates
+
+== 0.2.0 - 14-Feb-2003
+* The default behavior of PingTCP with regards to ECONNREFUSED is now
+ configurable
+* Added a VERSION constant and method (to the base class)
+* Added a test suite (for those with testunit installed)
+* Doc changes, rearrangement and general cleanup
+* Manifest is now MANIFEST
+* Added an INSTALL file
+
+== 0.1.0 - 9-Dec-2002
+* Added ping? alias for ping method
+* Warnings now handled separately
+* Corrected a mis-named variable in Ping::External
+* Fixed the install.rb file
+* Updated and added docs
+* Renamed tarball to net-pingsimple to reflect RAA naming convention
+
+== 0.0.1a
+* Did this release ever happen?
+
+== 0.0.1
+* Initial release.
23 MANIFEST
@@ -0,0 +1,23 @@
+* MANIFEST
+* CHANGES
+* Rakefile
+* README
+* net-ping.gemspec
+* examples/example_pingexternal.rb
+* examples/example_pinghttp.rb
+* examples/example_pingtcp.rb
+* examples/example_pingudp.rb
+* lib/net/ping.rb
+* lib/net/ping/icmp.rb
+* lib/net/ping/tcp.rb
+* lib/net/ping/udp.rb
+* lib/net/ping/wmi.rb
+* lib/net/ping/http.rb
+* lib/net/ping/external.rb
+* test/test_net_ping_external.rb
+* test/test_net_ping_http.rb
+* test/test_net_ping_icmp.rb
+* test/test_net_ping_tcp.rb
+* test/test_net_ping_udp.rb
+* test/test_net_ping_wmi.rb
+* test/test_net_ping.rb
50 README
@@ -0,0 +1,50 @@
+== Description
+ A collection of classes that provide different ways to ping computers.
+
+== Prerequisites
+ * Ruby 1.8.0 or later
+ * The win32-open3 (1.8.x) and windows-pr libraries are required on
+ MS Windows when using the Net::Ping::External class.
+ * Windows 2000 or later is required to use the Ping::WMI class.
+
+== Installation
+=== Remote Installation
+ gem install net-ping
+
+=== Local Installation
+ rake test (optional)
+ rake install (standard) OR rake gem_install (gems)
+
+== Notes
+ Please read the documentation under the 'doc' directory. Especially pay
+ attention to the documentation pertaining to ECONNREFUSED and TCP pings.
+
+ Also note the documentation regarding down hosts.
+
+ You do not need win32-open3 with Ruby 1.9.x. The open3 library that ships
+ as part of the Ruby standard library should work.
+
+== How to require net-ping
+ You can do either this:
+
+ require 'net/ping'
+
+ In which case you will get Net::Ping and all of its subclasses. Or,
+ you can load individual subclasses like this:
+
+ require 'net/ping/tcp'
+
+ The former has the advantage of being easier to remember and all inclusive,
+ not to mention backwards compatible. The latter has the advantage of
+ reducing your memory footprint.
+
+== Known Issues
+ Older versions of Ruby 1.9.x may not work with UDP pings.
+
+== License
+ Artistic 2.0
+
+== More documentation
+ If you installed this library via Rubygems, you can view the inline
+ documentation via ri or fire up 'gem server', and point your browser at
+ http://localhost:8808.
97 Rakefile
@@ -0,0 +1,97 @@
+require 'rake'
+require 'rake/testtask'
+include Config
+
+desc "Install the net-ping package (non-gem)"
+task :install do
+ dest1 = File.join(CONFIG['sitelibdir'], 'net')
+ dest2 = File.join(dest1, 'ping')
+
+ Dir.mkdir(dest1) unless File.exists?(dest1)
+ Dir.mkdir(dest2) unless File.exists?(dest2)
+
+ FileUtils.cp('lib/net/ping.rb', dest1, :verbose => true)
+
+ Dir['lib/net/ping/*.rb'].each{ |file|
+ FileUtils.cp(file, dest2, :verbose => true)
+ }
+end
+
+desc 'Create and install the net-ping gem'
+task :gem_install => [:gem] do
+ gem_file = Dir["*.gem"].first
+ sh "gem install #{gem_file}"
+end
+
+desc 'Create the net-ping gem'
+task :gem do
+ spec = eval(IO.read('net-ping.gemspec'))
+ Gem::Builder.new(spec).build
+end
+
+namespace 'example' do
+ desc 'Run the external ping example program'
+ task :external do
+ ruby '-Ilib examples/example_pingexternal.rb'
+ end
+
+ desc 'Run the http ping example program'
+ task :http do
+ ruby '-Ilib examples/example_pinghttp.rb'
+ end
+
+ desc 'Run the tcp ping example program'
+ task :tcp do
+ ruby '-Ilib examples/example_pingtcp.rb'
+ end
+
+ desc 'Run the udp ping example program'
+ task :udp do
+ ruby '-Ilib examples/example_pingudp.rb'
+ end
+end
+
+Rake::TestTask.new do |t|
+ t.libs << 'test'
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping.rb']
+end
+
+namespace 'test' do
+ Rake::TestTask.new('external') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_external.rb']
+ end
+
+ Rake::TestTask.new('http') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_http.rb']
+ end
+
+ Rake::TestTask.new('icmp') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_icmp.rb']
+ end
+
+ Rake::TestTask.new('tcp') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_tcp.rb']
+ end
+
+ Rake::TestTask.new('udp') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_udp.rb']
+ end
+
+ Rake::TestTask.new('wmi') do |t|
+ t.warning = true
+ t.verbose = true
+ t.test_files = FileList['test/test_net_ping_wmi.rb']
+ end
+end
251 doc/ping.txt
@@ -0,0 +1,251 @@
+= Description
+ A simple Ruby interface to the 'ping' command.
+
+= Synopsis
+ require 'net/ping'
+ include Net
+
+ Ping::TCP.service_check = true
+
+ pt = Net::Ping::TCP.new(host)
+ pu = Net::Ping::UDP.new(host)
+ pe = Net::Ping::External.new(host)
+ ph = Net::Ping::HTTP.new(uri)
+
+ if pt.ping
+ puts "TCP ping successful"
+ else
+ puts "TCP ping unsuccessful: " + pt.exception
+ end
+
+ if pu.ping
+ puts "UDP ping successful"
+ else
+ puts "UDP ping unsuccessful: " + pu.exception
+ end
+
+ if pe.ping
+ puts "External ping successful"
+ else
+ puts "External ping unsuccessful: " + pe.exception
+ end
+
+ if ph.ping?
+ puts "HTTP ping successful"
+ else
+ puts "HTTP ping unsuccessful: " + ph.exception
+ end
+
+= Ping Classes
+ * Ping::TCP
+ * Ping::UDP
+ * Ping::External
+ * Ping::HTTP
+ * Ping::ICMP
+ * Ping::WMI
+
+ All Ping classes are children of the Ping parent class (which should
+ never be instantiated directly).
+
+ The Ping::ICMP class requires root privileges on UNIX systems.
+
+ The Ping::WMI class only works on MS Windows.
+
+== Net::Ping
+Net::Ping.new(host=nil, port=7, timeout=5)
+ Creates and returns a new Ping object. If the host is not specified
+ in the constructor then it must be specified in the ping method.
+
+== Net::Ping::TCP
+Ping::TCP.service_check
+ Returns the setting for how ECONNREFUSED is handled. By default, this is
+ set to false, i.e. an ECONNREFUSED error is considered a failed ping.
+
+Ping::TCP.service_check=(bool)
+ Sets the behavior for how ECONNREFUSED is handled. By default, this is
+ set to false, i.e. an ECONNREFUSED error is considered a failed ping.
+
+Ping::TCP#ping(host=nil)
+ Attempts to open a connection using TCPSocket with a +host+ specified
+ either here or in the constructor. A successful open means the ping was
+ successful and true is returned. Otherwise, false is returned.
+
+== Net::Ping::UDP
+Ping::UDP#ping
+ Attempts to open a connection using UDPSocket and sends the value of
+ Ping::UDP#data as a string across the socket. If the return string matches,
+ then the ping was successful and true is returned. Otherwise, false is
+ returned.
+
+Ping::UDP#data
+ Returns the string that is sent across the UDP socket.
+
+Ping::UDP#data=(string)
+ Sets the string that is sent across the UDP socket. The default is "ping".
+ Note that the +string+ cannot be larger than MAX_DATA (64 characters).
+
+== Net::Ping::External
+Ping::External#ping
+ Uses the 'open3' module and calls your system's local 'ping' command with
+ various options, depending on platform. If nothing is sent to stderr, the
+ ping was successful and true is returned. Otherwise, false is returned.
+
+ The MS Windows platform requires the 'win32-open3' package.
+
+== Ping::HTTP
+Ping::HTTP.new(uri=nil, port=80, timeout=5)
+ Identical to Net::Ping.new except that, instead of a host, the first
+ argument is a URI.
+
+Ping::HTTP#ping
+ Checks for a response against +uri+. As long as kind of Net::HTTPSuccess
+ response is returned, the ping is successful and true is returned.
+ Otherwise, false is returned and Ping::HTTP#exception is set to the error
+ message.
+
+ Note that redirects are automatically followed unless the
+ Ping::HTTP#follow_redirects method is set to false.
+
+Ping::HTTP#follow_redirect
+ Indicates whether or not a redirect should be followed in a ping attempt.
+ By default this is set to true.
+
+Ping::HTTP#follow_redirect=(bool)
+ Sets whether or not a redirect should be followed in a ping attempt. If
+ set to false, then any redirect is considered a failed ping.
+
+Ping::HTTP#uri
+ An alias for Ping::HTTP#host.
+
+Ping::HTTP#uri=(uri)
+ An alias for Ping::HTTP#host=.
+
+== Ping::ICMP
+Ping::ICMP#duration
+ The time it took to ping the host. Not a precise value but a good estimate.
+
+== Ping::WMI
+Ping::WMI#ping(host, options={})
+ Unlike other Ping classes, this method returns a PingStatus struct that
+ contains various bits of information about the ping itself. The PingStatus
+ struct is a wrapper for the Win32_PingStatus WMI class.
+
+ In addition, you can pass options that will be interpreted as WQL parameters.
+
+Ping::WMI#ping?(host, options={})
+ Returns whether or not the ping succeeded.
+
+= Common Instance Methods
+Ping#exception
+ Returns the error string that was set if a ping call failed. If an exception
+ is raised, it is caught and stored in this attribute. It is not raised in
+ your code.
+
+ This should be nil if the ping succeeded.
+
+Ping#host
+ Returns the host name that ping attempts will ping against.
+
+Ping#host=(hostname)
+ Sets the host name that ping attempts will ping against.
+
+Ping#port
+ Returns the port number that ping attempts will use.
+
+Ping#port=(port)
+ Set the port number to open socket connections on. The default is 7 (or
+ whatever your 'echo' port is set to). Note that you can also specify a
+ string, such as "http".
+
+Ping#timeout
+ Returns the amount of time before the timeout module raises a TimeoutError
+ during connection attempts. The default is 5 seconds.
+
+Ping#timeout=(time)
+ Sets the amount of time before the timeout module raises a TimeoutError.
+ during connection attempts.
+
+Ping#warning
+ Returns a warning string that was returned during the ping attempt. This
+ typically occurs only in the Ping::External class, or the Ping::HTTP class
+ if a redirect occurred.
+
+== Notes
+ If a host is down *IT IS CONSIDERED A FAILED PING*, and the 'no answer from
+ +host+' text is assigned to the 'exception' attribute. You may disagree with
+ this behavior, in which case you need merely check the exception attribute
+ against a regex as a simple workaround.
+
+== Pre-emptive FAQ
+ Q: "Why don't you return exceptions if a connection fails?"
+
+ A: 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.
+
+ Q: "I know the host is alive, but a TCP or UDP ping tells me otherwise. What
+ gives?"
+
+ A: It's possible that the echo port has been disabled on the remote
+ host for security reasons. Your best best is to specify a different port
+ or to use Ping::ICMP or Ping::External instead.
+
+ In the case of UDP pings, they are often actively refused. It may be
+ more pragmatic to set Ping::UDP.service_check = false.
+
+ Q: "Why does a TCP ping return false when I know it should return true?"
+
+ A: By default ECONNREFUSED errors will return a value of false. This is
+ contrary to what most other folks do for TCP pings. The problem with
+ their philosophy is that you can get false positives if a firewall blocks
+ the route to the host. The problem with my philosophy is that you can
+ get false negatives if there is no firewall (or it's not blocking the
+ route). Given the alternatives I chose the latter.
+
+ You can always change the default behavior by using the +service_check+
+ class method.
+
+ A similar situation is true for UDP pings.
+
+ Q: "Couldn't you use traceroute information to tell for sure?"
+
+ A: I could but I won't so don't bug me about it. It's far more effort than
+ it's worth. If you want something like that, please port the
+ Net::Traceroute Perl module by Daniel Hagerty.
+
+= Known Bugs
+ You may see a test failure from the test_net_ping_tcp test case. You can
+ ignore these.
+
+ The socket library that ships with the Windows One-Click installer has
+ known issues. This may cause the Ping::ICMP class to fail. In fact, I
+ make an effort to skip those tests if I detect the one-click installer.
+
+ UDP pings may not work with older versions of Ruby 1.9.x.
+
+ Please report any bugs on the project page at
+ http://www.rubyforge.org/projects/shards.
+
+= Acknowledgements
+ The Ping::ICMP#ping method is based largely on the identical method from
+ the Net::Ping Perl module by Rob Brown. Much of the code was ported by
+ Jos Backus on ruby-talk.
+
+= Future Plans
+ Add support for syn pings.
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger, All Rights Reserved
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
+ djberg96 at gmail dot com
+ imperator on IRC (irc.freenode.net)
16 examples/example_pingexternal.rb
@@ -0,0 +1,16 @@
+########################################################################
+# example_pingexternal.rb
+#
+# A short sample program demonstrating an external ping. You can run
+# this program via the example:external task. Modify as you see fit.
+########################################################################
+require 'net/ping'
+
+good = 'www.rubyforge.org'
+bad = 'foo.bar.baz'
+
+p1 = Net::Ping::External.new(good)
+p p1.ping?
+
+p2 = Net::Ping::External.new(bad)
+p p2.ping?
22 examples/example_pinghttp.rb
@@ -0,0 +1,22 @@
+########################################################################
+# example_pinghttp.rb
+#
+# A short sample program demonstrating an http ping. You can run
+# this program via the example:http task. Modify as you see fit.
+########################################################################
+require 'net/ping'
+
+good = 'http://www.google.com/index.html'
+bad = 'http://www.ruby-lang.org/index.html'
+
+puts "== Good ping, no redirect"
+
+p1 = Net::Ping::HTTP.new(good)
+p p1.ping?
+
+puts "== Bad ping"
+
+p2 = Net::Ping::HTTP.new(bad)
+p p2.ping?
+p p2.warning
+p p2.exception
16 examples/example_pingtcp.rb
@@ -0,0 +1,16 @@
+########################################################################
+# example_pingtcp.rb
+#
+# A short sample program demonstrating a tcp ping. You can run
+# this program via the example:tcp task. Modify as you see fit.
+########################################################################
+require 'net/ping'
+
+good = 'www.google.com'
+bad = 'foo.bar.baz'
+
+p1 = Net::Ping::TCP.new(good, 'http')
+p p1.ping?
+
+p2 = Net::Ping::TCP.new(bad)
+p p2.ping?
12 examples/example_pingudp.rb
@@ -0,0 +1,12 @@
+########################################################################
+# example_pingudp.rb
+#
+# A short sample program demonstrating a UDP ping. You can run
+# this program via the example:udp task. Modify as you see fit.
+########################################################################
+require 'net/ping'
+
+host = 'www.google.com'
+
+u = Net::Ping::UDP.new(host)
+p u.ping?
15 lib/net/ping.rb
@@ -0,0 +1,15 @@
+# By doing a "require 'net/ping'" you are requiring every subclass. If you
+# want to require a specific ping type only, do "require 'net/ping/tcp'",
+# for example.
+#
+require 'rbconfig'
+
+require File.join(File.dirname(__FILE__), 'ping/tcp')
+require File.join(File.dirname(__FILE__), 'ping/udp')
+require File.join(File.dirname(__FILE__), 'ping/icmp')
+require File.join(File.dirname(__FILE__), 'ping/external')
+require File.join(File.dirname(__FILE__), 'ping/http')
+
+if Config::CONFIG['host_os'] =~ /dos|mswin|cygwin|mingw|win32/i
+ require File.join(File.dirname(__FILE__), 'ping/wmi')
+end
119 lib/net/ping/external.rb
@@ -0,0 +1,119 @@
+require 'rbconfig'
+require File.join(File.dirname(__FILE__), 'ping')
+
+if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
+ if RUBY_VERSION.to_f < 1.9
+ require 'win32/open3'
+ end
+ require 'windows/console'
+else
+ require 'open3'
+end
+
+# The Net module serves as a namespace only.
+module Net
+
+ # The Ping::External class encapsulates methods for external (system) pings.
+ class Ping::External < Ping
+
+ if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
+ include Windows::Console
+ end
+
+ # Pings the host using your system's ping utility and checks for any
+ # errors or warnings. Returns true if successful, or false if not.
+ #
+ # If the ping failed then the Ping::External#exception method should
+ # contain a string indicating what went wrong. If the ping succeeded then
+ # the Ping::External#warning method may or may not contain a value.
+ #
+ def ping(host = @host)
+ super(host)
+
+ input, output, error = ""
+ pstring = "ping "
+ bool = false
+ orig_cp = nil
+
+ case Config::CONFIG['host_os']
+ when /linux|bsd|osx|mach|darwin/i
+ pstring += "-c 1 #{host}"
+ when /solaris|sunos/i
+ pstring += "#{host} 1"
+ when /hpux/i
+ pstring += "#{host} -n 1"
+ when /win32|windows|mswin/i
+ orig_cp = GetConsoleCP()
+ SetConsoleCP(437) if orig_cp != 437 # United States
+ pstring += "-n 1 #{host}"
+ else
+ pstring += "#{host}"
+ end
+
+ start_time = Time.now
+
+ begin
+ e = nil
+
+ Timeout.timeout(@timeout){
+ input, output, error = Open3.popen3(pstring)
+ e = error.gets # Can't chomp yet, might be nil
+ }
+
+ input.close
+ error.close
+
+ if Config::CONFIG['host_os'] =~ /mswin|win32|dos/i &&
+ GetConsoleCP() != orig_cp
+ then
+ SetConsoleCP(orig_cp)
+ end
+
+ unless e.nil?
+ if e =~ /warning/i
+ @warning = e.chomp
+ bool = true
+ else
+ @exception = e.chomp
+ end
+ # The "no answer" response goes to stdout, not stderr, so check it
+ else
+ lines = output.readlines
+ output.close
+ if lines.nil? || lines.empty?
+ bool = true
+ else
+ regexp = /
+ no\ answer|
+ host\ unreachable|
+ could\ not\ find\ host|
+ request\ timed\ out|
+ 100%\ packet\ loss
+ /ix
+ lines.each{ |line|
+ if regexp.match(line)
+ @exception = line.chomp
+ break
+ end
+ }
+ bool = true unless @exception
+ end
+ end
+ rescue Exception => err
+ @exception = err.message
+ ensure
+ input.close if input && !input.closed?
+ error.close if error && !error.closed?
+ output.close if output && !output.closed?
+ end
+
+ # There is no duration if the ping failed
+ @duration = Time.now - start_time if bool
+
+ bool
+ end
+
+ alias ping? ping
+ alias pingecho ping
+ end
+end
95 lib/net/ping/http.rb
@@ -0,0 +1,95 @@
+require File.join(File.dirname(__FILE__), 'ping')
+require 'net/http'
+require 'uri'
+require 'rbconfig'
+
+# Force non-blocking Socket.getaddrinfo on Unix systems. Do not use on
+# Windows because it (ironically) causes blocking problems.
+unless Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
+ require 'resolv-replace'
+end
+
+# The Net module serves as a namespace only.
+module Net
+
+ # The Ping::HTTP class encapsulates methods for HTTP pings.
+ class Ping::HTTP < Ping
+
+ # By default an http ping will follow a redirect and give you the result
+ # of the final URI. If this value is set to false, then it will not
+ # follow a redirect and will return false immediately on a redirect.
+ #
+ attr_accessor :follow_redirect
+
+ # Creates and returns a new Ping::HTTP object. Note that the default
+ # port for Ping::HTTP is 80.
+ #
+ def initialize(uri=nil, port=80, timeout=5)
+ @follow_redirect = true
+ super(uri, port, timeout)
+ end
+
+ # Looks for an HTTP response from the URI passed to the constructor.
+ # If the result is a kind of Net::HTTPSuccess then the ping was
+ # boolful and true is returned. Otherwise, false is returned
+ # and the Ping::HTTP#exception method should contain a string
+ # indicating what went wrong.
+ #
+ # If the HTTP#follow_redirect accessor is set to true (which it is
+ # by default) and a redirect occurs during the ping, then the
+ # HTTP#warning attribute is set to the redirect message, but the
+ # return result is still true. If it's set to false then a false
+ # value is returned if a redirect occurs.
+ #
+ def ping(host = @host)
+ super(host)
+ bool = false
+ uri = URI.parse(host)
+
+ start_time = Time.now
+
+ begin
+ response = nil
+ Timeout.timeout(@timeout){
+ response = Net::HTTP.get_response(uri.host, uri.path, @port)
+ }
+ rescue Exception => err
+ @exception = err.message
+ else
+ if response.is_a?(Net::HTTPSuccess)
+ bool = true
+ else
+ if @follow_redirect
+ @warning = response.message
+
+ while response.is_a?(Net::HTTPRedirection)
+ redirect = URI.parse(response['location'])
+ redirect = uri + redirect if redirect.relative?
+ response = Net::HTTP.get_response(redirect.host, redirect.path, @port)
+ end
+
+ if response.is_a?(Net::HTTPSuccess)
+ bool = true
+ else
+ @warning = nil
+ @exception = response.message
+ end
+ else
+ @exception = response.message
+ end
+ end
+ end
+
+ # There is no duration if the ping failed
+ @duration = Time.now - start_time if bool
+
+ bool
+ end
+
+ alias ping? ping
+ alias pingecho ping
+ alias follow_redirect? follow_redirect
+ alias uri host
+ alias uri= host=
+ end
+end
165 lib/net/ping/icmp.rb
@@ -0,0 +1,165 @@
+require File.join(File.dirname(__FILE__), 'ping')
+
+# The Net module serves as a namespace only.
+module Net
+
+ # The Net::Ping::ICMP class encapsulates an icmp ping.
+ class Ping::ICMP < Ping
+ ICMP_ECHOREPLY = 0 # Echo reply
+ ICMP_ECHO = 8 # Echo request
+ ICMP_SUBCODE = 0
+
+ # You cannot set or change the port value. A value of 0 is always
+ # used internally for ICMP pings.
+ #
+ undef_method :port=
+
+ # Returns the data size, i.e. number of bytes sent on the ping. The
+ # default size is 56.
+ #
+ attr_reader :data_size
+
+ # Creates and returns a new Ping::ICMP object. This is similar to its
+ # superclass constructor, but must be created with root privileges (on
+ # UNIX systems), and the port value is ignored.
+ #
+ def initialize(host=nil, port=nil, timeout=5)
+ raise 'requires root privileges' if Process.euid > 0
+
+ @seq = 0
+ @bind_port = 0
+ @bind_host = nil
+ @data_size = 56
+ @data = ''
+
+ 0.upto(@data_size){ |n| @data << (n % 256).chr }
+
+ @pid = Process.pid & 0xffff
+
+ super(host, port, timeout)
+ @port = nil # This value is not used in ICMP pings.
+ end
+
+ # Sets the number of bytes sent in the ping method.
+ #
+ def data_size=(size)
+ @data_size = size
+ @data = ''
+ 0.upto(size){ |n| @data << (n % 256).chr }
+ end
+
+ # Associates the local end of the socket connection with the given
+ # +host+ and +port+. The default port is 0.
+ #
+ def bind(host, port = 0)
+ @bind_host = host
+ @bind_port = port
+ end
+
+ # Pings the +host+ specified in this method or in the constructor. If a
+ # host was not specified either here or in the constructor, an
+ # ArgumentError is raised.
+ #
+ def ping(host = @host)
+ super(host)
+ bool = false
+
+ socket = Socket.new(
+ Socket::PF_INET,
+ Socket::SOCK_RAW,
+ Socket::IPPROTO_ICMP
+ )
+
+ if @bind_host
+ saddr = Socket.pack_sockaddr_in(@bind_port, @bind_host)
+ socket.bind(saddr)
+ end
+
+ @seq = (@seq + 1) % 65536
+ pstring = 'C2 n3 A' << @data_size.to_s
+ timeout = @timeout
+
+ checksum = 0
+ msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)
+ checksum = checksum(msg)
+ msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)
+
+ begin
+ saddr = Socket.pack_sockaddr_in(0, host)
+ rescue Exception
+ socket.close unless socket.closed?
+ return bool
+ end
+
+ start_time = Time.now
+
+ socket.send(msg, 0, saddr) # Send the message
+
+ begin
+ Timeout.timeout(@timeout){
+ io_array = select([socket], nil, nil, timeout)
+
+ if io_array.nil? || io_array[0].empty?
+ return false
+ end
+
+ pid = nil
+ seq = nil
+
+ data, sender = socket.recvfrom(1500)
+ port, host = Socket.unpack_sockaddr_in(sender)
+ type, subcode = data[20, 2].unpack('C2')
+
+ case type
+ when ICMP_ECHOREPLY
+ if data.length >= 28
+ pid, seq = data[24, 4].unpack('n3')
+ end
+ else
+ if data.length > 56
@crhan
crhan added a note Apr 8, 2014

Is there any idea when will data.length greater then 56?

@djberg96
Owner
djberg96 added a note Apr 9, 2014

There's a :data_size accessor. If someone sets that, it could be greater than 56 I think.

@crhan
crhan added a note Apr 9, 2014

But there is no way to move the ICMP header afterwards, regarding of the data size. There is and always 20 bytes of IP header, and 8 bytes of ICMP header. Then take the pid and seq after 24 offset.

@djberg96
Owner
djberg96 added a note Apr 9, 2014

Well, I'll have to defer. This was donated code essentially. If you think this code is unnecessary I'll consider removing it. If you have some tests that could verify that it works without it, that would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ pid, seq = data[52, 4].unpack('n3')
+ end
+ end
+
+ if pid == @pid && seq == @seq && type == ICMP_ECHOREPLY
+ bool = true
+ end
+ }
+ rescue Exception => err
+ @exception = err
+ ensure
+ socket.close if socket
+ end
+
+ # There is no duration if the ping failed
+ @duration = Time.now - start_time if bool
+
+ return bool
+ end
+
+ alias ping? ping
+ alias pingecho ping
+
+ private
+
+ # Perform a checksum on the message. This is the sum of all the short
+ # words and it folds the high order bits into the low order bits.
+ #
+ def checksum(msg)
+ length = msg.length
+ num_short = length / 2
+ check = 0
+
+ msg.unpack("n#{num_short}").each do |short|
+ check += short
+ end
+
+ if length % 2 > 0
+ check += msg[length-1, 1].unpack('C').first << 8
+ end
+
+ check = (check >> 16) + (check & 0xffff)
+ return (~((check >> 16) + check) & 0xffff)
+ end
+ end
+end
88 lib/net/ping/ping.rb
@@ -0,0 +1,88 @@
+require 'socket'
+require 'timeout'
+
+# The Net module serves as a namespace only.
+#
+module Net
+
+ # The Ping class serves as an abstract base class for all other Ping class
+ # types. You should not instantiate this class directly.
+ #
+ class Ping
+ # The version of the net-ping library.
+ VERSION = '1.3.2'
+
+ # The host to ping. In the case of Ping::HTTP, this is the URI.
+ attr_accessor :host
+
+ # The port to ping. This is set to the echo port (7) by default. The
+ # Ping::HTTP class defaults to port 80.
+ #
+ attr_accessor :port
+
+ # The maximum time a ping attempt is made.
+ attr_accessor :timeout
+
+ # If a ping fails, this value is set to the error that occurred which
+ # caused it to fail.
+ #
+ attr_reader :exception
+
+ # This value is set if a ping succeeds, but some other condition arose
+ # during the ping attempt which merits warning, e.g a redirect in the
+ # case of Ping::HTTP#ping.
+ #
+ attr_reader :warning
+
+ # The number of seconds (returned as a Float) that it took to ping
+ # the host. This is not a precise value, but rather a good estimate
+ # since there is a small amount of internal calculation that is added
+ # to the overall time.
+ #
+ attr_reader :duration
+
+ # The default constructor for the Net::Ping class. Accepts an optional
+ # +host+, +port+ and +timeout+. The port defaults to your echo port, or
+ # 7 if that happens to be undefined. The default timeout is 5 seconds.
+ #
+ # The host, although optional in the constructor, must be specified at
+ # some point before the Net::Ping#ping method is called, or else an
+ # ArgumentError will be raised.
+ #
+ # Yields +self+ in block context.
+ #
+ # This class is not meant to be instantiated directly. It is strictly
+ # meant as an interface for subclasses.
+ #
+ def initialize(host=nil, port=nil, timeout=5)
+ @host = host
+ @port = port || Socket.getservbyname('echo') || 7
+ @timeout = timeout
+ @exception = nil
+ @warning = nil
+ @duration = nil
+
+ yield self if block_given?
+ end
+
+ # The default interface for the Net::Ping#ping method. Each subclass
+ # should call super() before continuing with their own implementation in
+ # order to ensure that the @exception and @warning instance variables
+ # are reset.
+ #
+ # If +host+ is nil here, then it will use the host specified in the
+ # constructor. If the +host+ is nil and there was no host specified
+ # in the constructor then an ArgumentError is raised.
+ #--
+ # The @duration should be set in the subclass' ping method.
+ #
+ def ping(host = @host)
+ raise ArgumentError, 'no host specified' unless host
+ @exception = nil
+ @warning = nil
+ end
+
+ alias ping? ping
+ alias pingecho ping
+ end
+end
83 lib/net/ping/tcp.rb
@@ -0,0 +1,83 @@
+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
+ tcp = nil
+ start_time = Time.now
+
+ begin
+ Timeout.timeout(@timeout){
+ begin
+ tcp = TCPSocket.new(host, @port)
+ rescue Errno::ECONNREFUSED => err
+ if @@service_check
+ bool = true
+ else
+ @exception = err
+ end
+ rescue Exception => err
+ @exception = err
+ else
+ bool = true
+ end
+ }
+ rescue Timeout::Error => err
+ @exception = err
+ ensure
+ tcp.close if tcp
+ 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
119 lib/net/ping/udp.rb
@@ -0,0 +1,119 @@
+require File.join(File.dirname(__FILE__), 'ping')
+
+# The Net module serves as a namespace only.
+module Net
+
+ # The Ping::UDP class encapsulates methods for UDP pings.
+ class Ping::UDP < Ping
+ @@service_check = true
+
+ # Returns whether or not the connect behavior should enforce remote
+ # service availability as well as reachability. The default is true.
+ #
+ def self.service_check
+ @@service_check
+ end
+
+ # Set whether or not the connect behavior should enforce remote
+ # service availability as well as reachability. If set to false
+ # then Errno::ECONNREFUSED or Errno::ECONNRESET will be considered
+ # a successful ping, meaning no actual data handshaking is required.
+ # By default, if either of those errors occurs it is considered a failed
+ # 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
+
+ # The maximum data size that can be sent in a UDP ping.
+ MAX_DATA = 64
+
+ # The data to send to the remote host. By default this is 'ping'.
+ # This should be MAX_DATA size characters or less.
+ #
+ attr_reader :data
+
+ # Creates and returns a new Ping::UDP object. This is effectively
+ # identical to its superclass constructor.
+ #
+ def initialize(host=nil, port=nil, timeout=5)
+ @data = 'ping'
+
+ super(host, port, timeout)
+
+ @bind_host = nil
+ @bind_port = nil
+ end
+
+ # Sets the data string sent to the remote host. This value cannot have
+ # a size greater than MAX_DATA.
+ #
+ def data=(string)
+ if string.size > MAX_DATA
+ err = "cannot set data string larger than #{MAX_DATA} characters"
+ raise ArgumentError, err
+ end
+
+ @data = string
+ end
+
+ # Associates the local end of the UDP connection with the given +host+
+ # and +port+. This is essentially a wrapper for UDPSocket#bind.
+ #
+ def bind(host, port)
+ @bind_host = host
+ @bind_port = port
+ end
+
+ # Sends a simple text string to the host and checks the return string. If
+ # the string sent and the string returned are a match then the ping was
+ # successful and true is returned. Otherwise, false is returned.
+ #
+ def ping(host = @host)
+ super(host)
+
+ bool = false
+ udp = UDPSocket.open
+ array = []
+
+ if @bind_host
+ udp.bind(@bind_host, @bind_port)
+ end
+
+ start_time = Time.now
+
+ begin
+ Timeout.timeout(@timeout){
+ udp.connect(host, @port)
+ udp.send(@data, 0)
+ array = udp.recvfrom(MAX_DATA)
+ }
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET => err
+ if @@service_check
+ @exception = err
+ else
+ bool = true
+ end
+ rescue Exception => err
+ @exception = err
+ else
+ if array[0] == @data
+ bool = true
+ end
+ ensure
+ udp.close if udp
+ end
+
+ # There is no duration if the ping failed
+ @duration = Time.now - start_time if bool
+
+ bool
+ end
+
+ alias ping? ping
+ alias pingecho ping
+ end
+end
118 lib/net/ping/wmi.rb
@@ -0,0 +1,118 @@
+require File.join(File.dirname(__FILE__), 'ping')
+require 'win32ole'
+
+# The Net module serves as a namespace only.
+#
+module Net
+
+ # The Ping::WMI class encapsulates the Win32_PingStatus WMI class for
+ # MS Windows.
+ #
+ class Ping::WMI < Ping
+
+ PingStatus = Struct.new(
+ 'PingStatus',
+ :address,
+ :buffer_size,
+ :no_fragmentation,
+ :primary_address_resolution_status,
+ :protocol_address,
+ :protocol_address_resolved,
+ :record_route,
+ :reply_inconsistency,
+ :reply_size,
+ :resolve_address_names,
+ :response_time,
+ :response_time_to_live,
+ :route_record,
+ :route_record_resolved,
+ :source_route,
+ :source_route_type,
+ :status_code,
+ :timeout,
+ :timestamp_record,
+ :timestamp_record_address,
+ :timestamp_record_address_resolved,
+ :timestamp_route,
+ :time_to_live,
+ :type_of_service
+ )
+
+ # Unlike the ping method for other Ping subclasses, this version returns
+ # a PingStatus struct which contains various bits of information about
+ # the results of the ping itself, such as response time.
+ #
+ # In addition, this version allows you to pass certain options that are
+ # then passed on to the underlying WQL query. See the MSDN documentation
+ # on Win32_PingStatus for details.
+ #
+ # Examples:
+ #
+ # # Ping with no options
+ # Ping::WMI.ping('www.perl.com')
+ #
+ # # Ping with options
+ # Ping::WMI.ping('www.perl.com', :BufferSize => 64, :NoFragmentation => true)
+ #--
+ # The PingStatus struct is a wrapper for the Win32_PingStatus WMI class.
+ #
+ def ping(host = @host, options = {})
+ super(host)
+
+ lhost = Socket.gethostname
+
+ cs = "winmgmts:{impersonationLevel=impersonate}!//#{lhost}/root/cimv2"
+ wmi = WIN32OLE.connect(cs)
+
+ query = "select * from win32_pingstatus where address = '#{host}'"
+
+ unless options.empty?
+ options.each{ |key, value|
+ if value.is_a?(String)
+ query << " and #{key} = '#{value}'"
+ else
+ query << " and #{key} = #{value}"
+ end
+ }
+ end
+
+ status = Struct::PingStatus.new
+
+ wmi.execquery(query).each{ |obj|
+ status.address = obj.Address
+ status.buffer_size = obj.BufferSize
+ status.no_fragmentation = obj.NoFragmentation
+ status.primary_address_resolution_status = obj.PrimaryAddressResolutionStatus
+ status.protocol_address = obj.ProtocolAddress
+ status.protocol_address_resolved = obj.ProtocolAddressResolved
+ status.record_route = obj.RecordRoute
+ status.reply_inconsistency = obj.ReplyInconsistency
+ status.reply_size = obj.ReplySize
+ status.resolve_address_names = obj.ResolveAddressNames
+ status.response_time = obj.ResponseTime
+ status.response_time_to_live = obj.ResponseTimeToLive
+ status.route_record = obj.RouteRecord
+ status.route_record_resolved = obj.RouteRecordResolved
+ status.source_route = obj.SourceRoute
+ status.source_route_type = obj.SourceRouteType
+ status.status_code = obj.StatusCode
+ status.timeout = obj.Timeout
+ status.timestamp_record = obj.TimeStampRecord
+ status.timestamp_record_address = obj.TimeStampRecordAddress
+ status.timestamp_record_address_resolved = obj.TimeStampRecordAddressResolved
+ status.timestamp_route = obj.TimeStampRoute
+ status.time_to_live = obj.TimeToLive
+ status.type_of_service = obj.TypeOfService
+ }
+
+ status.freeze # Read-only data
+ end
+
+ # Unlike Net::Ping::WMI#ping, this method returns true or false to
+ # indicate whether or not the ping was successful.
+ #
+ def ping?(host = @host, options = {})
+ ping(host, options).status_code == 0
+ end
+ end
+end
36 net-ping.gemspec
@@ -0,0 +1,36 @@
+require 'rubygems'
+require 'rbconfig'
+
+Gem::Specification.new do |gem|
+ gem.name = 'net-ping'
+ gem.version = '1.3.2'
+ gem.license = 'Artistic 2.0'
+ gem.author = 'Daniel J. Berger'
+ gem.email = 'djberg96@gmail.com'
+ gem.homepage = 'http://www.rubyforge.org/projects/shards'
+ gem.summary = 'A ping interface for Ruby.'
+ gem.test_file = 'test/test_net_ping.rb'
+ gem.has_rdoc = true
+ gem.files = Dir['**/*'].reject{ |f| f.include?('CVS') }
+
+ gem.rubyforge_project = 'shards'
+ gem.extra_rdoc_files = ['README', 'CHANGES', 'doc/ping.txt']
+
+ gem.add_development_dependency('test-unit', '>= 2.0.3')
+
+ # These dependencies are for Net::Ping::External
+ if Config::CONFIG['host_os'] =~ /mswin|dos|win32|cygwin|mingw/i
+ gem.platform = Gem::Platform::CURRENT
+ gem.add_dependency('windows-pr', '>= 1.0.8')
+
+ if RUBY_VERSION.to_f < 1.9
+ gem.add_dependency('win32-open3', '>= 0.3.1')
+ end
+ end
+
+ gem.description = <<-EOF
+ The net-ping library provides a ping interface for Ruby. It includes
+ separate TCP, HTTP, ICMP, UDP, WMI (for Windows) and external ping
+ classes.
+ EOF
+end
18 test/test_net_ping.rb
@@ -0,0 +1,18 @@
+######################################################################
+# test_net_ping.rb
+#
+# Test suite for all the Ping subclasses. Note that the Ping::ICMP
+# class test won't be run unless this is run as a privileged process.
+######################################################################
+require 'test_net_ping_external'
+require 'test_net_ping_http'
+require 'test_net_ping_tcp'
+require 'test_net_ping_udp'
+
+if Process.euid == 0
+ require 'test_net_ping_icmp'
+end
+
+if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
+ require 'test_net_ping_wmi'
+end
92 test/test_net_ping_external.rb
@@ -0,0 +1,92 @@
+#########################################################################
+# test_net_ping_external.rb
+#
+# Test case for the Net::PingExternal class. Run this via the 'test' or
+# 'test:external' rake task.
+#########################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/external'
+include Net
+
+class TC_PingExternal < Test::Unit::TestCase
+ def setup
+ @host = 'www.ruby-lang.org'
+ @bogus = 'foo.bar.baz'
+ @pe = Ping::External.new(@host)
+ @bad = Ping::External.new(@bogus)
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::External::VERSION)
+ end
+
+ def test_ping
+ assert_respond_to(@pe, :ping)
+ assert_nothing_raised{ @pe.ping }
+ assert_nothing_raised{ @pe.ping(@host) }
+ end
+
+ def test_ping_aliases
+ assert_respond_to(@pe, :ping?)
+ assert_respond_to(@pe, :pingecho)
+ assert_nothing_raised{ @pe.ping? }
+ assert_nothing_raised{ @pe.ping?(@host) }
+ assert_nothing_raised{ @pe.pingecho }
+ assert_nothing_raised{ @pe.pingecho(@host) }
+ end
+
+ def test_good_ping
+ assert_equal(true, @pe.ping?)
+ end
+
+ def test_bad_ping
+ assert_equal(false, @bad.ping?)
+ assert_equal(false, @bad.exception.nil?, "Bad exception data")
+ end
+
+ def test_duration
+ assert_nothing_raised{ @pe.ping }
+ assert_respond_to(@pe, :duration)
+ assert_kind_of(Float, @pe.duration)
+ end
+
+ def test_host
+ assert_respond_to(@pe, :host)
+ assert_respond_to(@pe, :host=)
+ assert_equal('www.ruby-lang.org', @pe.host)
+ end
+
+ def test_port
+ assert_respond_to(@pe, :port)
+ assert_respond_to(@pe, :port=)
+ assert_equal(7, @pe.port)
+ end
+
+ def test_timeout
+ assert_respond_to(@pe, :timeout)
+ assert_respond_to(@pe, :timeout=)
+ assert_equal(5, @pe.timeout)
+ end
+
+ def test_exception
+ assert_respond_to(@pe, :exception)
+ assert_nothing_raised{ @pe.ping }
+ assert_nothing_raised{ @bad.ping }
+ assert_nil(@pe.exception)
+ assert_not_nil(@bad.exception)
+ end
+
+ def test_warning
+ assert_respond_to(@pe, :warning)
+ end
+
+ def teardown
+ @host = nil
+ @bogus = nil
+ @pe = nil
+ @bad = nil
+ end
+end
86 test/test_net_ping_http.rb
@@ -0,0 +1,86 @@
+#################################################################################
+# test_net_ping_http.rb
+#
+# Test case for the Net::PingHTTP class. This should be run via the 'test' or
+# 'test:http' Rake task.
+#################################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/http'
+include Net
+
+class TC_PingHTTP < Test::Unit::TestCase
+ def setup
+ @uri = 'http://www.google.com/index.html'
+ @http = Ping::HTTP.new(@uri, 80, 30)
+ @bad = Ping::HTTP.new('http://www.blabfoobarurgh.com') # One hopes not
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::HTTP::VERSION)
+ end
+
+ def test_ping
+ assert_respond_to(@http, :ping)
+ assert_nothing_raised{ @http.ping }
+ end
+
+ def test_ping_aliases
+ assert_respond_to(@http, :ping?)
+ assert_respond_to(@http, :pingecho)
+ assert_nothing_raised{ @http.ping? }
+ assert_nothing_raised{ @http.pingecho }
+ end
+
+ def test_ping_success
+ assert_equal(true, @http.ping?)
+ assert_equal(false, @bad.ping?)
+ assert_not_nil(@bad.exception)
+ end
+
+ def test_duration
+ assert_nothing_raised{ @http.ping }
+ assert_respond_to(@http, :duration)
+ assert_kind_of(Float, @http.duration)
+ end
+
+ def test_host
+ assert_respond_to(@http, :host)
+ assert_respond_to(@http, :host=)
+ assert_respond_to(@http, :uri) # Alias
+ assert_respond_to(@http, :uri=) # Alias
+ assert_equal('http://www.google.com/index.html', @http.host)
+ end
+
+ def test_port
+ assert_respond_to(@http, :port)
+ assert_respond_to(@http, :port=)
+ assert_equal(80, @http.port)
+ end
+
+ def test_timeout
+ assert_respond_to(@http, :timeout)
+ assert_respond_to(@http, :timeout=)
+ assert_equal(30, @http.timeout)
+ assert_equal(5, @bad.timeout)
+ end
+
+ def test_exception
+ assert_respond_to(@http, :exception)
+ assert_nothing_raised{ @http.ping }
+ assert_nothing_raised{ @bad.ping }
+ assert_nil(@http.exception)
+ assert_not_nil(@bad.exception)
+ end
+
+ def test_warning
+ assert_respond_to(@http, :warning)
+ end
+
+ def teardown
+ @uri = nil
+ @http = nil
+ end
+end
130 test/test_net_ping_icmp.rb
@@ -0,0 +1,130 @@
+#######################################################################
+# test_net_ping_icmp.rb
+#
+# Test case for the Net::PingICMP class. You must run this test case
+# with root privileges on UNIX systems. This should be run via the
+# 'test' or 'test:icmp' Rake task.
+#######################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/icmp'
+include Net
+
+unless Process.euid == 0
+ raise "The test:icmp task must be run with root privileges"
+end
+
+class TC_PingICMP < Test::Unit::TestCase
+ def self.startup
+ @@one_click = Config::CONFIG['host_os'] == 'mswin32'
+ end
+
+ def setup
+ @host = "www.ruby-lang.org"
+ @icmp = Ping::ICMP.new(@host)
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::ICMP::VERSION)
+ end
+
+ def test_ping
+ assert_respond_to(@icmp, :ping)
+
+ omit_if(@@one_click, 'Unreliable socket library')
+
+ assert_nothing_raised{ @icmp.ping }
+ assert_nothing_raised{ @icmp.ping(@host) }
+ end
+
+ def test_ping_aliases_basic
+ assert_respond_to(@icmp, :ping?)
+ assert_respond_to(@icmp, :pingecho)
+
+ omit_if(@@one_click, 'Unreliable socket library')
+
+ assert_nothing_raised{ @icmp.ping? }
+ assert_nothing_raised{ @icmp.ping?(@host) }
+ end
+
+ def test_ping_returns_boolean
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_boolean(@icmp.pingecho)
+ assert_boolean(@icmp.pingecho(@host))
+ end
+
+ def test_ping_expected_failure
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_false(Ping::ICMP.new('bogus').ping?)
+ assert_false(Ping::ICMP.new('http://www.asdfhjklasdfhlkj.com').ping?)
+ end
+
+ def test_bind
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_respond_to(@icmp, :bind)
+ assert_nothing_raised{ @icmp.bind(Socket.gethostname) }
+ assert_nothing_raised{ @icmp.bind(Socket.gethostname, 80) }
+ end
+
+ def test_duration
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_nothing_raised{ @icmp.ping }
+ assert_respond_to(@icmp, :duration)
+ assert_kind_of(Float, @icmp.duration)
+ end
+
+ def test_host
+ assert_respond_to(@icmp, :host)
+ assert_respond_to(@icmp, :host=)
+ assert_equal('www.ruby-lang.org', @icmp.host)
+ end
+
+ def test_port
+ assert_respond_to(@icmp, :port)
+ assert_equal(nil, @icmp.port)
+ end
+
+ def test_timeout
+ assert_respond_to(@icmp, :timeout)
+ assert_respond_to(@icmp, :timeout=)
+ assert_equal(5, @icmp.timeout)
+ end
+
+ def test_exception
+ assert_respond_to(@icmp, :exception)
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_nothing_raised{ @icmp.ping }
+ assert_nil(@icmp.exception)
+ end
+
+ def test_warning
+ assert_respond_to(@icmp, :warning)
+ end
+
+ def test_data_size_get
+ assert_respond_to(@icmp, :data_size)
+ assert_equal(56, @icmp.data_size)
+ end
+
+ def test_data_size_set
+ assert_respond_to(@icmp, :data_size=)
+ assert_nothing_raised{ @icmp.data_size = 22 }
+ end
+
+ def test_odd_data_size_ok
+ assert_nothing_raised{ @icmp.data_size = 57 }
+ omit_if(@@one_click, 'Unreliable socket library')
+ assert_boolean(@icmp.ping)
+ end
+
+ def teardown
+ @host = nil
+ @icmp = nil
+ end
+
+ def self.shutdown
+ @@one_click = nil
+ end
+end
112 test/test_net_ping_tcp.rb
@@ -0,0 +1,112 @@
+#####################################################################
+# test_net_ping_tcp.rb
+#
+# Test case for the Net::PingTCP class. This test should be run via
+# the 'test' or 'test:tcp' Rake task.
+#####################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/tcp'
+include Net
+
+class TC_PingTCP < Test::Unit::TestCase
+ def setup
+ @host = 'www.ruby-lang.org'
+ @port = 'ftp'
+ @tcp = Ping::TCP.new(@host, @port)
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::TCP::VERSION)
+ end
+
+ def test_ping
+ assert_respond_to(@tcp, :ping)
+ assert_nothing_raised{ @tcp.ping }
+ assert_nothing_raised{ @tcp.ping(@host) }
+ end
+
+ def test_ping_aliases
+ assert_respond_to(@tcp, :ping?)
+ assert_respond_to(@tcp, :pingecho)
+ assert_nothing_raised{ @tcp.ping? }
+ assert_nothing_raised{ @tcp.ping?(@host) }
+ assert_nothing_raised{ @tcp.pingecho }
+ assert_nothing_raised{ @tcp.pingecho(@host) }
+ end
+
+ def test_ping_service_check_false
+ msg = "+this test may fail depending on your network environment+"
+ Ping::TCP.service_check = false
+ @tcp = Ping::TCP.new('localhost')
+ assert_equal(false, @tcp.ping?, msg)
+ assert_equal(false, @tcp.exception.nil?, "Bad exception data")
+ end
+
+ def test_ping_service_check_true
+ msg = "+this test may fail depending on your network environment+"
+ Ping::TCP.service_check = true
+ assert_equal(true, @tcp.ping?, msg)
+ end
+
+ def test_service_check
+ assert_respond_to(Ping::TCP, :service_check)
+ assert_respond_to(Ping::TCP, :service_check=)
+ end
+
+ # These will be removed eventually
+ def test_service_check_aliases
+ assert_respond_to(Ping::TCP, :econnrefused)
+ assert_respond_to(Ping::TCP, :econnrefused=)
+ assert_respond_to(Ping::TCP, :ecr)
+ assert_respond_to(Ping::TCP, :ecr=)
+ end
+
+ def test_service_check_expected_errors
+ assert_raises(ArgumentError){ Ping::TCP.service_check = "blah" }
+ end
+
+ # If the ping failed, the duration will be nil
+ def test_duration
+ assert_nothing_raised{ @tcp.ping }
+ assert_respond_to(@tcp, :duration)
+ omit_if(@tcp.duration.nil?, 'ping failed, skipping')
+ assert_kind_of(Float, @tcp.duration)
+ end
+
+ def test_host
+ assert_respond_to(@tcp, :host)
+ assert_respond_to(@tcp, :host=)
+ assert_equal(@host, @tcp.host)
+ end
+
+ def test_port
+ assert_respond_to(@tcp, :port)
+ assert_respond_to(@tcp, :port=)
+ assert_equal('ftp', @tcp.port)
+ end
+
+ def test_timeout
+ assert_respond_to(@tcp, :timeout)
+ assert_respond_to(@tcp, :timeout=)
+ assert_equal(5, @tcp.timeout)
+ end
+
+ def test_exception
+ msg = "+this test may fail depending on your network environment+"
+ assert_respond_to(@tcp, :exception)
+ assert_nothing_raised{ @tcp.ping }
+ assert_nil(@tcp.exception, msg)
+ end
+
+ def test_warning
+ assert_respond_to(@tcp, :warning)
+ end
+
+ def teardown
+ @host = nil
+ @tcp = nil
+ end
+end
102 test/test_net_ping_udp.rb
@@ -0,0 +1,102 @@
+################################################################
+# test_net_ping_udp.rb
+#
+# Test case for the Net::Ping::UDP class. This should be run
+# via the 'test' or 'test:udp' Rake task.
+#
+# If someone could provide me a host where a udp ping actually
+# works (with a service check), I would appreciate it. :)
+################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/udp'
+include Net
+
+class TC_PingUDP < Test::Unit::TestCase
+ def setup
+ Ping::UDP.service_check = false
+ @host = '127.0.0.1'
+ @udp = Ping::UDP.new(@host)
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::UDP::VERSION)
+ end
+
+ def test_ping
+ assert_respond_to(@udp, :ping)
+ assert_nothing_raised{ @udp.ping }
+ assert_nothing_raised{ @udp.ping(@host) }
+ end
+
+ def test_ping_aliases
+ assert_respond_to(@udp, :ping?)
+ assert_respond_to(@udp, :pingecho)
+ assert_nothing_raised{ @udp.ping? }
+ assert_nothing_raised{ @udp.ping?(@host) }
+ assert_nothing_raised{ @udp.pingecho }
+ assert_nothing_raised{ @udp.pingecho(@host) }
+ end
+
+ def test_ping_standard
+ assert_equal(true, @udp.ping?)
+ assert_equal(true, @udp.exception.nil?)
+ end
+
+ def test_bind
+ assert_respond_to(@udp, :bind)
+ assert_nothing_raised{ @udp.bind('127.0.0.1', 80) }
+ end
+
+ def test_duration
+ assert_nothing_raised{ @udp.ping }
+ assert_respond_to(@udp, :duration)
+ assert_kind_of(Float, @udp.duration)
+ end
+
+ def test_host
+ assert_respond_to(@udp, :host)
+ assert_respond_to(@udp, :host=)
+ assert_equal('127.0.0.1', @udp.host)
+ end
+
+ def test_port
+ assert_respond_to(@udp, :port)
+ assert_respond_to(@udp, :port=)
+ assert_equal(7, @udp.port)
+ end
+
+ def test_timeout
+ assert_respond_to(@udp, :timeout)
+ assert_respond_to(@udp, :timeout=)
+ assert_equal(5, @udp.timeout)
+ end
+
+ def test_exception
+ assert_respond_to(@udp, :exception)
+ assert_nothing_raised{ @udp.ping }
+ assert_nil(@udp.exception)
+ end
+
+ def test_warning
+ assert_respond_to(@udp, :warning)
+ end
+
+ def test_service_check
+ assert_respond_to(Ping::UDP, :service_check)
+ assert_respond_to(Ping::UDP, :service_check=)
+ assert_equal(false, Ping::UDP.service_check) # Set in setup
+ end
+
+ def test_service_check_expected_failures
+ assert_raise(ArgumentError){ Ping::UDP.service_check(1) }
+ assert_raise(ArgumentError){ Ping::UDP.service_check = 1 }
+ end
+
+ def teardown
+ @host = nil
+ @udp = nil
+ end
+end
88 test/test_net_ping_wmi.rb
@@ -0,0 +1,88 @@
+#######################################################################
+# test_net_ping_wmi.rb
+#
+# Test case for the Net::Ping::WMI class. These tests will only be
+# run MS Windows. You should run this test via the 'test' or
+# 'test:wmi' Rake task.
+#######################################################################
+require 'rubygems'
+gem 'test-unit'
+
+require 'test/unit'
+require 'net/ping/wmi'
+include Net
+
+class TC_Ping_WMI < Test::Unit::TestCase
+ def self.startup
+ @@windows = Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
+ end
+
+ def setup
+ @host = "www.ruby-lang.org"
+ @wmi = Ping::WMI.new(@host) if @@windows
+ end
+
+ def test_version
+ assert_equal('1.3.2', Ping::WMI::VERSION)
+ end
+
+ def test_ping_basic
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_respond_to(@wmi, :ping)
+ assert_nothing_raised{ @wmi.ping }
+ end
+
+ def test_ping_with_host
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_nothing_raised{ @wmi.ping(@host) }
+ end
+
+ def test_ping_with_options
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_nothing_raised{ @wmi.ping(@host, :NoFragmentation => true) }
+ end
+
+ def test_pingecho_alias
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_respond_to(@wmi, :pingecho)
+ assert_nothing_raised{ @wmi.pingecho }
+ assert_nothing_raised{ @wmi.pingecho(@host) }
+ end
+
+ def test_ping_returns_struct
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_kind_of(Struct::PingStatus, @wmi.ping)
+ end
+
+ def test_ping_returns_boolean
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_boolean(@wmi.ping?)
+ assert_boolean(@wmi.ping?(@host))
+ end
+
+ def test_ping_expected_failure
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_false(Ping::WMI.new('bogus').ping?)
+ assert_false(Ping::WMI.new('http://www.asdfhjklasdfhlkj.com').ping?)
+ end
+
+ def test_exception
+ omit_unless(@@windows, 'skipped on Unix platforms')
+ assert_respond_to(@wmi, :exception)
+ assert_nothing_raised{ @wmi.ping }
+ assert_nil(@wmi.exception)
+ end
+
+ def test_warning
+ assert_respond_to(@wmi, :warning)
+ end
+
+ def teardown
+ @host = nil
+ @wmi = nil
+ end
+
+ def self.shutdown
+ @@windows = nil
+ end
+end

0 comments on commit 18e6e23

Please sign in to comment.
Something went wrong with that request. Please try again.