em-ssh 0.4.1 → 0.4.2
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/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
|