net-ssh 0.5.0
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/doc/LICENSE-BSD +27 -0
- data/doc/LICENSE-GPL +280 -0
- data/doc/LICENSE-RUBY +56 -0
- data/doc/README +13 -0
- data/doc/manual-html/chapter-1.html +333 -0
- data/doc/manual-html/chapter-2.html +455 -0
- data/doc/manual-html/chapter-3.html +413 -0
- data/doc/manual-html/chapter-4.html +353 -0
- data/doc/manual-html/chapter-5.html +393 -0
- data/doc/manual-html/chapter-6.html +296 -0
- data/doc/manual-html/index.html +217 -0
- data/doc/manual-html/manual.css +192 -0
- data/doc/manual/chapter.erb +18 -0
- data/doc/manual/example.erb +18 -0
- data/doc/manual/index.erb +29 -0
- data/doc/manual/manual.css +192 -0
- data/doc/manual/manual.rb +240 -0
- data/doc/manual/manual.yml +67 -0
- data/doc/manual/page.erb +87 -0
- data/doc/manual/parts/channels_callbacks.txt +32 -0
- data/doc/manual/parts/channels_loop.txt +14 -0
- data/doc/manual/parts/channels_open.txt +20 -0
- data/doc/manual/parts/channels_operations.txt +15 -0
- data/doc/manual/parts/channels_types.txt +3 -0
- data/doc/manual/parts/channels_what_are.txt +7 -0
- data/doc/manual/parts/exec_channels.txt +28 -0
- data/doc/manual/parts/exec_open.txt +51 -0
- data/doc/manual/parts/exec_popen3.txt +35 -0
- data/doc/manual/parts/forward_direct.txt +37 -0
- data/doc/manual/parts/forward_handlers.txt +16 -0
- data/doc/manual/parts/forward_intro.txt +18 -0
- data/doc/manual/parts/forward_local.txt +18 -0
- data/doc/manual/parts/forward_remote.txt +14 -0
- data/doc/manual/parts/intro_author.txt +1 -0
- data/doc/manual/parts/intro_getting.txt +39 -0
- data/doc/manual/parts/intro_license.txt +6 -0
- data/doc/manual/parts/intro_support.txt +7 -0
- data/doc/manual/parts/intro_what_is.txt +7 -0
- data/doc/manual/parts/intro_what_is_not.txt +3 -0
- data/doc/manual/parts/proxy_http.txt +52 -0
- data/doc/manual/parts/proxy_intro.txt +1 -0
- data/doc/manual/parts/proxy_socks.txt +23 -0
- data/doc/manual/parts/session_key.txt +66 -0
- data/doc/manual/parts/session_options.txt +42 -0
- data/doc/manual/parts/session_session.txt +14 -0
- data/doc/manual/parts/session_start.txt +49 -0
- data/doc/manual/tutorial.erb +30 -0
- data/examples/channel-demo.rb +81 -0
- data/examples/port-forward.rb +51 -0
- data/examples/process-demo.rb +91 -0
- data/examples/remote-net-port-forward.rb +45 -0
- data/examples/remote-port-forward.rb +80 -0
- data/examples/tail-demo.rb +49 -0
- data/lib/net/ssh.rb +52 -0
- data/lib/net/ssh/connection/channel.rb +411 -0
- data/lib/net/ssh/connection/constants.rb +47 -0
- data/lib/net/ssh/connection/driver.rb +343 -0
- data/lib/net/ssh/connection/services.rb +72 -0
- data/lib/net/ssh/connection/term.rb +90 -0
- data/lib/net/ssh/errors.rb +27 -0
- data/lib/net/ssh/proxy/errors.rb +34 -0
- data/lib/net/ssh/proxy/http.rb +126 -0
- data/lib/net/ssh/proxy/socks4.rb +83 -0
- data/lib/net/ssh/proxy/socks5.rb +160 -0
- data/lib/net/ssh/service/forward/driver.rb +319 -0
- data/lib/net/ssh/service/forward/local-network-handler.rb +74 -0
- data/lib/net/ssh/service/forward/remote-network-handler.rb +81 -0
- data/lib/net/ssh/service/forward/services.rb +76 -0
- data/lib/net/ssh/service/process/driver.rb +153 -0
- data/lib/net/ssh/service/process/open.rb +193 -0
- data/lib/net/ssh/service/process/popen3.rb +160 -0
- data/lib/net/ssh/service/process/services.rb +66 -0
- data/lib/net/ssh/service/services.rb +44 -0
- data/lib/net/ssh/session.rb +242 -0
- data/lib/net/ssh/transport/algorithm-negotiator.rb +267 -0
- data/lib/net/ssh/transport/compress/compressor.rb +53 -0
- data/lib/net/ssh/transport/compress/decompressor.rb +53 -0
- data/lib/net/ssh/transport/compress/none-compressor.rb +39 -0
- data/lib/net/ssh/transport/compress/none-decompressor.rb +39 -0
- data/lib/net/ssh/transport/compress/services.rb +68 -0
- data/lib/net/ssh/transport/compress/zlib-compressor.rb +60 -0
- data/lib/net/ssh/transport/compress/zlib-decompressor.rb +52 -0
- data/lib/net/ssh/transport/constants.rb +66 -0
- data/lib/net/ssh/transport/errors.rb +47 -0
- data/lib/net/ssh/transport/identity-cipher.rb +61 -0
- data/lib/net/ssh/transport/kex/dh-gex.rb +106 -0
- data/lib/net/ssh/transport/kex/dh.rb +231 -0
- data/lib/net/ssh/transport/kex/services.rb +60 -0
- data/lib/net/ssh/transport/ossl/buffer-factory.rb +52 -0
- data/lib/net/ssh/transport/ossl/buffer.rb +87 -0
- data/lib/net/ssh/transport/ossl/cipher-factory.rb +98 -0
- data/lib/net/ssh/transport/ossl/digest-factory.rb +51 -0
- data/lib/net/ssh/transport/ossl/hmac-factory.rb +71 -0
- data/lib/net/ssh/transport/ossl/hmac/hmac.rb +62 -0
- data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +44 -0
- data/lib/net/ssh/transport/ossl/hmac/md5.rb +46 -0
- data/lib/net/ssh/transport/ossl/hmac/none.rb +46 -0
- data/lib/net/ssh/transport/ossl/hmac/services.rb +68 -0
- data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +44 -0
- data/lib/net/ssh/transport/ossl/hmac/sha1.rb +45 -0
- data/lib/net/ssh/transport/ossl/key-factory.rb +113 -0
- data/lib/net/ssh/transport/ossl/services.rb +149 -0
- data/lib/net/ssh/transport/packet-stream.rb +210 -0
- data/lib/net/ssh/transport/services.rb +146 -0
- data/lib/net/ssh/transport/session.rb +296 -0
- data/lib/net/ssh/transport/version-negotiator.rb +73 -0
- data/lib/net/ssh/userauth/agent.rb +218 -0
- data/lib/net/ssh/userauth/constants.rb +35 -0
- data/lib/net/ssh/userauth/driver.rb +176 -0
- data/lib/net/ssh/userauth/methods/hostbased.rb +119 -0
- data/lib/net/ssh/userauth/methods/password.rb +70 -0
- data/lib/net/ssh/userauth/methods/publickey.rb +137 -0
- data/lib/net/ssh/userauth/methods/services.rb +63 -0
- data/lib/net/ssh/userauth/services.rb +126 -0
- data/lib/net/ssh/userauth/userkeys.rb +258 -0
- data/lib/net/ssh/util/buffer.rb +274 -0
- data/lib/net/ssh/util/openssl.rb +146 -0
- data/lib/net/ssh/util/prompter.rb +73 -0
- data/lib/net/ssh/version.rb +29 -0
- data/test/ALL-TESTS.rb +21 -0
- data/test/connection/tc_channel.rb +136 -0
- data/test/connection/tc_driver.rb +287 -0
- data/test/connection/tc_integration.rb +85 -0
- data/test/proxy/tc_http.rb +209 -0
- data/test/proxy/tc_socks4.rb +148 -0
- data/test/proxy/tc_socks5.rb +214 -0
- data/test/service/forward/tc_driver.rb +289 -0
- data/test/service/forward/tc_local_network_handler.rb +123 -0
- data/test/service/forward/tc_remote_network_handler.rb +108 -0
- data/test/service/process/tc_driver.rb +79 -0
- data/test/service/process/tc_integration.rb +117 -0
- data/test/service/process/tc_open.rb +179 -0
- data/test/service/process/tc_popen3.rb +164 -0
- data/test/tc_integration.rb +79 -0
- data/test/transport/compress/tc_none_compress.rb +41 -0
- data/test/transport/compress/tc_none_decompress.rb +45 -0
- data/test/transport/compress/tc_zlib_compress.rb +61 -0
- data/test/transport/compress/tc_zlib_decompress.rb +48 -0
- data/test/transport/kex/tc_dh.rb +304 -0
- data/test/transport/kex/tc_dh_gex.rb +70 -0
- data/test/transport/ossl/fixtures/dsa-encrypted +15 -0
- data/test/transport/ossl/fixtures/dsa-encrypted-bad +15 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted +12 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted-bad +12 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted.pub +1 -0
- data/test/transport/ossl/fixtures/not-a-private-key +4 -0
- data/test/transport/ossl/fixtures/not-supported +2 -0
- data/test/transport/ossl/fixtures/rsa-encrypted +18 -0
- data/test/transport/ossl/fixtures/rsa-encrypted-bad +18 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted +15 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted-bad +15 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted.pub +1 -0
- data/test/transport/ossl/hmac/tc_hmac.rb +58 -0
- data/test/transport/ossl/hmac/tc_md5.rb +50 -0
- data/test/transport/ossl/hmac/tc_md5_96.rb +50 -0
- data/test/transport/ossl/hmac/tc_none.rb +50 -0
- data/test/transport/ossl/hmac/tc_sha1.rb +50 -0
- data/test/transport/ossl/hmac/tc_sha1_96.rb +50 -0
- data/test/transport/ossl/tc_buffer.rb +97 -0
- data/test/transport/ossl/tc_buffer_factory.rb +67 -0
- data/test/transport/ossl/tc_cipher_factory.rb +84 -0
- data/test/transport/ossl/tc_digest_factory.rb +39 -0
- data/test/transport/ossl/tc_hmac_factory.rb +72 -0
- data/test/transport/ossl/tc_key_factory.rb +199 -0
- data/test/transport/tc_algorithm_negotiator.rb +169 -0
- data/test/transport/tc_identity_cipher.rb +52 -0
- data/test/transport/tc_integration.rb +110 -0
- data/test/transport/tc_packet_stream.rb +183 -0
- data/test/transport/tc_session.rb +283 -0
- data/test/transport/tc_version_negotiator.rb +86 -0
- data/test/userauth/methods/tc_hostbased.rb +136 -0
- data/test/userauth/methods/tc_password.rb +89 -0
- data/test/userauth/methods/tc_publickey.rb +167 -0
- data/test/userauth/tc_agent.rb +223 -0
- data/test/userauth/tc_driver.rb +190 -0
- data/test/userauth/tc_integration.rb +81 -0
- data/test/userauth/tc_userkeys.rb +265 -0
- data/test/util/tc_buffer.rb +217 -0
- metadata +256 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
|
10
|
+
# distribution for the texts of these licenses.
|
|
11
|
+
# -----------------------------------------------------------------------------
|
|
12
|
+
# net-ssh website : http://net-ssh.rubyforge.org
|
|
13
|
+
# project website: http://rubyforge.org/projects/net-ssh
|
|
14
|
+
# =============================================================================
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
module Net
|
|
18
|
+
module SSH
|
|
19
|
+
module Service
|
|
20
|
+
module Forward
|
|
21
|
+
|
|
22
|
+
# Register the services pertaining to port forwarding.
|
|
23
|
+
def register_services( container )
|
|
24
|
+
|
|
25
|
+
# All port forwarding services go in the :forward namespace.
|
|
26
|
+
container.namespace_define :forward do |ns|
|
|
27
|
+
|
|
28
|
+
# The :driver service manages all port forwarding. It is declared
|
|
29
|
+
# as deferred so that it is not actually instantiated until it is
|
|
30
|
+
# used--otherwise, it would be instantiated as soon as it was added
|
|
31
|
+
# to the list of available services, whether it was ever used or
|
|
32
|
+
# not.
|
|
33
|
+
ns.driver :model => :singleton_deferred do |c,p|
|
|
34
|
+
require 'net/ssh/service/forward/driver'
|
|
35
|
+
Driver.new( c[:connection][:driver],
|
|
36
|
+
c[:transport][:buffers],
|
|
37
|
+
c[:log_for, p],
|
|
38
|
+
:local => c[:local_network_handler],
|
|
39
|
+
:remote => c[:remote_network_handler] )
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# A constant service, used to indicate the maximum block size to be
|
|
43
|
+
# passed over a forwarded connection.
|
|
44
|
+
ns.read_block_size { 64 * 1024 }
|
|
45
|
+
|
|
46
|
+
# The :local_network_handler service returns a proc object that
|
|
47
|
+
# creates new LocalNetworkHandler instances for a given client
|
|
48
|
+
# connection. This is used for forwarding ports on the local host.
|
|
49
|
+
ns.local_network_handler :model => :singleton_deferred do |c,p|
|
|
50
|
+
require 'net/ssh/service/forward/local-network-handler'
|
|
51
|
+
log = c[:log_for, p]
|
|
52
|
+
block_size = c[:read_block_size]
|
|
53
|
+
lambda do |client|
|
|
54
|
+
LocalNetworkHandler.new( log, block_size, client )
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The :remote_network_handler service returns a proc object that
|
|
59
|
+
# creates new RemoteNetworkHandler instances for a given port and
|
|
60
|
+
# host. This is used for forwarding ports on a remote host.
|
|
61
|
+
ns.remote_network_handler :model => :singleton_deferred do |c,p|
|
|
62
|
+
require 'net/ssh/service/forward/remote-network-handler'
|
|
63
|
+
log = c[:log_for, p]
|
|
64
|
+
block_size = c[:read_block_size]
|
|
65
|
+
lambda do |port, host|
|
|
66
|
+
RemoteNetworkHandler.new( log, block_size, port, host )
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
module_function :register_services
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
|
10
|
+
# distribution for the texts of these licenses.
|
|
11
|
+
# -----------------------------------------------------------------------------
|
|
12
|
+
# net-ssh website : http://net-ssh.rubyforge.org
|
|
13
|
+
# project website: http://rubyforge.org/projects/net-ssh
|
|
14
|
+
# =============================================================================
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require 'net/ssh/errors'
|
|
18
|
+
|
|
19
|
+
module Net
|
|
20
|
+
module SSH
|
|
21
|
+
module Service
|
|
22
|
+
module Process
|
|
23
|
+
|
|
24
|
+
# Represents a process executing on the remote machine. It also provides
|
|
25
|
+
# a simple interface for interacting with such a remote process.
|
|
26
|
+
#
|
|
27
|
+
# It may be used in either of two ways. The first allows multiple
|
|
28
|
+
# processes to be invoked on the remote machine and run in parallel
|
|
29
|
+
# over the same session. Because of this, it is a bit complicated to
|
|
30
|
+
# set up:
|
|
31
|
+
#
|
|
32
|
+
# require 'net/ssh'
|
|
33
|
+
#
|
|
34
|
+
# Net::SSH.start( 'host', 'user', 'passwd' ) do |session|
|
|
35
|
+
# process = session.process.open( "bc" )
|
|
36
|
+
# dialog = [ "5+5", "7*12", "1+2*5/(7+3)" ]
|
|
37
|
+
#
|
|
38
|
+
# process.on_success do |p|
|
|
39
|
+
# puts "requesting computation of '#{dialog.first}'"
|
|
40
|
+
# p.puts dialog.shift
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# process.on_failure do |p, status|
|
|
44
|
+
# puts "process failed to start (#{status})"
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# process.on_stdout do |p, data|
|
|
48
|
+
# puts "--> #{data}"
|
|
49
|
+
# if dialog.empty?
|
|
50
|
+
# p.close_input
|
|
51
|
+
# else
|
|
52
|
+
# puts "requesting computation of '#{dialog.first}'"
|
|
53
|
+
# p.puts dialog.shift
|
|
54
|
+
# end
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# process.on_stderr do |p, data|
|
|
58
|
+
# puts "[stderr]--> #{data}"
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# process.on_exit do |p, status|
|
|
62
|
+
# puts "process finished with exit status: #{status}"
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# session.loop
|
|
66
|
+
# end
|
|
67
|
+
#
|
|
68
|
+
# Naturally, not all of the callbacks used above are required. If you
|
|
69
|
+
# omit any of them, they will simply not be called. However, you
|
|
70
|
+
# *should* do something when the process is successfully started
|
|
71
|
+
# (+on_success+), and you *should* do something when data is recieved
|
|
72
|
+
# over stdout (+on_stdout+). Lastly, you *must* execute
|
|
73
|
+
# <tt>session.loop</tt> in order to process the connection.
|
|
74
|
+
#
|
|
75
|
+
# The simpler way to use this service is only available when you
|
|
76
|
+
# are not handling multiple parallel processes--you can only use it
|
|
77
|
+
# when the process you are executing is the only task you are using the
|
|
78
|
+
# SSH connection for. It is reminiscent of the popen interface: you
|
|
79
|
+
# invoke a command and get three pseudo-IO objects back--one for the
|
|
80
|
+
# command's "stdin" stream, one for it's "stdout" stream, and one for
|
|
81
|
+
# it's "stderr" stream. You may then write to the "stdin" stream, and
|
|
82
|
+
# read from the "stdout" and "stderr" streams.
|
|
83
|
+
#
|
|
84
|
+
# For example:
|
|
85
|
+
#
|
|
86
|
+
# require 'net/ssh'
|
|
87
|
+
#
|
|
88
|
+
# Net::SSH.start( 'host', 'user', 'passwd' ) do |session|
|
|
89
|
+
# input, output, error = session.process.popen3( "bc" )
|
|
90
|
+
# input.puts "5+5"
|
|
91
|
+
# puts "5+5=#{output.read}"
|
|
92
|
+
# input.puts "7*12"
|
|
93
|
+
# puts "7*12=#{output.read}"
|
|
94
|
+
# input.puts "1+2*5/(7+3)"
|
|
95
|
+
# puts "1+2*5/(7+3)=#{output.read}"
|
|
96
|
+
# input.puts "quit"
|
|
97
|
+
# end
|
|
98
|
+
#
|
|
99
|
+
# One caveat with this format: the process cannot be explicitly
|
|
100
|
+
# terminated from the client side--the process must terminate on its
|
|
101
|
+
# own (for example, by recieving a "quit" command, as used above). If
|
|
102
|
+
# the command does not support any means of gracefully aborting it,
|
|
103
|
+
# then the only way to kill the command is to terminate the connection.
|
|
104
|
+
#
|
|
105
|
+
# A slightly cleaner approach uses blocks to denote the lifespan of the
|
|
106
|
+
# process. When the block terminates, the process is killed (if it is
|
|
107
|
+
# still running):
|
|
108
|
+
#
|
|
109
|
+
# require 'net/ssh'
|
|
110
|
+
#
|
|
111
|
+
# Net::SSH.start( 'host', 'user', 'passwd' ) do |session|
|
|
112
|
+
# session.process.popen3( "cat" ) do |input, output, error|
|
|
113
|
+
# input.puts "hello"
|
|
114
|
+
# puts "echo: #{output.read}"
|
|
115
|
+
# input.puts "world"
|
|
116
|
+
# puts "echo: #{output.read}"
|
|
117
|
+
# end
|
|
118
|
+
# end
|
|
119
|
+
class Driver
|
|
120
|
+
|
|
121
|
+
# Create a new Driver instance, using the given log and handlers
|
|
122
|
+
# hash.
|
|
123
|
+
def initialize( connection, log, handlers )
|
|
124
|
+
@connection = connection
|
|
125
|
+
@log = log
|
|
126
|
+
@handlers = handlers
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def open( command )
|
|
130
|
+
@log.debug "opening '#{command}'" if @log.debug?
|
|
131
|
+
process = @handlers[ :open ].call( command )
|
|
132
|
+
|
|
133
|
+
if block_given?
|
|
134
|
+
yield process
|
|
135
|
+
@connection.loop
|
|
136
|
+
return nil
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
process
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def popen3( command, &block )
|
|
143
|
+
@log.debug "popen3 '#{command}'" if @log.debug?
|
|
144
|
+
mgr = @handlers[ :popen3 ]
|
|
145
|
+
mgr.popen3( command, &block )
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
end # module Process
|
|
151
|
+
end # module Service
|
|
152
|
+
end # module SSH
|
|
153
|
+
end # module Net
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
|
10
|
+
# distribution for the texts of these licenses.
|
|
11
|
+
# -----------------------------------------------------------------------------
|
|
12
|
+
# net-ssh website : http://net-ssh.rubyforge.org
|
|
13
|
+
# project website: http://rubyforge.org/projects/net-ssh
|
|
14
|
+
# =============================================================================
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require 'net/ssh/errors'
|
|
18
|
+
|
|
19
|
+
module Net
|
|
20
|
+
module SSH
|
|
21
|
+
module Service
|
|
22
|
+
module Process
|
|
23
|
+
|
|
24
|
+
# A delegate class to manage the processing for a single executed
|
|
25
|
+
# process on the remote host. It opens a channel, executes the process
|
|
26
|
+
# on it, and manages the various callbacks.
|
|
27
|
+
#
|
|
28
|
+
# This service is typically used like this:
|
|
29
|
+
#
|
|
30
|
+
# Net::SSH.start( 'host', 'user' ) do |session|
|
|
31
|
+
# session.process.open( "bc" ) do |process|
|
|
32
|
+
# ...
|
|
33
|
+
# end
|
|
34
|
+
# end
|
|
35
|
+
class OpenManager
|
|
36
|
+
|
|
37
|
+
# Create a new OpenManager instance on the given connection. It will
|
|
38
|
+
# attempt to execute the given command. If a block is given, the
|
|
39
|
+
# manager will be yielded to the block, and the constructor will not
|
|
40
|
+
# return until all channels are closed.
|
|
41
|
+
def initialize( connection, log, command )
|
|
42
|
+
@log = log
|
|
43
|
+
@command = command
|
|
44
|
+
@channel = connection.open_channel(
|
|
45
|
+
"session", &method( :do_confirm ) )
|
|
46
|
+
|
|
47
|
+
if block_given?
|
|
48
|
+
yield self
|
|
49
|
+
connection.loop
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Register the given block to be invoked when the command has been
|
|
54
|
+
# confirmed to have been successfully started. The block should
|
|
55
|
+
# accept a single parameter, the process instance that was created
|
|
56
|
+
# (+self+).
|
|
57
|
+
def on_success( &block )
|
|
58
|
+
@on_success = block
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Register the given block to be invoked when the command could not
|
|
62
|
+
# be started. The block should accept two parameters: the process
|
|
63
|
+
# instance (+self+) and a status string. (The status string is
|
|
64
|
+
# currently always +nil+, since SSH itself does not indicate why the
|
|
65
|
+
# program failed to start.)
|
|
66
|
+
def on_failure( &block )
|
|
67
|
+
@on_failure = block
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Register the given block to be invoked when data is recieved from
|
|
71
|
+
# the invoked command's +stdout+ stream. The block should accept two
|
|
72
|
+
# parameters: the process instance (+self+) and the data string. Note
|
|
73
|
+
# that if the process sends large amounts of data, this method may be
|
|
74
|
+
# invoked multiple times, each time with a portion of the command's
|
|
75
|
+
# output.
|
|
76
|
+
def on_stdout( &block )
|
|
77
|
+
@on_stdout = block
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Register the given block to be invoked when data is recieved from
|
|
81
|
+
# the invoked command's +stderr+ stream. The block should accept two
|
|
82
|
+
# parameters: the process instance (+self+) and the data string. Note
|
|
83
|
+
# that if the process sends large amounts of data, this method may be
|
|
84
|
+
# invoked multiple times, each time with a portion of the command's
|
|
85
|
+
# error output.
|
|
86
|
+
def on_stderr( &block )
|
|
87
|
+
@on_stderr = block
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Register the given block to be invoked when the process terminates
|
|
91
|
+
# normally. The block should accept two parameters: the process
|
|
92
|
+
# instance (+self+) and the exit status of the process.
|
|
93
|
+
def on_exit( &block )
|
|
94
|
+
@on_exit = block
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Send the given data to the process. It will be sent via the
|
|
98
|
+
# process's +stdin+ stream. This method returns immediately.
|
|
99
|
+
def write( data )
|
|
100
|
+
@channel.send_data data
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Send the given data to the process, appending a newline. As with
|
|
104
|
+
# Kernel::puts, this will not append a newline if the string already
|
|
105
|
+
# has one. See #write.
|
|
106
|
+
def puts( data )
|
|
107
|
+
@channel.send_data data.chomp + "\n"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Indicate that no more data will be sent to the process (sends an
|
|
111
|
+
# EOF to the process). The process may continue to send data, but
|
|
112
|
+
# the +stdin+ stream is effectively closed. This will return
|
|
113
|
+
# immediately.
|
|
114
|
+
def close_input
|
|
115
|
+
@channel.send_eof
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Close the process. All streams (+stdin+, +stdout+, +stderr+) will
|
|
119
|
+
# be closed. Any output that the process had already produced will
|
|
120
|
+
# still be sent, but it will be shut down as soon as possible. This
|
|
121
|
+
# will return immediately.
|
|
122
|
+
def close
|
|
123
|
+
@channel.close
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Invoked when the channel's opening has been confirmed by the
|
|
127
|
+
# server. This is where the command to execute will be sent to the
|
|
128
|
+
# server.
|
|
129
|
+
def do_confirm( channel )
|
|
130
|
+
channel.on_success &method(:do_exec_success)
|
|
131
|
+
channel.on_failure &method(:do_exec_failure)
|
|
132
|
+
channel.exec @command, true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Invoked when the invocation of the command has been successful.
|
|
136
|
+
# This registers various callbacks, and then calls the +on_success+
|
|
137
|
+
# callback (if registered).
|
|
138
|
+
def do_exec_success( channel )
|
|
139
|
+
channel.on_data &method(:do_data)
|
|
140
|
+
channel.on_extended_data &method(:do_extended_data)
|
|
141
|
+
channel.on_close &method(:do_close)
|
|
142
|
+
channel.on_request &method(:do_request)
|
|
143
|
+
@on_success.call( self ) if @on_success
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Invoked when the invocation of the command failed. This will call
|
|
147
|
+
# the +on_failure+ callback, if registered, or will otherwise raise
|
|
148
|
+
# an exception.
|
|
149
|
+
def do_exec_failure( channel )
|
|
150
|
+
if @on_failure
|
|
151
|
+
@on_failure.call( self, nil )
|
|
152
|
+
else
|
|
153
|
+
raise Net::SSH::Exception,
|
|
154
|
+
"could not execute process (#{@command})"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Invoked when data arrives over the channel. This simply delegates to
|
|
159
|
+
# the +on_stdout+ callback, if registered.
|
|
160
|
+
def do_data( channel, data )
|
|
161
|
+
@on_stdout.call( self, data ) if @on_stdout
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Invoked when extended data arrives over the channel. This simply
|
|
165
|
+
# delegates to the +on_stderr+ callback, if registered, if the type
|
|
166
|
+
# is 1; otherwise it does nothing.
|
|
167
|
+
def do_extended_data( channel, type, data )
|
|
168
|
+
case type
|
|
169
|
+
when 1
|
|
170
|
+
@on_stderr.call( self, data ) if @on_stderr
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Invoked when the channel is closed. This simply delegates to
|
|
175
|
+
# the +on_exit+ callback, if registered.
|
|
176
|
+
def do_close( channel )
|
|
177
|
+
@on_exit.call( self, @exit_status ) if @on_exit
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Invoked when a channel request is received.
|
|
181
|
+
def do_request( channel, type, want_reply, data )
|
|
182
|
+
case type
|
|
183
|
+
when "exit-status"
|
|
184
|
+
@exit_status = data.read_long
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end # module Process
|
|
191
|
+
end # module Service
|
|
192
|
+
end # module SSH
|
|
193
|
+
end # module Net
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
|
7
|
+
# library for Ruby. This file (and the library as a whole) may be used only as
|
|
8
|
+
# allowed by either the BSD license, or the Ruby license (or, by association
|
|
9
|
+
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
|
10
|
+
# distribution for the texts of these licenses.
|
|
11
|
+
# -----------------------------------------------------------------------------
|
|
12
|
+
# net-ssh website : http://net-ssh.rubyforge.org
|
|
13
|
+
# project website: http://rubyforge.org/projects/net-ssh
|
|
14
|
+
# =============================================================================
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require 'net/ssh/errors'
|
|
18
|
+
|
|
19
|
+
module Net
|
|
20
|
+
module SSH
|
|
21
|
+
module Service
|
|
22
|
+
module Process
|
|
23
|
+
|
|
24
|
+
# A delegate class for managing popen3 requests for remote processes.
|
|
25
|
+
class POpen3Manager
|
|
26
|
+
|
|
27
|
+
# Create a new POpen3Manager instance on the given connection.
|
|
28
|
+
def initialize( connection, log )
|
|
29
|
+
@connection = connection
|
|
30
|
+
@log = log
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Invokes the given command synchronously on the current connection.
|
|
34
|
+
# (This means that parallel commands and operations cannot be
|
|
35
|
+
# executed when this method is used.) This will return +nil+ if the
|
|
36
|
+
# method could not be executed. If the command is successfully
|
|
37
|
+
# invoked, and a block is given, the block is then invoked with the
|
|
38
|
+
# input, output, and error streams of the command as parameters, and
|
|
39
|
+
# the channel is closed as soon as the block terminates. If a block
|
|
40
|
+
# is not given, the input, output, and error channels are returned
|
|
41
|
+
# and the process *might* not terminate until the session itself
|
|
42
|
+
# terminates.
|
|
43
|
+
def popen3( command )
|
|
44
|
+
@connection.open_channel( "session" ) do |chan|
|
|
45
|
+
|
|
46
|
+
chan.on_success do |ch|
|
|
47
|
+
input = SSHStdinPipe.new( ch )
|
|
48
|
+
output = SSHStdoutPipe.new( ch )
|
|
49
|
+
error = SSHStderrPipe.new( ch )
|
|
50
|
+
|
|
51
|
+
if block_given?
|
|
52
|
+
yield input, output, error
|
|
53
|
+
chan.close
|
|
54
|
+
else
|
|
55
|
+
return [ input, output, error ]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
chan.on_failure do |ch|
|
|
60
|
+
chan.close
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
chan.exec command, true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@connection.loop
|
|
67
|
+
return nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# A specialized class for use by the Net::SSH "popen3" service.
|
|
71
|
+
# An instance of this class represents a means of writing data to an
|
|
72
|
+
# SSH channel. This class should never be instantiated directly; use
|
|
73
|
+
# the popen3 method instead.
|
|
74
|
+
class SSHStdinPipe
|
|
75
|
+
|
|
76
|
+
# Create a new +stdin+ pipe on the given channel.
|
|
77
|
+
def initialize( channel )
|
|
78
|
+
@channel = channel
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Write the given data as channel data to the underlying channel.
|
|
82
|
+
def write( data )
|
|
83
|
+
@channel.send_data data
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Write the given data as channel data to the underlying channel,
|
|
87
|
+
# appending a newline character (if one isn't already appended).
|
|
88
|
+
def puts( data )
|
|
89
|
+
write data.chomp + "\n"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# An abstract class representing a writable stream on a channel. This
|
|
95
|
+
# is subclassed by SSHStdoutPipe and SSHStderrPipe.
|
|
96
|
+
class SSHOutputPipe
|
|
97
|
+
|
|
98
|
+
# Create a new output pipe on the given channel.
|
|
99
|
+
def initialize( channel )
|
|
100
|
+
@channel = channel
|
|
101
|
+
@data = ""
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Read all available bytes from the pipe. If there are no available
|
|
105
|
+
# bytes, then this will block until data becomes available.
|
|
106
|
+
def read
|
|
107
|
+
if @data.length < 1
|
|
108
|
+
@channel.connection.loop { @data.length < 1 }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
data, @data = @data, ""
|
|
112
|
+
return data
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# A specialization of SSHOutputPipe that represents specifically the
|
|
118
|
+
# +stdout+ stream of a process. It should only be used by popen3.
|
|
119
|
+
class SSHStdoutPipe < SSHOutputPipe
|
|
120
|
+
|
|
121
|
+
# Create a new +stdout+ stream on the given channel. Only one such
|
|
122
|
+
# pipe should ever be associated with a channel.
|
|
123
|
+
def initialize( channel )
|
|
124
|
+
super( channel )
|
|
125
|
+
channel.on_data &method(:do_data)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Invoked when data is recieved from the channel. It simply
|
|
129
|
+
# accumulates all data until a +read+ is invoked.
|
|
130
|
+
def do_data( channel, data )
|
|
131
|
+
@data << data
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# A specialization of SSHOutputPipe that represents specifically the
|
|
137
|
+
# +stderr+ stream of a process. It should only be used by popen3.
|
|
138
|
+
class SSHStderrPipe < SSHOutputPipe
|
|
139
|
+
|
|
140
|
+
# Create a new +stderr+ stream on the given channel. Only one such
|
|
141
|
+
# pipe should ever be associated with a channel.
|
|
142
|
+
def initialize( channel )
|
|
143
|
+
super( channel )
|
|
144
|
+
channel.on_extended_data &method(:do_data)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Invoked when data is recieved from the channel. It simply
|
|
148
|
+
# accumulates all data until a +read+ is invoked.
|
|
149
|
+
def do_data( channel, type, data )
|
|
150
|
+
@data << data if type == 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end # module Process
|
|
158
|
+
end # module Service
|
|
159
|
+
end # module SSH
|
|
160
|
+
end # module Net
|