This repository has been archived by the owner on Feb 18, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 65
/
external.rb
159 lines (140 loc) · 4.59 KB
/
external.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
require 'open3'
require 'rbconfig'
require File.join(File.dirname(__FILE__), 'ping')
# The Net module serves as a namespace only.
module Net
# The Ping::External class encapsulates methods for external (system) pings.
class Ping::External < Ping
ERR_MSG_SIZE = 4096
# 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)
pcmd = ['ping']
bool = false
case RbConfig::CONFIG['host_os']
when /linux/i
pcmd += ['-c', '1', '-W', @timeout.to_s, host]
when /bsd|osx|mach|darwin/i
pcmd += ['-c', '1', '-t', @timeout.to_s, host]
when /solaris|sunos/i
pcmd += [host, @timeout.to_s]
when /hpux/i
pcmd += [host, '-n1', '-m', @timeout.to_s]
when /win32|windows|msdos|mswin|cygwin|mingw/i
#pcmd += ['-n', '1', '-w', (1000 * @timeout).to_i.to_s, host]
pcmd += ['-n', '1', '-w', (@timeout * 1000).to_s, host]
else
pcmd += [host]
end
start_time = Time.now
begin
err = nil
Open3.popen3(*pcmd) do |stdin, stdout, stderr, thread|
err = stderr.gets # Can't chomp yet, might be nil
case thread.value.exitstatus
when 0
bool = true # Success, at least one response.
if err & err =~ /warning/i
@warning = err.chomp
end
when 2
bool = false # Transmission successful, no response.
@exception = err.chomp if err
else
bool = false # An error occurred
if err
@exception = err.chomp
else
stdout.each_line do |line|
if line =~ /(timed out|could not find host|packet loss)/i
@exception = line.chomp
break
end
end
end
end
end
rescue Exception => error
@exception = error.message
end
# There is no duration if the ping failed
@duration = Time.now - start_time if bool
bool
end
# Runs a specified shell command in a separate thread.
# If it exceeds the given timeout in seconds, kills it.
# Returns a list of the form
#
# [exit_code, err]
#
# which contains any output sent by the command to stderr as a String.
# Uses Kernel.select to wait up to the timeout length (in seconds)
# before killing the process spawned by Open3.
#
def run_with_timeout(*command)
err = nil
exit_code = nil
begin
# Start task in another thread, which spawns a process
stdin, stdout, stderr, thread = Open3.popen3(*command)
# Get the pid of the spawned process
pid = thread[:pid]
start = Time.now
while (Time.now - start) < timeout and thread.alive?
begin
err = stderr.read_nonblock(ERR_MSG_SIZE)
rescue IO::WaitReadable
IO.select([stderr], nil, nil, @timeout)
next
rescue EOFError
# Command has completed, not really an error...
break
end
end
if thread.alive?
# We need to kill the process, because killing the thread leaves
# the process alive but detached, annoyingly enough.
begin
Process.kill("TERM", pid)
err = "execution expired"
rescue Errno::ESRCH
# The process already exited, ignoring
end
end
# Join the thread and get its exit status
exit_code = thread.value.exitstatus
ensure
stdin.close if stdin
stdout.close if stdout
stderr.close if stderr
end
err ||= ''
return [exit_code, err]
end
# Runs a command without a timeout. The returned value
# is a list of the form
#
# [exit_code, err]
#
def run_no_timeout(*command)
out, err, exit_code = Open3.capture3(*command)
if exit_code != 0 and (err.nil? or err.empty?)
out.each_line do |line|
if line =~ /(timed out|could not find host)/i
err = line
break
end
end
end
return [exit_code, err]
end
alias ping? ping
alias pingecho ping
end
end