wping 0.1.0-mswin32
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.
- data/bin/ping.rb +51 -0
- data/lib/win32/ping.rb +149 -0
- metadata +47 -0
data/bin/ping.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
$: << File.join( File.dirname( __FILE__ ), '../lib' )
|
2
|
+
require 'win32/ping'
|
3
|
+
require 'resolv'
|
4
|
+
|
5
|
+
include Win32
|
6
|
+
|
7
|
+
size = 32
|
8
|
+
count = 4
|
9
|
+
forever = false
|
10
|
+
|
11
|
+
while arg = ARGV.shift
|
12
|
+
case arg
|
13
|
+
when /-t/
|
14
|
+
forever = true
|
15
|
+
else
|
16
|
+
host = arg
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
pinger = Win32::PingICMP.new
|
21
|
+
|
22
|
+
real_host = Resolv.new.getaddress( host )
|
23
|
+
host = "#{host} [#{real_host}]" unless host == real_host
|
24
|
+
puts "\nPinging #{host} with #{size} bytes of data:\n\n"
|
25
|
+
i = count
|
26
|
+
total = max = received = lost = 0
|
27
|
+
min = nil
|
28
|
+
|
29
|
+
while forever == true or i > 0
|
30
|
+
i -= 1
|
31
|
+
r = pinger.ping( real_host, 1, size ).first
|
32
|
+
if r.successful
|
33
|
+
puts "Reply from #{real_host}: bytes=#{size} time=#{r.round_trip_time} TTL=#{r.ttl}"
|
34
|
+
received += 1
|
35
|
+
min ||= r.round_trip_time
|
36
|
+
min = [min, r.round_trip_time].min
|
37
|
+
max = [max, r.round_trip_time].max
|
38
|
+
total += r.round_trip_time
|
39
|
+
else
|
40
|
+
puts "Ping failed"
|
41
|
+
lost += 1
|
42
|
+
end
|
43
|
+
sleep 1
|
44
|
+
end
|
45
|
+
|
46
|
+
avg = total.to_f / count
|
47
|
+
puts "\nPing statistics for #{real_host}:"
|
48
|
+
puts " Packets: Sent = #{count}, Received = #{received}, Lost = #{lost} (#{'%d'%[lost/count*100]}% loss),"
|
49
|
+
puts "Approximate round trip times in milli-seconds:"
|
50
|
+
puts " Minimum = #{min}ms, Maximum = #{max}ms, Average = #{avg}ms\n"
|
51
|
+
|
data/lib/win32/ping.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'Win32API'
|
2
|
+
require 'ipaddr'
|
3
|
+
require 'resolv'
|
4
|
+
require 'enumerator'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
class Integer
|
8
|
+
def to_ip
|
9
|
+
ip = []
|
10
|
+
self.to_s( 2 ).rjust( 32, "0" ).split(//).each_slice( 8 ) do |p|
|
11
|
+
ip << p.join.to_i( 2 )
|
12
|
+
end
|
13
|
+
ip.join '.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_w32ip
|
17
|
+
[self].pack( 'N' ).unpack( 'L' ).first
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class IPAddr
|
22
|
+
def to_w32ip
|
23
|
+
self.to_i.to_w32ip
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Win32; end
|
28
|
+
class Win32::PingICMP
|
29
|
+
@@icmp_create_file = Win32API.new( 'icmp', 'IcmpCreateFile', '', 'N' )
|
30
|
+
@@icmp_send_echo = Win32API.new( 'icmp', 'IcmpSendEcho', 'NNPIPPNN', 'N' )
|
31
|
+
@@icmp_close_handle = Win32API.new( 'icmp', 'IcmpCloseHandle', 'N', 'I' )
|
32
|
+
@@resolv = Resolv.new
|
33
|
+
|
34
|
+
IPFLAG_DONT_FRAGMENT = 0x02
|
35
|
+
REPLY_BUFFER_SIZE = 1024
|
36
|
+
ICMP_ECHO_REPLY_SIZE = 28
|
37
|
+
|
38
|
+
# Low level, you probably shouldn't be using it
|
39
|
+
def self.icmp_create_file
|
40
|
+
handle = @@icmp_create_file.call
|
41
|
+
if block_given?
|
42
|
+
begin
|
43
|
+
yield handle
|
44
|
+
ensure
|
45
|
+
icmp_close_handle handle
|
46
|
+
handle = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
handle
|
50
|
+
end
|
51
|
+
|
52
|
+
# This is pretty low level and probably shouldn't be used, but since
|
53
|
+
# I believe in freedom, I have left it public just in case.
|
54
|
+
# I left out the data size and buffer size args because ruby can
|
55
|
+
# figure that out. int_ip is the int form of the ip address.
|
56
|
+
def self.icmp_send_echo handle, int_ip, request_data, request_options,
|
57
|
+
reply_buffer, timeout
|
58
|
+
@@icmp_send_echo.call( handle, int_ip, request_data, request_data.size,
|
59
|
+
request_options, reply_buffer, reply_buffer.size,
|
60
|
+
timeout )
|
61
|
+
end
|
62
|
+
|
63
|
+
# Low level. Are you sure you need this?
|
64
|
+
def self.icmp_close_handle handle
|
65
|
+
@@icmp_close_handle.call( handle )
|
66
|
+
end
|
67
|
+
|
68
|
+
# Low level.
|
69
|
+
def self.resolv hostname
|
70
|
+
@@resolv.getaddress hostname
|
71
|
+
end
|
72
|
+
|
73
|
+
# Some algorythm I found on line.
|
74
|
+
# This generates the buffer to ping with
|
75
|
+
def self.create_buffer size
|
76
|
+
b = []
|
77
|
+
1.upto size do |i|
|
78
|
+
# readable characters
|
79
|
+
b << i % 94 + 32
|
80
|
+
end
|
81
|
+
|
82
|
+
("%c"*size)%b
|
83
|
+
end
|
84
|
+
|
85
|
+
# heres what you want
|
86
|
+
def ping host, count = 1, size = 32, no_frag = false, ttl = 64, timeout = 4000
|
87
|
+
ip = nil
|
88
|
+
nresolv = false
|
89
|
+
begin
|
90
|
+
if nresolv
|
91
|
+
host = self.class.resolv host
|
92
|
+
end
|
93
|
+
ip = IPAddr.new( host )
|
94
|
+
rescue
|
95
|
+
unless nresolv
|
96
|
+
nresolv = true
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
raise $!
|
100
|
+
end
|
101
|
+
|
102
|
+
reply_buffer = "0" * ( size + ICMP_ECHO_REPLY_SIZE )
|
103
|
+
req_data = self.class.create_buffer size
|
104
|
+
replies = []
|
105
|
+
no_frag = no_frag ? IPFLAG_DONT_FRAGMENT : 0
|
106
|
+
# struct options
|
107
|
+
# u_char ttl
|
108
|
+
# u_char tos
|
109
|
+
# u_char flags
|
110
|
+
# u_char options_size
|
111
|
+
options = ("%c"*4)%[ttl,0,no_frag,0]
|
112
|
+
self.class.icmp_create_file do |handle|
|
113
|
+
count.times do
|
114
|
+
reply = OpenStruct.new
|
115
|
+
reply.reply_count = self.class.icmp_send_echo( handle, ip.to_w32ip,
|
116
|
+
req_data, options,
|
117
|
+
reply_buffer, timeout )
|
118
|
+
reply.request_data = req_data
|
119
|
+
reply.reply_data = reply_buffer[28..-1]
|
120
|
+
header = reply_buffer.unpack( 'NLLSSLCCCCL' )
|
121
|
+
reply.ip = header[0].to_ip
|
122
|
+
reply.status, reply.round_trip_time = header[1..2]
|
123
|
+
reply.data_size, reply.reserved = header[3..4]
|
124
|
+
# this is a pointer to the actual reply data. We assume
|
125
|
+
# that it is a 28 so we don't need it, maybe future versions
|
126
|
+
# will
|
127
|
+
#reply.pdata = header[5]
|
128
|
+
reply.time_to_live = reply.ttl = header[6]
|
129
|
+
reply.type_of_service = reply.tos = header[7]
|
130
|
+
reply.flags = header[8]
|
131
|
+
reply.options_size = header[9]
|
132
|
+
# this is a pointer to the optiondata, we don't need it
|
133
|
+
# but maybe future versions will
|
134
|
+
#reply.poptions_data = header[10]
|
135
|
+
# I was using this one for testing
|
136
|
+
#reply.reply_buffer = reply_buffer
|
137
|
+
reply.successful = ( reply.status == 0 )
|
138
|
+
replies << reply
|
139
|
+
end
|
140
|
+
end
|
141
|
+
def replies.all_successful?
|
142
|
+
self.find {|r| !r.successful }.nil?
|
143
|
+
end
|
144
|
+
def replies.one_successful?
|
145
|
+
!self.find {|r| r.successful}.nil?
|
146
|
+
end
|
147
|
+
replies
|
148
|
+
end
|
149
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: wping
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2006-11-20 00:00:00 -05:00
|
8
|
+
summary: ruby wrapper for win32api icmp.dll
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: rcorsaro@gmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: ruby wrapper for win32api icmp.dll
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: mswin32
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- rcorsaro
|
30
|
+
files:
|
31
|
+
- bin/ping.rb
|
32
|
+
- lib/win32
|
33
|
+
- lib/win32/ping.rb
|
34
|
+
test_files: []
|
35
|
+
|
36
|
+
rdoc_options: []
|
37
|
+
|
38
|
+
extra_rdoc_files: []
|
39
|
+
|
40
|
+
executables:
|
41
|
+
- ping.rb
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
requirements:
|
45
|
+
- none
|
46
|
+
dependencies: []
|
47
|
+
|