em-ssh 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/em-ssh.rb +2 -0
- data/lib/em-ssh/callbacks.rb +1 -0
- data/lib/em-ssh/connection.rb +40 -3
- data/lib/em-ssh/packet-stream.rb +6 -0
- data/lib/em-ssh/session.rb +45 -2
- data/lib/em-ssh/shell.rb +16 -3
- data/lib/em-ssh/version.rb +1 -1
- metadata +2 -2
data/lib/em-ssh.rb
CHANGED
@@ -26,6 +26,8 @@ module EventMachine
|
|
26
26
|
class ConnectionFailed < SshError; end
|
27
27
|
class ConnectionTimeout < ConnectionFailed; end
|
28
28
|
class ConnectionTerminated < SshError; end
|
29
|
+
# The server failed to negotiate an ssh protocol version
|
30
|
+
class NegotiationTimeout < ConnectionFailed; end
|
29
31
|
|
30
32
|
|
31
33
|
class << self
|
data/lib/em-ssh/callbacks.rb
CHANGED
@@ -90,6 +90,7 @@ module EventMachine
|
|
90
90
|
def cancel
|
91
91
|
raise "#{@obj} does not have any callbacks for #{@event.inspect}" unless @obj.respond_to?(:callbacks) && @obj.callbacks.respond_to?(:[]) && @obj.callbacks[@event].respond_to?(:delete)
|
92
92
|
@obj.callbacks[@event].delete(self)
|
93
|
+
@obj = nil
|
93
94
|
self
|
94
95
|
end # cancel
|
95
96
|
end # class::Callback
|
data/lib/em-ssh/connection.rb
CHANGED
@@ -100,11 +100,35 @@ module EventMachine
|
|
100
100
|
@data = @socket.input
|
101
101
|
end # post_init
|
102
102
|
|
103
|
-
# @return
|
104
103
|
def unbind
|
105
104
|
debug("#{self} is unbound")
|
106
105
|
fire(:closed)
|
107
106
|
@closed = true
|
107
|
+
@socket && @socket.close
|
108
|
+
@socket = nil
|
109
|
+
@data = nil
|
110
|
+
@error_callback = nil
|
111
|
+
|
112
|
+
failed_timeout = [@contimeout, @negotimeout, @algotimeout].find { |t| t }
|
113
|
+
instance_variables.each do |iv|
|
114
|
+
if (t = instance_variable_get(iv)) && (t.is_a?(EM::Timer) || t.is_a?(EM::PeriodicTimer))
|
115
|
+
t.cancel
|
116
|
+
instance_variable_set(iv, nil)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if @algorithms
|
121
|
+
@algorithms.instance_variable_set(:@session, nil)
|
122
|
+
@algorithms = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
callbacks.values.flatten.each(&:cancel)
|
126
|
+
callbacks.clear
|
127
|
+
instance_variables.select{|iv| (t = instance_variable_get(iv)) && t.is_a?(EM::Ssh::Callbacks::Callback) }.each do |iv|
|
128
|
+
instance_variable_set(iv, nil)
|
129
|
+
end
|
130
|
+
|
131
|
+
fail(NegotiationTimeout.new(@host)) if failed_timeout
|
108
132
|
end
|
109
133
|
|
110
134
|
def receive_data(data)
|
@@ -116,7 +140,7 @@ module EventMachine
|
|
116
140
|
def connection_completed
|
117
141
|
@contimeout.cancel
|
118
142
|
@nocon.cancel
|
119
|
-
end
|
143
|
+
end
|
120
144
|
|
121
145
|
def initialize(options = {})
|
122
146
|
debug("#{self.class}.new(#{options})")
|
@@ -129,7 +153,7 @@ module EventMachine
|
|
129
153
|
|
130
154
|
begin
|
131
155
|
on(:connected) do |session|
|
132
|
-
@connected
|
156
|
+
@connected = true
|
133
157
|
succeed(session, @host)
|
134
158
|
end
|
135
159
|
on(:error) do |e|
|
@@ -141,11 +165,20 @@ module EventMachine
|
|
141
165
|
fail(ConnectionFailed.new(@host))
|
142
166
|
close_connection
|
143
167
|
end
|
168
|
+
|
144
169
|
@contimeout = EM::Timer.new(@timeout) do
|
145
170
|
fail(ConnectionTimeout.new(@host))
|
146
171
|
close_connection
|
147
172
|
end
|
148
173
|
|
174
|
+
@negotimeout = EM::Timer.new(options[:nego_timeout] || @timeout) do
|
175
|
+
fail(NegotiationTimeout.new(@host))
|
176
|
+
end
|
177
|
+
|
178
|
+
@algotimeout = EM::Timer.new(options[:nego_timeout] || @timeout) do
|
179
|
+
fail(NegotiationTimeout.new(@host))
|
180
|
+
end
|
181
|
+
|
149
182
|
@nonego = on(:closed) do
|
150
183
|
fail(ConnectionTerminated.new(@host))
|
151
184
|
close_connection
|
@@ -160,12 +193,16 @@ module EventMachine
|
|
160
193
|
@host_key_verifier = select_host_key_verifier(options[:paranoid])
|
161
194
|
@server_version = ServerVersion.new(self)
|
162
195
|
on(:version_negotiated) do
|
196
|
+
@negotimeout.cancel
|
197
|
+
@negotimeout = nil
|
163
198
|
@data.consume!(@server_version.header.length)
|
164
199
|
@algorithms = Net::SSH::Transport::Algorithms.new(self, options)
|
165
200
|
|
166
201
|
register_data_handler
|
167
202
|
|
168
203
|
on_next(:algo_init) do
|
204
|
+
@algotimeout.cancel
|
205
|
+
@algotimeout = nil
|
169
206
|
auth = AuthenticationSession.new(self, options)
|
170
207
|
user = options.fetch(:user, user)
|
171
208
|
Fiber.new do
|
data/lib/em-ssh/packet-stream.rb
CHANGED
@@ -34,6 +34,12 @@ module EventMachine
|
|
34
34
|
@packet = nil
|
35
35
|
end # initialize(content="")
|
36
36
|
|
37
|
+
def close
|
38
|
+
# remove reference to the connection to facilitate Garbage Collection
|
39
|
+
return super.tap { @connection = nil } if respond_to?(:super)
|
40
|
+
@connection = nil
|
41
|
+
end
|
42
|
+
|
37
43
|
# Consumes n bytes from the buffer, where n is the current position
|
38
44
|
# unless otherwise specified. This is useful for removing data from the
|
39
45
|
# buffer that has previously been read, when you are expecting more data
|
data/lib/em-ssh/session.rb
CHANGED
@@ -3,7 +3,7 @@ module EventMachine
|
|
3
3
|
class Session < Net::SSH::Connection::Session
|
4
4
|
include Log
|
5
5
|
|
6
|
-
def initialize(transport, options
|
6
|
+
def initialize(transport, options={})
|
7
7
|
super(transport, options)
|
8
8
|
register_callbacks
|
9
9
|
end
|
@@ -28,6 +28,32 @@ module EventMachine
|
|
28
28
|
transport.send_message(msg)
|
29
29
|
end
|
30
30
|
|
31
|
+
# Override Net::SSH::Connection::Session#close to remove dangling references to
|
32
|
+
# EM::Ssh::Connections and EM::Ssh::Sessions. Also directly close local channels
|
33
|
+
# if the connection is already closed.
|
34
|
+
def close
|
35
|
+
if @chan_timer
|
36
|
+
@chan_timer.cancel
|
37
|
+
remove_instance_variable(:@chan_timer)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Net::SSH::Connection::Session#close doesn't check if the transport is
|
41
|
+
# closed. If it is then calling Channel#close will will not close the
|
42
|
+
# channel localy and the connection will just spin.
|
43
|
+
if transport.closed?
|
44
|
+
channels.each do |id, c|
|
45
|
+
c.instance_variable_set(:@connection, nil)
|
46
|
+
end
|
47
|
+
channels.clear
|
48
|
+
else
|
49
|
+
channels.each { |id, channel| channel.close }
|
50
|
+
loop { channels.any? && !transport.closed? }
|
51
|
+
end
|
52
|
+
# remove the reference to the connection to facilitate Garbage Collection
|
53
|
+
transport, @transport = @transport, nil
|
54
|
+
@listeners.clear
|
55
|
+
transport.close
|
56
|
+
end
|
31
57
|
|
32
58
|
private
|
33
59
|
|
@@ -41,12 +67,29 @@ module EventMachine
|
|
41
67
|
send(MAP[packet.type], packet)
|
42
68
|
end # |packet|
|
43
69
|
|
44
|
-
chan_timer = EM.add_periodic_timer(0.01) do
|
70
|
+
@chan_timer = EM.add_periodic_timer(0.01) do
|
45
71
|
# we need to check the channel for any data to send and tell it to process any input
|
46
72
|
# at some point we should override Channel#enqueue_pending_output, etc.,.
|
47
73
|
channels.each { |id, channel| channel.process unless channel.closing? }
|
48
74
|
end
|
49
75
|
end # register_callbacks
|
76
|
+
|
77
|
+
def channel_close(packet)
|
78
|
+
channel = channels[packet[:local_id]]
|
79
|
+
super(packet).tap do
|
80
|
+
# remove the connection reference to facilitate Garbage Collection
|
81
|
+
channel.instance_variable_set(:@connection, nil)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def channel_open_failure(packet)
|
86
|
+
channel = channels[packet[:local_id]]
|
87
|
+
super(packet).tap do
|
88
|
+
# remove the connection reference to facilitate Garbage Collection
|
89
|
+
channel.instance_variable_set(:@connection, nil)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
50
93
|
end # class::Session
|
51
94
|
end # class::Ssh
|
52
95
|
end # module::EventMachine
|
data/lib/em-ssh/shell.rb
CHANGED
@@ -93,11 +93,23 @@ module EventMachine
|
|
93
93
|
|
94
94
|
# Close the connection to the server and all child shells.
|
95
95
|
# Disconnected shells cannot be split.
|
96
|
-
def disconnect
|
96
|
+
def disconnect(timeout = nil)
|
97
|
+
if timeout
|
98
|
+
EM::Timer.new(timeout) { disconnect! }
|
99
|
+
end
|
97
100
|
close
|
98
|
-
session && session.close
|
101
|
+
@session && @session.close
|
102
|
+
disconnect!
|
99
103
|
end
|
100
104
|
|
105
|
+
def disconnect!
|
106
|
+
@session = nil
|
107
|
+
if @connection
|
108
|
+
@connection.close_connection
|
109
|
+
@connection = nil
|
110
|
+
end
|
111
|
+
end # disconnect!
|
112
|
+
|
101
113
|
# @return [Boolean] true if the session is still alive
|
102
114
|
def connected?
|
103
115
|
session && !session.closed?
|
@@ -108,7 +120,7 @@ module EventMachine
|
|
108
120
|
# Fires :closed event.
|
109
121
|
# @see Callbacks
|
110
122
|
def close
|
111
|
-
shell.close.tap{ debug("closing") } if shell.active?
|
123
|
+
shell.close.tap{ debug("closing") } if shell && shell.active?
|
112
124
|
@closed = true
|
113
125
|
children.each { |c| c.close }
|
114
126
|
fire(:closed)
|
@@ -305,6 +317,7 @@ module EventMachine
|
|
305
317
|
# @see #send_and_wait
|
306
318
|
# @param [String] d the data to send encoded as a string
|
307
319
|
def send_data(d, send_newline=true)
|
320
|
+
return unless shell
|
308
321
|
if send_newline
|
309
322
|
shell.send_data("#{d}#{line_terminator}")
|
310
323
|
else
|
data/lib/em-ssh/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|