net-ping 2.1.0-universal-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ require File.join(File.dirname(__FILE__), 'ping')
2
+ require 'win32ole'
3
+
4
+ # The Net module serves as a namespace only.
5
+ #
6
+ module Net
7
+
8
+ # The Ping::WMI class encapsulates the Win32_PingStatus WMI class for
9
+ # MS Windows.
10
+ #
11
+ class Ping::WMI < Ping
12
+
13
+ PingStatus = Struct.new(
14
+ 'PingStatus',
15
+ :address,
16
+ :buffer_size,
17
+ :no_fragmentation,
18
+ :primary_address_resolution_status,
19
+ :protocol_address,
20
+ :protocol_address_resolved,
21
+ :record_route,
22
+ :reply_inconsistency,
23
+ :reply_size,
24
+ :resolve_address_names,
25
+ :response_time,
26
+ :response_time_to_live,
27
+ :route_record,
28
+ :route_record_resolved,
29
+ :source_route,
30
+ :source_route_type,
31
+ :status_code,
32
+ :timeout,
33
+ :timestamp_record,
34
+ :timestamp_record_address,
35
+ :timestamp_record_address_resolved,
36
+ :timestamp_route,
37
+ :time_to_live,
38
+ :type_of_service
39
+ )
40
+
41
+ # Unlike the ping method for other Ping subclasses, this version returns
42
+ # a PingStatus struct which contains various bits of information about
43
+ # the results of the ping itself, such as response time.
44
+ #
45
+ # In addition, this version allows you to pass certain options that are
46
+ # then passed on to the underlying WQL query. See the MSDN documentation
47
+ # on Win32_PingStatus for details.
48
+ #
49
+ # Examples:
50
+ #
51
+ # # Ping with no options
52
+ # Ping::WMI.ping('www.perl.com')
53
+ #
54
+ # # Ping with options
55
+ # Ping::WMI.ping('www.perl.com', :BufferSize => 64, :NoFragmentation => true)
56
+ #--
57
+ # The PingStatus struct is a wrapper for the Win32_PingStatus WMI class.
58
+ #
59
+ def ping(host = @host, options = {})
60
+ super(host)
61
+
62
+ lhost = Socket.gethostname
63
+
64
+ cs = "winmgmts:{impersonationLevel=impersonate}!//#{lhost}/root/cimv2"
65
+ wmi = WIN32OLE.connect(cs)
66
+
67
+ query = "select * from win32_pingstatus where address = '#{host}'"
68
+
69
+ unless options.empty?
70
+ options.each{ |key, value|
71
+ if value.is_a?(String)
72
+ query << " and #{key} = '#{value}'"
73
+ else
74
+ query << " and #{key} = #{value}"
75
+ end
76
+ }
77
+ end
78
+
79
+ status = Struct::PingStatus.new
80
+
81
+ wmi.execquery(query).each{ |obj|
82
+ status.address = obj.Address
83
+ status.buffer_size = obj.BufferSize
84
+ status.no_fragmentation = obj.NoFragmentation
85
+ status.primary_address_resolution_status = obj.PrimaryAddressResolutionStatus
86
+ status.protocol_address = obj.ProtocolAddress
87
+ status.protocol_address_resolved = obj.ProtocolAddressResolved
88
+ status.record_route = obj.RecordRoute
89
+ status.reply_inconsistency = obj.ReplyInconsistency
90
+ status.reply_size = obj.ReplySize
91
+ status.resolve_address_names = obj.ResolveAddressNames
92
+ status.response_time = obj.ResponseTime
93
+ status.response_time_to_live = obj.ResponseTimeToLive
94
+ status.route_record = obj.RouteRecord
95
+ status.route_record_resolved = obj.RouteRecordResolved
96
+ status.source_route = obj.SourceRoute
97
+ status.source_route_type = obj.SourceRouteType
98
+ status.status_code = obj.StatusCode
99
+ status.timeout = obj.Timeout
100
+ status.timestamp_record = obj.TimeStampRecord
101
+ status.timestamp_record_address = obj.TimeStampRecordAddress
102
+ status.timestamp_record_address_resolved = obj.TimeStampRecordAddressResolved
103
+ status.timestamp_route = obj.TimeStampRoute
104
+ status.time_to_live = obj.TimeToLive
105
+ status.type_of_service = obj.TypeOfService
106
+ }
107
+
108
+ status.freeze # Read-only data
109
+ end
110
+
111
+ # Unlike Net::Ping::WMI#ping, this method returns true or false to
112
+ # indicate whether or not the ping was successful.
113
+ #
114
+ def ping?(host = @host, options = {})
115
+ ping(host, options).status_code == 0
116
+ end
117
+ end
118
+ end
data/lib/net/ping.rb ADDED
@@ -0,0 +1,24 @@
1
+ # By doing a "require 'net/ping'" you are requiring every subclass. If you
2
+ # want to require a specific ping type only, do "require 'net/ping/tcp'",
3
+ # for example.
4
+ #
5
+ require 'rbconfig'
6
+
7
+ require_relative 'ping/tcp'
8
+ require_relative 'ping/udp'
9
+ require_relative 'ping/icmp'
10
+ require_relative 'ping/external'
11
+ require_relative 'ping/http'
12
+
13
+ RbConfig = Config unless Object.const_defined?(:RbConfig)
14
+
15
+ begin
16
+ `busybox`
17
+ RbConfig::CONFIG['busybox'] = true
18
+ rescue Errno::ENOENT
19
+ RbConfig::CONFIG['busybox'] = false
20
+ end
21
+
22
+ if File::ALT_SEPARATOR
23
+ require_relative 'ping/wmi'
24
+ end
@@ -0,0 +1,4 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'linux'])
3
+ spec.add_dependency('cap2', '>= 0.2.2')
4
+ spec
@@ -0,0 +1,7 @@
1
+ spec = Gem::Specification.load('net-ping.gemspec').dup
2
+ spec.platform = Gem::Platform.new(['universal', 'mingw-ucrt'])
3
+ spec.add_dependency('win32-security', '>= 0.2.0')
4
+
5
+ # No longer a default gem as of Ruby 4.0. Used by the WMI ping class.
6
+ spec.add_dependency('win32ole', '>= 1.8.8')
7
+ spec
data/net-ping.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ require_relative "lib/net/ping/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'net-ping'
5
+ spec.version = Net::Ping::VERSION
6
+ spec.license = 'Artistic 2.0'
7
+ spec.author = 'Chris Chernesky'
8
+ spec.email = 'chris.netping@tinderglow.com'
9
+ spec.homepage = 'https://github.com/chernesk/net-ping'
10
+ spec.summary = 'A ping interface for Ruby.'
11
+ spec.test_file = 'test/test_net_ping.rb'
12
+ spec.files = Dir['**/*'].reject { |f| f.include?('git') || File.extname(f) == '.gem' }
13
+ spec.metadata = {
14
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
15
+ 'changelog_uri' => "#{spec.homepage}/blob/master/CHANGES",
16
+ 'documentation_uri' => "https://www.rubydoc.info/gems/#{spec.name}",
17
+ 'homepage_uri' => spec.homepage,
18
+ 'source_code_uri' => spec.homepage
19
+ }
20
+
21
+ spec.extra_rdoc_files = ['README.md', 'CHANGES', 'doc/ping.txt']
22
+
23
+ # The TCP Ping class requires this for non-blocking sockets.
24
+ spec.required_ruby_version = ">= 1.9.3"
25
+
26
+ spec.add_development_dependency('test-unit', '>= 0')
27
+ spec.add_development_dependency('webmock', '>= 0')
28
+ spec.add_development_dependency('rake', '>= 0')
29
+ spec.add_development_dependency('pry-byebug', '>= 0')
30
+
31
+ spec.description = <<-EOF
32
+ The net-ping library provides a ping interface for Ruby. It includes
33
+ separate TCP, HTTP, LDAP, ICMP, UDP, WMI (for Windows) and external ping
34
+ classes.
35
+ EOF
36
+ end
@@ -0,0 +1,44 @@
1
+ ######################################################################
2
+ # test_net_ping.rb
3
+ #
4
+ # Test suite for all the Ping subclasses. Note that the Ping::ICMP
5
+ # class test won't be run unless this is run as a privileged process.
6
+ ######################################################################
7
+ require 'test_net_ping_external'
8
+ require 'test_net_ping_gem_packaging'
9
+ require 'test_net_ping_http'
10
+ require 'test_net_ping_tcp'
11
+ require 'test_net_ping_udp'
12
+
13
+ if File::ALT_SEPARATOR
14
+ require 'win32/security'
15
+
16
+ if Win32::Security.elevated_security?
17
+ require 'test_net_ping_icmp'
18
+ end
19
+ else
20
+ # If cap2 is availble, check if we are root, or our process has net_raw,
21
+ # then include ICMP tests
22
+ begin
23
+ require 'cap2'
24
+ current_process = Cap2.process
25
+ if Process.euid == 0 \
26
+ || current_process.permitted?(:net_raw) \
27
+ && current_process.enabled?(:net_raw)
28
+ require 'test_net_ping_icmp'
29
+ end
30
+ rescue LoadError
31
+ # If we don't have cap2, include ICMP tests if we are root
32
+ require 'test_net_ping_icmp' if Process.euid == 0
33
+ end
34
+ end
35
+
36
+ if File::ALT_SEPARATOR
37
+ require 'test_net_ping_wmi'
38
+ end
39
+
40
+ class TC_Net_Ping < Test::Unit::TestCase
41
+ def test_net_ping_version
42
+ assert_equal(Gem::Specification.load('net-ping.gemspec').version.to_s, Net::Ping::VERSION)
43
+ end
44
+ end
@@ -0,0 +1,232 @@
1
+ #########################################################################
2
+ # test_net_ping_external.rb
3
+ #
4
+ # Test case for the Net::PingExternal class. Run this via the 'test' or
5
+ # 'test:external' rake task.
6
+ #
7
+ # WARNING: I've noticed that test failures will occur if you're using
8
+ # OpenDNS. This is apparently caused by them messing with upstream
9
+ # replies for advertising purposes.
10
+ #########################################################################
11
+ require 'test-unit'
12
+ require 'net/ping/external'
13
+ require 'mkmf'
14
+ require 'stringio'
15
+
16
+ class TC_Net_Ping_External < Test::Unit::TestCase
17
+ def setup
18
+ @host = 'localhost'
19
+ @bogus = 'foo.bar.baz'
20
+ @pe = Net::Ping::External.new(@host)
21
+ @bad = Net::Ping::External.new(@bogus)
22
+ end
23
+
24
+ test "ping basic functionality" do
25
+ assert_respond_to(@pe, :ping)
26
+ end
27
+
28
+ test "ping with no arguments" do
29
+ assert_nothing_raised{ @pe.ping }
30
+ end
31
+
32
+ test "ping accepts a hostname" do
33
+ assert_nothing_raised{ @pe.ping(@host) }
34
+ end
35
+
36
+ test "ping returns a boolean" do
37
+ assert_boolean(@pe.ping)
38
+ assert_boolean(@bad.ping)
39
+ end
40
+
41
+ test "ping? alias" do
42
+ assert_respond_to(@pe, :ping?)
43
+ assert_alias_method(@pe, :ping?, :ping)
44
+ end
45
+
46
+ test "pingecho alias" do
47
+ assert_nothing_raised{ @pe.pingecho }
48
+ assert_alias_method(@pe, :pingecho, :ping)
49
+ end
50
+
51
+ test "pinging a good host returns true" do
52
+ omit_if(find_executable0('ping').nil?)
53
+ assert_true(@pe.ping?)
54
+ end
55
+
56
+ test "pinging a bogus host returns false" do
57
+ assert_false(@bad.ping?)
58
+ end
59
+
60
+ test "duration basic functionality" do
61
+ omit_if(find_executable0('ping').nil?)
62
+ assert_nothing_raised{ @pe.ping }
63
+ assert_respond_to(@pe, :duration)
64
+ assert_kind_of(Float, @pe.duration)
65
+ end
66
+
67
+ test "duration is unset if a bad ping follows a good ping" do
68
+ omit_if(find_executable0('ping').nil?)
69
+ assert_nothing_raised{ @pe.ping }
70
+ assert_not_nil(@pe.duration)
71
+ assert_false(@pe.ping?(@bogus))
72
+ assert_nil(@pe.duration)
73
+ end
74
+
75
+ test "host getter basic functionality" do
76
+ assert_respond_to(@pe, :host)
77
+ assert_equal('localhost', @pe.host)
78
+ end
79
+
80
+ test "host setter basic functionality" do
81
+ assert_respond_to(@pe, :host=)
82
+ assert_nothing_raised{ @pe.host = @bad }
83
+ assert_equal(@bad, @pe.host)
84
+ end
85
+
86
+ test "port getter basic functionality" do
87
+ assert_respond_to(@pe, :port)
88
+ assert_equal(7, @pe.port)
89
+ end
90
+
91
+ test "port setter basic functionality" do
92
+ assert_respond_to(@pe, :port=)
93
+ assert_nothing_raised{ @pe.port = 90 }
94
+ assert_equal(90, @pe.port)
95
+ end
96
+
97
+ test "timeout getter basic functionality" do
98
+ assert_respond_to(@pe, :timeout)
99
+ assert_equal(5, @pe.timeout)
100
+ end
101
+
102
+ test "timeout setter basic functionality" do
103
+ assert_respond_to(@pe, :timeout=)
104
+ assert_nothing_raised{ @pe.timeout = 30 }
105
+ assert_equal(30, @pe.timeout)
106
+ end
107
+
108
+ test "exception method basic functionality" do
109
+ assert_respond_to(@pe, :exception)
110
+ assert_nil(@pe.exception)
111
+ end
112
+
113
+ test "pinging a bogus host stores exception data" do
114
+ assert_nothing_raised{ @bad.ping? }
115
+ assert_not_nil(@bad.exception)
116
+ end
117
+
118
+ test "pinging a good host results in no exception data" do
119
+ omit_if(find_executable0('ping').nil?)
120
+ assert_nothing_raised{ @pe.ping }
121
+ assert_nil(@pe.exception)
122
+ end
123
+
124
+ test "warning basic functionality" do
125
+ assert_respond_to(@pe, :warning)
126
+ assert_nil(@pe.warning)
127
+ end
128
+
129
+ test "timing out causes expected result" do
130
+ ext = Net::Ping::External.new('foo.bar.baz', nil, 1)
131
+ start = Time.now
132
+ assert_false(ext.ping?)
133
+ elapsed = Time.now - start
134
+ assert_true(elapsed < 2.5, "Actual elapsed: #{elapsed}")
135
+ assert_not_nil(ext.exception)
136
+ end
137
+
138
+ test "pinging an unreachable host on the same subnet returns false" do
139
+ @bad = Net::Ping::External.new('192.168.0.99')
140
+ assert_false(@bad.ping?)
141
+ end
142
+
143
+ test "ping6 uses timeout for FreeBSD" do
144
+ command = nil
145
+ original_os = RbConfig::CONFIG['host_os']
146
+ original_popen3 = Open3.method(:popen3)
147
+
148
+ RbConfig::CONFIG['host_os'] = 'freebsd'
149
+ Open3.define_singleton_method(:popen3) do |*args, &block|
150
+ command = args
151
+ stdin = StringIO.new
152
+ stdout = StringIO.new
153
+ stderr = StringIO.new
154
+ status = Struct.new(:exitstatus).new(0)
155
+ thread = Struct.new(:value).new(status)
156
+ block.call(stdin, stdout, stderr, thread)
157
+ end
158
+
159
+ @pe.ping6('example.test', 2, 3, 4)
160
+
161
+ assert_equal(['ping6', '-c', '2', '-x', '4', 'example.test'], command)
162
+ ensure
163
+ RbConfig::CONFIG['host_os'] = original_os
164
+ Open3.define_singleton_method(:popen3, original_popen3)
165
+ end
166
+
167
+ test "ping6 uses interval for macOS" do
168
+ command = nil
169
+ original_os = RbConfig::CONFIG['host_os']
170
+ original_popen3 = Open3.method(:popen3)
171
+
172
+ RbConfig::CONFIG['host_os'] = 'darwin'
173
+ Open3.define_singleton_method(:popen3) do |*args, &block|
174
+ command = args
175
+ stdin = StringIO.new
176
+ stdout = StringIO.new
177
+ stderr = StringIO.new
178
+ status = Struct.new(:exitstatus).new(0)
179
+ thread = Struct.new(:value).new(status)
180
+ block.call(stdin, stdout, stderr, thread)
181
+ end
182
+
183
+ @pe.ping6('example.test', 2, 3, 4)
184
+
185
+ assert_equal(['ping6', '-c', '2', '-i', '3', 'example.test'], command)
186
+ ensure
187
+ RbConfig::CONFIG['host_os'] = original_os
188
+ Open3.define_singleton_method(:popen3, original_popen3)
189
+ end
190
+
191
+ test "ping6 succeeds without an exception when stderr is empty" do
192
+ stdin = StringIO.new
193
+ stdout = StringIO.new('64 bytes from ::1')
194
+ stderr = StringIO.new
195
+ status = Struct.new(:exitstatus).new(0)
196
+ thread = Struct.new(:value).new(status)
197
+ popen3 = Open3.method(:popen3)
198
+ nil_match = NilClass.instance_method(:=~) if NilClass.instance_methods(false).include?(:=~)
199
+ false_match = FalseClass.instance_method(:=~) if FalseClass.instance_methods(false).include?(:=~)
200
+
201
+ Open3.singleton_class.send(:define_method, :popen3) do |*args, &block|
202
+ block.call(stdin, stdout, stderr, thread)
203
+ end
204
+ [NilClass, FalseClass].each do |klass|
205
+ klass.send(:define_method, :=~) do |*args|
206
+ raise NoMethodError, "undefined method '=~' for #{self.inspect}"
207
+ end
208
+ end
209
+
210
+ assert_true(@pe.ping6('::1'))
211
+ assert_nil(@pe.exception)
212
+ ensure
213
+ Open3.singleton_class.send(:define_method, :popen3, popen3) if popen3
214
+ if nil_match
215
+ NilClass.send(:define_method, :=~, nil_match)
216
+ else
217
+ NilClass.send(:remove_method, :=~)
218
+ end
219
+ if false_match
220
+ FalseClass.send(:define_method, :=~, false_match)
221
+ else
222
+ FalseClass.send(:remove_method, :=~)
223
+ end
224
+ end
225
+
226
+ def teardown
227
+ @host = nil
228
+ @bogus = nil
229
+ @pe = nil
230
+ @bad = nil
231
+ end
232
+ end