hrr_rb_ssh 0.3.0.pre1 → 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.
- checksums.yaml +4 -4
- data/.gitignore +0 -3
- data/.travis.yml +1 -0
- data/README.md +208 -46
- data/demo/client.rb +71 -0
- data/demo/echo_server.rb +8 -3
- data/demo/more_flexible_auth.rb +105 -0
- data/demo/multi_step_auth.rb +99 -0
- data/demo/server.rb +10 -4
- data/demo/subsystem_echo_server.rb +8 -3
- data/hrr_rb_ssh.gemspec +6 -6
- data/lib/hrr_rb_ssh.rb +1 -1
- data/lib/hrr_rb_ssh/algorithm/publickey.rb +0 -1
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2.rb +12 -9
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/ecdsa_signature_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/signature.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss.rb +10 -7
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/signature.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa.rb +9 -6
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/signature.rb +2 -4
- data/lib/hrr_rb_ssh/authentication.rb +103 -22
- data/lib/hrr_rb_ssh/authentication/constant.rb +14 -0
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb +44 -7
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/context.rb +16 -9
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_request.rb +7 -6
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_response.rb +5 -2
- data/lib/hrr_rb_ssh/authentication/method/none.rb +23 -7
- data/lib/hrr_rb_ssh/authentication/method/none/context.rb +15 -7
- data/lib/hrr_rb_ssh/authentication/method/password.rb +28 -7
- data/lib/hrr_rb_ssh/authentication/method/password/context.rb +16 -7
- data/lib/hrr_rb_ssh/authentication/method/publickey.rb +63 -10
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm.rb +0 -1
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/functionable.rb +32 -8
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/signature_blob.rb +2 -4
- data/lib/hrr_rb_ssh/authentication/method/publickey/context.rb +11 -2
- data/lib/hrr_rb_ssh/client.rb +234 -0
- data/lib/hrr_rb_ssh/codable.rb +15 -13
- data/lib/hrr_rb_ssh/compat/ruby.rb +0 -1
- data/lib/hrr_rb_ssh/connection.rb +145 -75
- data/lib/hrr_rb_ssh/connection/channel.rb +342 -109
- data/lib/hrr_rb_ssh/connection/channel/channel_type/direct_tcpip.rb +24 -19
- data/lib/hrr_rb_ssh/connection/channel/channel_type/forwarded_tcpip.rb +24 -19
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session.rb +19 -12
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain.rb +0 -2
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain/chain_context.rb +0 -3
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/global_request_handler.rb +14 -12
- data/lib/hrr_rb_ssh/connection/request_handler.rb +1 -3
- data/lib/hrr_rb_ssh/connection/request_handler/reference_env_request_handler.rb +0 -2
- data/lib/hrr_rb_ssh/connection/request_handler/reference_exec_request_handler.rb +4 -6
- data/lib/hrr_rb_ssh/connection/request_handler/reference_pty_req_request_handler.rb +10 -12
- data/lib/hrr_rb_ssh/connection/request_handler/reference_shell_request_handler.rb +4 -6
- data/lib/hrr_rb_ssh/connection/request_handler/reference_window_change_request_handler.rb +0 -2
- data/lib/hrr_rb_ssh/error/closed_authentication.rb +1 -1
- data/lib/hrr_rb_ssh/error/closed_connection.rb +1 -1
- data/lib/hrr_rb_ssh/error/closed_transport.rb +1 -1
- data/lib/hrr_rb_ssh/loggable.rb +42 -0
- data/lib/hrr_rb_ssh/message/001_ssh_msg_disconnect.rb +2 -4
- data/lib/hrr_rb_ssh/message/002_ssh_msg_ignore.rb +2 -4
- data/lib/hrr_rb_ssh/message/003_ssh_msg_unimplemented.rb +2 -4
- data/lib/hrr_rb_ssh/message/004_ssh_msg_debug.rb +2 -4
- data/lib/hrr_rb_ssh/message/005_ssh_msg_service_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/006_ssh_msg_service_accept.rb +2 -4
- data/lib/hrr_rb_ssh/message/020_ssh_msg_kexinit.rb +2 -4
- data/lib/hrr_rb_ssh/message/021_ssh_msg_newkeys.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kex_dh_gex_request_old.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kexdh_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kexecdh_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kex_dh_gex_group.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kexdh_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kexecdh_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/032_ssh_msg_kex_dh_gex_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/033_ssh_msg_kex_dh_gex_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/034_ssh_msg_kex_dh_gex_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/050_ssh_msg_userauth_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/051_ssh_msg_userauth_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/052_ssh_msg_userauth_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_info_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_pk_ok.rb +2 -4
- data/lib/hrr_rb_ssh/message/061_ssh_msg_userauth_info_response.rb +2 -4
- data/lib/hrr_rb_ssh/message/080_ssh_msg_global_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/081_ssh_msg_request_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/082_ssh_msg_request_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/090_ssh_msg_channel_open.rb +2 -4
- data/lib/hrr_rb_ssh/message/091_ssh_msg_channel_open_confirmation.rb +2 -4
- data/lib/hrr_rb_ssh/message/092_ssh_msg_channel_open_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/093_ssh_msg_channel_window_adjust.rb +2 -4
- data/lib/hrr_rb_ssh/message/094_ssh_msg_channel_data.rb +2 -4
- data/lib/hrr_rb_ssh/message/095_ssh_msg_channel_extended_data.rb +2 -4
- data/lib/hrr_rb_ssh/message/096_ssh_msg_channel_eof.rb +2 -4
- data/lib/hrr_rb_ssh/message/097_ssh_msg_channel_close.rb +2 -4
- data/lib/hrr_rb_ssh/message/098_ssh_msg_channel_request.rb +3 -5
- data/lib/hrr_rb_ssh/message/099_ssh_msg_channel_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/100_ssh_msg_channel_failure.rb +2 -4
- data/lib/hrr_rb_ssh/server.rb +16 -10
- data/lib/hrr_rb_ssh/transport.rb +113 -77
- data/lib/hrr_rb_ssh/transport/compression_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/compression_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +43 -37
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange.rb +87 -52
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman.rb +43 -37
- data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/mac_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/mac_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/receiver.rb +8 -7
- data/lib/hrr_rb_ssh/transport/sender.rb +5 -3
- data/lib/hrr_rb_ssh/transport/sequence_number.rb +0 -4
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +0 -1
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/version.rb +1 -1
- metadata +18 -51
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519.rb +0 -61
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key.rb +0 -29
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content.rb +0 -26
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey.rb +0 -158
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob.rb +0 -23
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature.rb +0 -23
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519.rb +0 -21
- data/lib/hrr_rb_ssh/compat/ruby/array.rb +0 -14
- data/lib/hrr_rb_ssh/logger.rb +0 -56
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519.rb +0 -20
@@ -2,12 +2,16 @@
|
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
4
|
require 'socket'
|
5
|
-
require '
|
5
|
+
require 'thread'
|
6
|
+
require 'monitor'
|
7
|
+
require 'hrr_rb_ssh/loggable'
|
6
8
|
require 'hrr_rb_ssh/connection/channel/channel_type'
|
7
9
|
|
8
10
|
module HrrRbSsh
|
9
11
|
class Connection
|
10
12
|
class Channel
|
13
|
+
include Loggable
|
14
|
+
|
11
15
|
INITIAL_WINDOW_SIZE = 100000
|
12
16
|
MAXIMUM_PACKET_SIZE = 100000
|
13
17
|
|
@@ -19,10 +23,11 @@ module HrrRbSsh
|
|
19
23
|
:local_maximum_packet_size,
|
20
24
|
:remote_window_size,
|
21
25
|
:remote_maximum_packet_size,
|
22
|
-
:receive_message_queue
|
26
|
+
:receive_message_queue,
|
27
|
+
:exit_status
|
23
28
|
|
24
|
-
def initialize connection, message, socket=nil
|
25
|
-
|
29
|
+
def initialize connection, message, socket=nil, logger: nil
|
30
|
+
self.logger = logger
|
26
31
|
|
27
32
|
@connection = connection
|
28
33
|
|
@@ -34,64 +39,85 @@ module HrrRbSsh
|
|
34
39
|
@remote_window_size = message[:'initial window size']
|
35
40
|
@remote_maximum_packet_size = message[:'maximum packet size']
|
36
41
|
|
37
|
-
@channel_type_instance = ChannelType[@channel_type].new connection, self, message, socket
|
42
|
+
@channel_type_instance = ChannelType[@channel_type].new connection, self, message, socket, logger: logger
|
38
43
|
|
39
44
|
@receive_message_queue = Queue.new
|
40
45
|
@receive_data_queue = Queue.new
|
46
|
+
@receive_extended_data_queue = Queue.new
|
41
47
|
|
42
48
|
@r_io_in, @w_io_in = IO.pipe
|
43
49
|
@r_io_out, @w_io_out = IO.pipe
|
44
50
|
@r_io_err, @w_io_err = IO.pipe
|
45
51
|
|
52
|
+
@channel_closing_monitor = Monitor.new
|
53
|
+
|
46
54
|
@closed = nil
|
55
|
+
@exit_status = nil
|
47
56
|
end
|
48
57
|
|
49
58
|
def set_remote_parameters message
|
50
59
|
@remote_channel = message[:'sender channel']
|
51
|
-
@remote_window_size
|
60
|
+
@remote_window_size = message[:'initial window size']
|
52
61
|
@remote_maximum_packet_size = message[:'maximum packet size']
|
53
62
|
end
|
54
63
|
|
55
64
|
def io
|
56
|
-
|
65
|
+
case @connection.mode
|
66
|
+
when Mode::SERVER
|
67
|
+
[@r_io_in, @w_io_out, @w_io_err]
|
68
|
+
when Mode::CLIENT
|
69
|
+
[@w_io_in, @r_io_out, @r_io_err]
|
70
|
+
end
|
57
71
|
end
|
58
72
|
|
59
73
|
def start
|
60
74
|
@channel_loop_thread = channel_loop_thread
|
61
|
-
@
|
62
|
-
|
63
|
-
|
64
|
-
|
75
|
+
case @connection.mode
|
76
|
+
when Mode::SERVER
|
77
|
+
@out_sender_thread = out_sender_thread
|
78
|
+
@err_sender_thread = err_sender_thread
|
79
|
+
@receiver_thread = receiver_thread
|
80
|
+
@channel_type_instance.start
|
81
|
+
when Mode::CLIENT
|
82
|
+
@out_receiver_thread = out_receiver_thread
|
83
|
+
@err_receiver_thread = err_receiver_thread
|
84
|
+
@sender_thread = sender_thread
|
85
|
+
@channel_type_instance.start
|
86
|
+
end
|
65
87
|
@closed = false
|
88
|
+
log_debug { "in start: #{@waiting_thread.inspect}" }
|
89
|
+
@waiting_thread.wakeup if @waiting_thread
|
90
|
+
end
|
91
|
+
|
92
|
+
def wait_until_started
|
93
|
+
@waiting_thread = Thread.current
|
94
|
+
log_debug { "in wait_until_started: #{@waiting_thread.inspect}" }
|
95
|
+
Thread.stop
|
66
96
|
end
|
67
97
|
|
68
98
|
def wait_until_senders_closed
|
69
|
-
[
|
99
|
+
[
|
100
|
+
@out_sender_thread,
|
101
|
+
@err_sender_thread,
|
102
|
+
].each{ |t|
|
70
103
|
begin
|
71
|
-
|
72
|
-
rescue
|
73
|
-
|
104
|
+
t.join if t.instance_of? Thread
|
105
|
+
rescue => e
|
106
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
74
107
|
end
|
75
108
|
}
|
76
|
-
[@out_sender_thread, @err_sender_thread].select{ |t| t.instance_of? Thread }.each(&:join)
|
77
109
|
end
|
78
110
|
|
79
111
|
def close from=:outside, exitstatus=0
|
80
|
-
|
81
|
-
|
82
|
-
|
112
|
+
@channel_closing_monitor.synchronize {
|
113
|
+
return if @closed
|
114
|
+
log_info { "close channel" }
|
115
|
+
@closed = true
|
116
|
+
}
|
83
117
|
unless from == :channel_type_instance
|
84
118
|
@channel_type_instance.close
|
85
119
|
end
|
86
120
|
@receive_message_queue.close
|
87
|
-
@receive_data_queue.close
|
88
|
-
[@r_io_in, @w_io_in, @r_io_out, @w_io_out, @r_io_err, @w_io_err].each{ |io|
|
89
|
-
begin
|
90
|
-
io.close
|
91
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
92
|
-
Thread.pass
|
93
|
-
end
|
94
|
-
}
|
95
121
|
begin
|
96
122
|
if from == :channel_type_instance
|
97
123
|
send_channel_eof
|
@@ -99,16 +125,36 @@ module HrrRbSsh
|
|
99
125
|
when Integer
|
100
126
|
send_channel_request_exit_status exitstatus
|
101
127
|
else
|
102
|
-
|
128
|
+
log_warn { "skip sending exit-status because exitstatus is not an instance of Integer" }
|
103
129
|
end
|
130
|
+
elsif from == :sender_thread
|
131
|
+
send_channel_eof
|
104
132
|
end
|
105
133
|
send_channel_close
|
106
134
|
rescue Error::ClosedConnection => e
|
107
135
|
Thread.pass
|
108
136
|
rescue => e
|
109
|
-
|
137
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
110
138
|
end
|
111
|
-
|
139
|
+
log_info { "channel closed" }
|
140
|
+
end
|
141
|
+
|
142
|
+
def wait_until_closed
|
143
|
+
[
|
144
|
+
@out_sender_thread,
|
145
|
+
@err_sender_thread,
|
146
|
+
@receiver_thread,
|
147
|
+
@out_receiver_thread,
|
148
|
+
@err_receiver_thread,
|
149
|
+
@sender_thread,
|
150
|
+
@channel_loop_thread
|
151
|
+
].each{ |t|
|
152
|
+
begin
|
153
|
+
t.join if t.instance_of? Thread
|
154
|
+
rescue => e
|
155
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
156
|
+
end
|
157
|
+
}
|
112
158
|
end
|
113
159
|
|
114
160
|
def closed?
|
@@ -117,56 +163,72 @@ module HrrRbSsh
|
|
117
163
|
|
118
164
|
def channel_loop_thread
|
119
165
|
Thread.start do
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
166
|
+
log_info { "start channel loop thread" }
|
167
|
+
begin
|
168
|
+
loop do
|
169
|
+
begin
|
170
|
+
message = @receive_message_queue.deq
|
171
|
+
if message.nil? && @receive_message_queue.closed?
|
172
|
+
break
|
173
|
+
end
|
174
|
+
case message[:'message number']
|
175
|
+
when Message::SSH_MSG_CHANNEL_EOF::VALUE
|
176
|
+
@receive_data_queue.close
|
177
|
+
@receive_extended_data_queue.close
|
178
|
+
when Message::SSH_MSG_CHANNEL_REQUEST::VALUE
|
179
|
+
log_info { "received channel request: #{message[:'request type']}" }
|
180
|
+
case @connection.mode
|
181
|
+
when Mode::SERVER
|
182
|
+
begin
|
183
|
+
@channel_type_instance.request message
|
184
|
+
rescue => e
|
185
|
+
log_warn { "request failed: #{e.message}" }
|
186
|
+
send_channel_failure if message[:'want reply']
|
187
|
+
else
|
188
|
+
send_channel_success if message[:'want reply']
|
189
|
+
end
|
190
|
+
when Mode::CLIENT
|
191
|
+
case message[:'request type']
|
192
|
+
when "exit-status"
|
193
|
+
log_info { "exit status: #{message[:'exit status']}" }
|
194
|
+
@exit_status = message[:'exit status'].to_i
|
195
|
+
end
|
138
196
|
end
|
197
|
+
when Message::SSH_MSG_CHANNEL_DATA::VALUE
|
198
|
+
log_info { "received channel data" }
|
199
|
+
local_channel = message[:'recipient channel']
|
200
|
+
@receive_data_queue.enq message[:'data']
|
201
|
+
when Message::SSH_MSG_CHANNEL_EXTENDED_DATA::VALUE
|
202
|
+
log_info { "received channel extended data" }
|
203
|
+
local_channel = message[:'recipient channel']
|
204
|
+
@receive_extended_data_queue.enq message[:'data']
|
205
|
+
when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
|
206
|
+
log_info { "received channel window adjust" }
|
207
|
+
@remote_window_size = [@remote_window_size + message[:'bytes to add'], 0xffff_ffff].min
|
139
208
|
else
|
140
|
-
|
141
|
-
send_channel_success
|
142
|
-
end
|
209
|
+
log_warn { "received unsupported message: #{message.inspect}" }
|
143
210
|
end
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
|
149
|
-
@logger.debug { "received channel window adjust" }
|
150
|
-
@remote_window_size = [@remote_window_size + message[:'bytes to add'], 0xffff_ffff].min
|
151
|
-
else
|
152
|
-
@logger.warn { "received unsupported message: #{message.inspect}" }
|
211
|
+
rescue => e
|
212
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
213
|
+
close from=:channel_loop_thread
|
214
|
+
break
|
153
215
|
end
|
154
|
-
rescue => e
|
155
|
-
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
156
|
-
close from=:channel_loop_thread
|
157
|
-
break
|
158
216
|
end
|
217
|
+
ensure
|
218
|
+
log_info { "closing channel loop thread" }
|
219
|
+
@receive_data_queue.close
|
220
|
+
@receive_extended_data_queue.close
|
159
221
|
end
|
160
|
-
|
222
|
+
log_info { "channel loop thread closed" }
|
161
223
|
end
|
162
224
|
end
|
163
225
|
|
164
226
|
def out_sender_thread
|
165
227
|
Thread.start {
|
166
|
-
|
228
|
+
log_info { "start out sender thread" }
|
167
229
|
loop do
|
168
230
|
if @r_io_out.closed?
|
169
|
-
|
231
|
+
log_info { "closing out sender thread" }
|
170
232
|
break
|
171
233
|
end
|
172
234
|
begin
|
@@ -175,30 +237,24 @@ module HrrRbSsh
|
|
175
237
|
sending_data = data[0, sendable_size]
|
176
238
|
send_channel_data sending_data if sendable_size > 0
|
177
239
|
@remote_window_size -= sendable_size
|
178
|
-
rescue EOFError => e
|
179
|
-
|
180
|
-
@r_io_out.close
|
181
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
182
|
-
Thread.pass
|
183
|
-
end
|
184
|
-
rescue IOError => e
|
185
|
-
@logger.warn { "channel IO is closed" }
|
186
|
-
close
|
240
|
+
rescue EOFError, IOError => e
|
241
|
+
@r_io_out.close rescue nil
|
187
242
|
rescue => e
|
188
|
-
|
243
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
244
|
+
@r_io_out.close rescue nil
|
189
245
|
close
|
190
246
|
end
|
191
247
|
end
|
192
|
-
|
248
|
+
log_info { "out sender thread closed" }
|
193
249
|
}
|
194
250
|
end
|
195
251
|
|
196
252
|
def err_sender_thread
|
197
253
|
Thread.start {
|
198
|
-
|
254
|
+
log_info { "start err sender thread" }
|
199
255
|
loop do
|
200
256
|
if @r_io_err.closed?
|
201
|
-
|
257
|
+
log_info { "closing err sender thread" }
|
202
258
|
break
|
203
259
|
end
|
204
260
|
begin
|
@@ -207,55 +263,140 @@ module HrrRbSsh
|
|
207
263
|
sending_data = data[0, sendable_size]
|
208
264
|
send_channel_extended_data sending_data if sendable_size > 0
|
209
265
|
@remote_window_size -= sendable_size
|
210
|
-
rescue EOFError => e
|
211
|
-
|
212
|
-
@r_io_err.close
|
213
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
214
|
-
Thread.pass
|
215
|
-
end
|
216
|
-
rescue IOError => e
|
217
|
-
@logger.warn { "channel IO is closed" }
|
218
|
-
close
|
266
|
+
rescue EOFError, IOError => e
|
267
|
+
@r_io_err.close rescue nil
|
219
268
|
rescue => e
|
220
|
-
|
269
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
270
|
+
@r_io_err.close rescue nil
|
221
271
|
close
|
222
272
|
end
|
223
273
|
end
|
224
|
-
|
274
|
+
log_info { "err sender thread closed" }
|
225
275
|
}
|
226
276
|
end
|
227
277
|
|
228
278
|
def receiver_thread
|
229
279
|
Thread.start {
|
230
|
-
|
280
|
+
log_info { "start receiver thread" }
|
231
281
|
loop do
|
232
282
|
begin
|
233
283
|
data = @receive_data_queue.deq
|
234
284
|
if data.nil? && @receive_data_queue.closed?
|
235
|
-
|
236
|
-
|
237
|
-
@w_io_in.
|
238
|
-
|
285
|
+
log_info { "closing receiver thread" }
|
286
|
+
log_info { "closing w_io_in" }
|
287
|
+
@w_io_in.close
|
288
|
+
log_info { "w_io_in closed" }
|
239
289
|
break
|
240
290
|
end
|
241
291
|
@w_io_in.write data
|
242
292
|
@local_window_size -= data.size
|
243
293
|
if @local_window_size < INITIAL_WINDOW_SIZE/2
|
244
|
-
|
294
|
+
log_info { "send channel window adjust" }
|
245
295
|
send_channel_window_adjust
|
246
296
|
@local_window_size += INITIAL_WINDOW_SIZE
|
247
297
|
end
|
248
|
-
rescue IOError => e
|
249
|
-
@logger.warn { "channel IO is closed" }
|
298
|
+
rescue Errno::EPIPE, IOError => e
|
250
299
|
close
|
251
300
|
break
|
252
301
|
rescue => e
|
253
|
-
|
302
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
254
303
|
close
|
255
304
|
break
|
256
305
|
end
|
257
306
|
end
|
258
|
-
|
307
|
+
log_info { "receiver thread closed" }
|
308
|
+
}
|
309
|
+
end
|
310
|
+
|
311
|
+
def out_receiver_thread
|
312
|
+
Thread.start {
|
313
|
+
log_info { "start out receiver thread" }
|
314
|
+
loop do
|
315
|
+
begin
|
316
|
+
data = @receive_data_queue.deq
|
317
|
+
if data.nil? && @receive_data_queue.closed?
|
318
|
+
log_info { "closing out receiver thread" }
|
319
|
+
log_info { "closing w_io_out" }
|
320
|
+
@w_io_out.close
|
321
|
+
log_info { "w_io_out closed" }
|
322
|
+
break
|
323
|
+
end
|
324
|
+
@w_io_out.write data
|
325
|
+
@local_window_size -= data.size
|
326
|
+
if @local_window_size < INITIAL_WINDOW_SIZE/2
|
327
|
+
log_info { "send channel window adjust" }
|
328
|
+
send_channel_window_adjust
|
329
|
+
@local_window_size += INITIAL_WINDOW_SIZE
|
330
|
+
end
|
331
|
+
rescue Errno::EPIPE, IOError => e
|
332
|
+
close
|
333
|
+
break
|
334
|
+
rescue => e
|
335
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
336
|
+
close
|
337
|
+
break
|
338
|
+
end
|
339
|
+
end
|
340
|
+
log_info { "out receiver thread closed" }
|
341
|
+
}
|
342
|
+
end
|
343
|
+
|
344
|
+
def err_receiver_thread
|
345
|
+
Thread.start {
|
346
|
+
log_info { "start err receiver thread" }
|
347
|
+
loop do
|
348
|
+
begin
|
349
|
+
data = @receive_extended_data_queue.deq
|
350
|
+
if data.nil? && @receive_extended_data_queue.closed?
|
351
|
+
log_info { "closing err receiver thread" }
|
352
|
+
log_info { "closing w_io_err" }
|
353
|
+
@w_io_err.close
|
354
|
+
log_info { "w_io_err closed" }
|
355
|
+
break
|
356
|
+
end
|
357
|
+
@w_io_err.write data
|
358
|
+
@local_window_size -= data.size
|
359
|
+
if @local_window_size < INITIAL_WINDOW_SIZE/2
|
360
|
+
log_info { "send channel window adjust" }
|
361
|
+
send_channel_window_adjust
|
362
|
+
@local_window_size += INITIAL_WINDOW_SIZE
|
363
|
+
end
|
364
|
+
rescue Error::EPIPE, IOError => e
|
365
|
+
close
|
366
|
+
break
|
367
|
+
rescue => e
|
368
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
369
|
+
close
|
370
|
+
break
|
371
|
+
end
|
372
|
+
end
|
373
|
+
log_info { "err receiver thread closed" }
|
374
|
+
}
|
375
|
+
end
|
376
|
+
|
377
|
+
def sender_thread
|
378
|
+
Thread.start {
|
379
|
+
log_info { "start sender thread" }
|
380
|
+
loop do
|
381
|
+
if @r_io_in.closed?
|
382
|
+
log_info { "closing sender thread" }
|
383
|
+
break
|
384
|
+
end
|
385
|
+
begin
|
386
|
+
data = @r_io_in.readpartial(10240)
|
387
|
+
sendable_size = [data.size, @remote_window_size].min
|
388
|
+
sending_data = data[0, sendable_size]
|
389
|
+
send_channel_data sending_data if sendable_size > 0
|
390
|
+
@remote_window_size -= sendable_size
|
391
|
+
rescue EOFError, IOError => e
|
392
|
+
@r_io_in.close rescue nil
|
393
|
+
rescue => e
|
394
|
+
log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
395
|
+
@r_io_in.close rescue nil
|
396
|
+
end
|
397
|
+
end
|
398
|
+
close from=:sender_thread
|
399
|
+
log_info { "sender thread closed" }
|
259
400
|
}
|
260
401
|
end
|
261
402
|
|
@@ -264,7 +405,7 @@ module HrrRbSsh
|
|
264
405
|
:'message number' => Message::SSH_MSG_CHANNEL_SUCCESS::VALUE,
|
265
406
|
:'recipient channel' => @remote_channel,
|
266
407
|
}
|
267
|
-
payload = Message::SSH_MSG_CHANNEL_SUCCESS.encode message
|
408
|
+
payload = Message::SSH_MSG_CHANNEL_SUCCESS.new(logger: logger).encode message
|
268
409
|
@connection.send payload
|
269
410
|
end
|
270
411
|
|
@@ -273,7 +414,7 @@ module HrrRbSsh
|
|
273
414
|
:'message number' => Message::SSH_MSG_CHANNEL_FAILURE::VALUE,
|
274
415
|
:'recipient channel' => @remote_channel,
|
275
416
|
}
|
276
|
-
payload = Message::SSH_MSG_CHANNEL_FAILURE.encode message
|
417
|
+
payload = Message::SSH_MSG_CHANNEL_FAILURE.new(logger: logger).encode message
|
277
418
|
@connection.send payload
|
278
419
|
end
|
279
420
|
|
@@ -283,7 +424,7 @@ module HrrRbSsh
|
|
283
424
|
:'recipient channel' => @remote_channel,
|
284
425
|
:'bytes to add' => INITIAL_WINDOW_SIZE,
|
285
426
|
}
|
286
|
-
payload = Message::SSH_MSG_CHANNEL_WINDOW_ADJUST.encode message
|
427
|
+
payload = Message::SSH_MSG_CHANNEL_WINDOW_ADJUST.new(logger: logger).encode message
|
287
428
|
@connection.send payload
|
288
429
|
end
|
289
430
|
|
@@ -293,7 +434,7 @@ module HrrRbSsh
|
|
293
434
|
:'recipient channel' => @remote_channel,
|
294
435
|
:'data' => data,
|
295
436
|
}
|
296
|
-
payload = Message::SSH_MSG_CHANNEL_DATA.encode message
|
437
|
+
payload = Message::SSH_MSG_CHANNEL_DATA.new(logger: logger).encode message
|
297
438
|
@connection.send payload
|
298
439
|
end
|
299
440
|
|
@@ -304,7 +445,99 @@ module HrrRbSsh
|
|
304
445
|
:'data type code' => code,
|
305
446
|
:'data' => data,
|
306
447
|
}
|
307
|
-
payload = Message::SSH_MSG_CHANNEL_EXTENDED_DATA.encode message
|
448
|
+
payload = Message::SSH_MSG_CHANNEL_EXTENDED_DATA.new(logger: logger).encode message
|
449
|
+
@connection.send payload
|
450
|
+
end
|
451
|
+
|
452
|
+
def send_channel_request_pty_req term_env_var_val, term_width_chars, term_height_rows, term_width_pixel, term_height_pixel, encoded_term_modes
|
453
|
+
message = {
|
454
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
455
|
+
:'recipient channel' => @remote_channel,
|
456
|
+
:'request type' => "pty-req",
|
457
|
+
:'want reply' => false,
|
458
|
+
:'TERM environment variable value' => term_env_var_val,
|
459
|
+
:'terminal width, characters' => term_width_chars,
|
460
|
+
:'terminal height, rows' => term_height_rows,
|
461
|
+
:'terminal width, pixels' => term_width_pixel,
|
462
|
+
:'terminal height, pixels' => term_height_pixel,
|
463
|
+
:'encoded terminal modes' => encoded_term_modes,
|
464
|
+
}
|
465
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
466
|
+
@connection.send payload
|
467
|
+
end
|
468
|
+
|
469
|
+
def send_channel_request_env variable_name, variable_value
|
470
|
+
message = {
|
471
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
472
|
+
:'recipient channel' => @remote_channel,
|
473
|
+
:'request type' => "env",
|
474
|
+
:'want reply' => false,
|
475
|
+
:'variable name' => variable_name,
|
476
|
+
:'variable value' => variable_value,
|
477
|
+
}
|
478
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
479
|
+
@connection.send payload
|
480
|
+
end
|
481
|
+
|
482
|
+
def send_channel_request_shell
|
483
|
+
message = {
|
484
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
485
|
+
:'recipient channel' => @remote_channel,
|
486
|
+
:'request type' => "shell",
|
487
|
+
:'want reply' => false,
|
488
|
+
}
|
489
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
490
|
+
@connection.send payload
|
491
|
+
end
|
492
|
+
|
493
|
+
def send_channel_request_exec command
|
494
|
+
message = {
|
495
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
496
|
+
:'recipient channel' => @remote_channel,
|
497
|
+
:'request type' => "exec",
|
498
|
+
:'want reply' => false,
|
499
|
+
:'command' => command,
|
500
|
+
}
|
501
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
502
|
+
@connection.send payload
|
503
|
+
end
|
504
|
+
|
505
|
+
def send_channel_request_subsystem subsystem_name
|
506
|
+
message = {
|
507
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
508
|
+
:'recipient channel' => @remote_channel,
|
509
|
+
:'request type' => "subsystem",
|
510
|
+
:'want reply' => false,
|
511
|
+
:'subsystem name' => subsystem_name,
|
512
|
+
}
|
513
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
514
|
+
@connection.send payload
|
515
|
+
end
|
516
|
+
|
517
|
+
def send_channel_request_window_change term_width_cols, term_height_rows, term_width_pixel, term_height_pixel
|
518
|
+
message = {
|
519
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
520
|
+
:'recipient channel' => @remote_channel,
|
521
|
+
:'request type' => "window-change",
|
522
|
+
:'want reply' => false,
|
523
|
+
:'terminal width, columns' => term_width_cols,
|
524
|
+
:'terminal height, rows' => term_height_rows,
|
525
|
+
:'terminal width, pixels' => term_width_pixel,
|
526
|
+
:'terminal height, pixels' => term_height_pixel,
|
527
|
+
}
|
528
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
529
|
+
@connection.send payload
|
530
|
+
end
|
531
|
+
|
532
|
+
def send_channel_request_signal signal_name
|
533
|
+
message = {
|
534
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
535
|
+
:'recipient channel' => @remote_channel,
|
536
|
+
:'request type' => "signal",
|
537
|
+
:'want reply' => false,
|
538
|
+
:'signal name' => signal_name,
|
539
|
+
}
|
540
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
308
541
|
@connection.send payload
|
309
542
|
end
|
310
543
|
|
@@ -316,7 +549,7 @@ module HrrRbSsh
|
|
316
549
|
:'want reply' => false,
|
317
550
|
:'exit status' => exitstatus,
|
318
551
|
}
|
319
|
-
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
552
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
|
320
553
|
@connection.send payload
|
321
554
|
end
|
322
555
|
|
@@ -325,7 +558,7 @@ module HrrRbSsh
|
|
325
558
|
:'message number' => Message::SSH_MSG_CHANNEL_EOF::VALUE,
|
326
559
|
:'recipient channel' => @remote_channel,
|
327
560
|
}
|
328
|
-
payload = Message::SSH_MSG_CHANNEL_EOF.encode message
|
561
|
+
payload = Message::SSH_MSG_CHANNEL_EOF.new(logger: logger).encode message
|
329
562
|
@connection.send payload
|
330
563
|
end
|
331
564
|
|
@@ -334,7 +567,7 @@ module HrrRbSsh
|
|
334
567
|
:'message number' => Message::SSH_MSG_CHANNEL_CLOSE::VALUE,
|
335
568
|
:'recipient channel' => @remote_channel,
|
336
569
|
}
|
337
|
-
payload = Message::SSH_MSG_CHANNEL_CLOSE.encode message
|
570
|
+
payload = Message::SSH_MSG_CHANNEL_CLOSE.new(logger: logger).encode message
|
338
571
|
@connection.send payload
|
339
572
|
end
|
340
573
|
end
|