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,51 @@
|
|
|
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
|
+
$:.unshift "../lib"
|
|
18
|
+
|
|
19
|
+
require 'net/ssh'
|
|
20
|
+
|
|
21
|
+
# This assumes three things:
|
|
22
|
+
#
|
|
23
|
+
# 1) That you have an SSH server running on your local machine,
|
|
24
|
+
# 2) That the USER environment variable is set to your user name, and
|
|
25
|
+
# 3) That you have public and private keys conigured so that you can log into
|
|
26
|
+
# your machine via SSH without being prompted for a password.
|
|
27
|
+
#
|
|
28
|
+
# If #2 or #3 are not true, you can add your user-name and password as the
|
|
29
|
+
# second and third parameters (respectively) to Net::SSH.start.
|
|
30
|
+
|
|
31
|
+
Net::SSH.start( 'localhost' ) do |session|
|
|
32
|
+
session.forward.local( 12345, 'www.yahoo.com', 80 )
|
|
33
|
+
session.forward.local( 12346, 'www.google.com', 80 )
|
|
34
|
+
|
|
35
|
+
trap("SIGINT") do
|
|
36
|
+
puts "direct channels open : #{session.forward.open_direct_channel_count}"
|
|
37
|
+
puts "direct channels opened: #{session.forward.direct_channel_count}"
|
|
38
|
+
puts "active local forwards : #{session.forward.active_locals.length} " +
|
|
39
|
+
"(#{session.forward.active_locals.inspect})"
|
|
40
|
+
session.close
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
puts "forwarding ports..."
|
|
45
|
+
session.loop { true }
|
|
46
|
+
rescue Exception => e
|
|
47
|
+
unless e.message =~ /connection closed by remote host/
|
|
48
|
+
raise
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
$:.unshift "../lib"
|
|
18
|
+
require 'net/ssh'
|
|
19
|
+
|
|
20
|
+
# This assumes three things:
|
|
21
|
+
#
|
|
22
|
+
# 1) That you have an SSH server running on your local machine,
|
|
23
|
+
# 2) That the USER environment variable is set to your user name, and
|
|
24
|
+
# 3) That you have public and private keys conigured so that you can log into
|
|
25
|
+
# your machine via SSH without being prompted for a password.
|
|
26
|
+
#
|
|
27
|
+
# If #2 or #3 are not true, you can add your user-name and password as the
|
|
28
|
+
# second and third parameters (respectively) to Net::SSH.start.
|
|
29
|
+
|
|
30
|
+
Net::SSH.start( 'localhost' ) do |session|
|
|
31
|
+
|
|
32
|
+
# ===========================================================================
|
|
33
|
+
|
|
34
|
+
session.process.open( "bc" ) do |bc|
|
|
35
|
+
dialog = [ "5+5", "7*12", "sqrt(2.000000)" ]
|
|
36
|
+
|
|
37
|
+
bc.on_success do |p|
|
|
38
|
+
puts "process started successfully. starting interactive session."
|
|
39
|
+
puts "requesting result of #{dialog.first}"
|
|
40
|
+
p.puts dialog.shift
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
bc.on_failure do |p, status|
|
|
44
|
+
puts "process failed to start (#{status})"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
bc.on_stdout do |p,data|
|
|
48
|
+
puts "--> #{data}"
|
|
49
|
+
unless dialog.empty?
|
|
50
|
+
puts "requesting result of #{dialog.first}"
|
|
51
|
+
p.puts dialog.shift
|
|
52
|
+
else
|
|
53
|
+
p.close_input
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
bc.on_stderr do |p,data|
|
|
58
|
+
puts "got stuff from stderr: #{data}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
bc.on_exit do |p, status|
|
|
62
|
+
puts "process finished with exit status: #{status}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
puts "done!"
|
|
67
|
+
|
|
68
|
+
# ===========================================================================
|
|
69
|
+
|
|
70
|
+
puts "now, trying 'bc' with popen3..."
|
|
71
|
+
|
|
72
|
+
input, output, error = session.process.popen3( "bc" )
|
|
73
|
+
input.puts "5+5"
|
|
74
|
+
puts "5+5=#{output.read}"
|
|
75
|
+
input.puts "10*2"
|
|
76
|
+
puts "10*2=#{output.read}"
|
|
77
|
+
input.puts "quit"
|
|
78
|
+
|
|
79
|
+
# ===========================================================================
|
|
80
|
+
|
|
81
|
+
puts "trying 'cat' with popen3"
|
|
82
|
+
session.process.popen3( "cat" ) do |input,output,error|
|
|
83
|
+
input.puts "hello"
|
|
84
|
+
puts output.read
|
|
85
|
+
input.puts "world"
|
|
86
|
+
puts output.read
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
puts "done!"
|
|
90
|
+
|
|
91
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
$:.unshift "../lib"
|
|
18
|
+
|
|
19
|
+
require 'net/ssh'
|
|
20
|
+
|
|
21
|
+
# This assumes four things:
|
|
22
|
+
#
|
|
23
|
+
# 1) That you have an SSH server running on your local machine,
|
|
24
|
+
# 2) That the USER environment variable is set to your user name, and
|
|
25
|
+
# 3) That you have public and private keys conigured so that you can log into
|
|
26
|
+
# your machine via SSH without being prompted for a password.
|
|
27
|
+
# 4) That you have a web server running on your local machine on port 80.
|
|
28
|
+
#
|
|
29
|
+
# If #2 or #3 are not true, you can add your user-name and password as the
|
|
30
|
+
# second and third parameters (respectively) to Net::SSH.start.
|
|
31
|
+
|
|
32
|
+
Net::SSH.start( 'localhost' ) do |session|
|
|
33
|
+
session.forward.remote_to( 80, "localhost", 12345 )
|
|
34
|
+
|
|
35
|
+
trap("SIGINT") { session.close }
|
|
36
|
+
|
|
37
|
+
begin
|
|
38
|
+
puts "forwarding remote port via localhost..."
|
|
39
|
+
session.loop { true }
|
|
40
|
+
rescue Exception => e
|
|
41
|
+
unless e.message =~ /connection closed by remote host/
|
|
42
|
+
raise
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
$:.unshift "../lib"
|
|
18
|
+
|
|
19
|
+
require 'net/ssh'
|
|
20
|
+
|
|
21
|
+
# This assumes three things:
|
|
22
|
+
#
|
|
23
|
+
# 1) That you have an SSH server running on your local machine,
|
|
24
|
+
# 2) That the USER environment variable is set to your user name, and
|
|
25
|
+
# 3) That you have public and private keys conigured so that you can log into
|
|
26
|
+
# your machine via SSH without being prompted for a password.
|
|
27
|
+
#
|
|
28
|
+
# If #2 or #3 are not true, you can add your user-name and password as the
|
|
29
|
+
# second and third parameters (respectively) to Net::SSH.start.
|
|
30
|
+
|
|
31
|
+
class RemoteForwardListener
|
|
32
|
+
def error( msg )
|
|
33
|
+
raise "[#{self.class}] An error occurred: #{msg}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def setup( remote_port )
|
|
37
|
+
puts "[#{self.class}] forwarding enabled from remote port #{remote_port}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def on_open( channel, c_addr, c_port, o_addr, o_port )
|
|
41
|
+
puts "[#{self.class}] channel opened from remote server:"
|
|
42
|
+
puts " - connected address: #{c_addr}:#{c_port}"
|
|
43
|
+
puts " - originator address: #{o_addr}:#{o_port}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def on_receive( channel, data )
|
|
47
|
+
puts "data recevied from remote machine: #{data.inspect}"
|
|
48
|
+
msg = "It worked! You just connected over a remote forwarded SSH " +
|
|
49
|
+
"connection!\n\n" +
|
|
50
|
+
"------\n" +
|
|
51
|
+
data
|
|
52
|
+
channel.send_data "HTTP/1.0 200 OK\r\n" +
|
|
53
|
+
"Content-Type: text/plain\r\n" +
|
|
54
|
+
"Content-Length: #{msg.length}\r\n" +
|
|
55
|
+
"\r\n" +
|
|
56
|
+
msg
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def on_close( channel )
|
|
60
|
+
puts "remote channel closed"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def on_eof( channel )
|
|
64
|
+
puts "remote end of channel promised not to send any more data"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Net::SSH.start( 'localhost' ) do |session|
|
|
69
|
+
session.forward.remote( RemoteForwardListener.new, 12345 )
|
|
70
|
+
|
|
71
|
+
trap("SIGINT") { session.close }
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
session.loop { true }
|
|
75
|
+
rescue Exception => e
|
|
76
|
+
unless e.message =~ /connection closed by remote host/
|
|
77
|
+
raise
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
$:.unshift "../lib"
|
|
18
|
+
require 'net/ssh'
|
|
19
|
+
|
|
20
|
+
# This assumes three things:
|
|
21
|
+
#
|
|
22
|
+
# 1) That you have an SSH server running on your local machine,
|
|
23
|
+
# 2) That the USER environment variable is set to your user name, and
|
|
24
|
+
# 3) That you have public and private keys conigured so that you can log into
|
|
25
|
+
# your machine via SSH without being prompted for a password.
|
|
26
|
+
#
|
|
27
|
+
# If #2 or #3 are not true, you can add your user-name and password as the
|
|
28
|
+
# second and third parameters (respectively) to Net::SSH.start.
|
|
29
|
+
|
|
30
|
+
Net::SSH.start( 'localhost' ) do |session|
|
|
31
|
+
|
|
32
|
+
# Note: two things here,
|
|
33
|
+
#
|
|
34
|
+
# 1) open_channel does not immediately invoke the associated block. It only
|
|
35
|
+
# calls the block after the server has confirmed that the channel is valid.
|
|
36
|
+
# 2) channel.exec does not block--it just sends the request to the server and
|
|
37
|
+
# returns.
|
|
38
|
+
#
|
|
39
|
+
# For these two reasons, you MUST call session.loop, so that packets get
|
|
40
|
+
# processed and dispatched to the appropriate channel for handling.
|
|
41
|
+
|
|
42
|
+
session.open_channel do |channel|
|
|
43
|
+
channel.on_data { |chan,data| puts "--> #{data.inspect}" }
|
|
44
|
+
channel.on_extended_data { |chan,type,data| print data }
|
|
45
|
+
channel.exec "tail -f /tmp/mylog"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
session.loop
|
|
49
|
+
end
|
data/lib/net/ssh.rb
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
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/session'
|
|
18
|
+
|
|
19
|
+
#--
|
|
20
|
+
# Documentation Roadmap:
|
|
21
|
+
#
|
|
22
|
+
# 1. Start with net/ssh/session.rb (Net::SSH::Session). This creates a new
|
|
23
|
+
# Needle registry and registers all the services.
|
|
24
|
+
#
|
|
25
|
+
# 2. Look at net/ssh/transport/services.rb to see how the transport services
|
|
26
|
+
# are defined, and what classes implement each of them.
|
|
27
|
+
#
|
|
28
|
+
# 3. Look at net/ssh/transport/session.rb (Net::SSH::Transport::Session). This
|
|
29
|
+
# implements the driver for the transport layer.
|
|
30
|
+
#
|
|
31
|
+
# 4. Look at net/ssh/userauth/services.rb to see how the services for the
|
|
32
|
+
# user authentication layer are defined, and implemented.
|
|
33
|
+
#
|
|
34
|
+
# 5. Look at net/ssh/connection/services.rb to see how the services for the
|
|
35
|
+
# connection layer are defined and implemented.
|
|
36
|
+
#
|
|
37
|
+
# 6. Look at net/ssh/service/services.rb to see how the auxiliary services
|
|
38
|
+
# (process and forward) are defined.
|
|
39
|
+
#++
|
|
40
|
+
|
|
41
|
+
module Net
|
|
42
|
+
module SSH
|
|
43
|
+
|
|
44
|
+
# A convenience method for starting a new SSH session. See
|
|
45
|
+
# Net::SSH::Session.
|
|
46
|
+
def start( *args, &block )
|
|
47
|
+
Net::SSH::Session.new( *args, &block )
|
|
48
|
+
end
|
|
49
|
+
module_function :start
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,411 @@
|
|
|
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/connection/constants'
|
|
18
|
+
|
|
19
|
+
module Net
|
|
20
|
+
module SSH
|
|
21
|
+
module Connection
|
|
22
|
+
|
|
23
|
+
class Channel
|
|
24
|
+
include Constants
|
|
25
|
+
|
|
26
|
+
#--
|
|
27
|
+
# ====================================================================
|
|
28
|
+
# ATTRIBUTES
|
|
29
|
+
# ====================================================================
|
|
30
|
+
#++
|
|
31
|
+
|
|
32
|
+
# The channel's local id (assigned by the connection)
|
|
33
|
+
attr_reader :local_id
|
|
34
|
+
|
|
35
|
+
# The channel's remote id (assigned by the remote server)
|
|
36
|
+
attr_reader :remote_id
|
|
37
|
+
|
|
38
|
+
# The connection driver instance that owns this channel
|
|
39
|
+
attr_reader :connection
|
|
40
|
+
|
|
41
|
+
# The type of this channel
|
|
42
|
+
attr_reader :type
|
|
43
|
+
|
|
44
|
+
# The maximum packet size that may be sent over this channel
|
|
45
|
+
attr_reader :maximum_packet_size
|
|
46
|
+
|
|
47
|
+
# The maximum data window size for this channel
|
|
48
|
+
attr_reader :window_size
|
|
49
|
+
|
|
50
|
+
#--
|
|
51
|
+
# ====================================================================
|
|
52
|
+
# FACTORY METHODS
|
|
53
|
+
# ====================================================================
|
|
54
|
+
#++
|
|
55
|
+
|
|
56
|
+
# Requests that a new channel be opened on the remote host.
|
|
57
|
+
# This will return immediately, but the +on_confirm_open+ callback
|
|
58
|
+
# will be invoked when the remote host confirms that the channel has
|
|
59
|
+
# been successfully opened.
|
|
60
|
+
def self.open( connection, log, buffers, type, data=nil )
|
|
61
|
+
channel = new( connection, log, buffers, type )
|
|
62
|
+
|
|
63
|
+
msg = buffers.writer
|
|
64
|
+
|
|
65
|
+
msg.write_byte CHANNEL_OPEN
|
|
66
|
+
msg.write_string type
|
|
67
|
+
msg.write_long channel.local_id
|
|
68
|
+
msg.write_long 0x7FFFFFFF, 0x7FFFFFFF
|
|
69
|
+
msg.write data.to_s if data
|
|
70
|
+
|
|
71
|
+
connection.send_message msg
|
|
72
|
+
|
|
73
|
+
channel
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Creates a new channel object with the given internal
|
|
77
|
+
# information. The channel is assumed to already be
|
|
78
|
+
# connected to a remote host.
|
|
79
|
+
def self.create( connection, log, buffers, type, remote_id,
|
|
80
|
+
window_size, packet_size )
|
|
81
|
+
# begin
|
|
82
|
+
channel = new( connection, log, buffers, type )
|
|
83
|
+
channel.do_confirm_open remote_id, window_size, packet_size
|
|
84
|
+
channel
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private_class_method :new
|
|
88
|
+
|
|
89
|
+
#--
|
|
90
|
+
# ====================================================================
|
|
91
|
+
# CONSTRUCTOR
|
|
92
|
+
# ====================================================================
|
|
93
|
+
#++
|
|
94
|
+
|
|
95
|
+
# Create a new channel object on the given connection, and of the given
|
|
96
|
+
# type.
|
|
97
|
+
def initialize( connection, log, buffers, type )
|
|
98
|
+
@connection = connection
|
|
99
|
+
@log = log
|
|
100
|
+
@buffers = buffers
|
|
101
|
+
@type = type
|
|
102
|
+
@local_id = @connection.allocate_channel_id
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#--
|
|
106
|
+
# ====================================================================
|
|
107
|
+
# CALLBACK HOOKS
|
|
108
|
+
# ====================================================================
|
|
109
|
+
#++
|
|
110
|
+
|
|
111
|
+
# Set the callback to use when the channel has been confirmed
|
|
112
|
+
# to be open.
|
|
113
|
+
def on_confirm_open( &block )
|
|
114
|
+
@on_confirm_open = block
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Set the callback to use when the channel could not be opened
|
|
118
|
+
# for some reason.
|
|
119
|
+
def on_confirm_failed( &block )
|
|
120
|
+
@on_confirm_failed = block
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Set the callback to be invoked when the server requests
|
|
124
|
+
# that the window size be adjusted.
|
|
125
|
+
def on_window_adjust( &block )
|
|
126
|
+
@on_window_adjust = block
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Set the callback to be invoked when the server sends a
|
|
130
|
+
# data packet over the channel.
|
|
131
|
+
def on_data( &block )
|
|
132
|
+
@on_data = block
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Set the callback to be invoked when the server sends an
|
|
136
|
+
# extended data packet over the channel.
|
|
137
|
+
def on_extended_data( &block )
|
|
138
|
+
@on_extended_data = block
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Set the callback to be invoked when the server sends an EOF
|
|
142
|
+
# packet.
|
|
143
|
+
def on_eof( &block )
|
|
144
|
+
@on_eof = block
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Set the callback to be invoked when the server sends a
|
|
148
|
+
# request packet.
|
|
149
|
+
def on_request( &block )
|
|
150
|
+
@on_request = block
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Set the callback to invoked when the server sends
|
|
154
|
+
# confirmation of a successful operation.
|
|
155
|
+
def on_success( &block )
|
|
156
|
+
@on_success = block
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Set the callback to invoked when the server sends
|
|
160
|
+
# notification of a failed operation.
|
|
161
|
+
def on_failure( &block )
|
|
162
|
+
@on_failure = block
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Set the callback to be invoked when the channel is closed.
|
|
166
|
+
def on_close( &block )
|
|
167
|
+
@on_close = block
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#--
|
|
171
|
+
# ====================================================================
|
|
172
|
+
# CHANNEL STATE ACCESSORS
|
|
173
|
+
# ====================================================================
|
|
174
|
+
#++
|
|
175
|
+
|
|
176
|
+
def valid?
|
|
177
|
+
not @local_id.nil?
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Retrieved a named property of the channel.
|
|
181
|
+
def property( name )
|
|
182
|
+
( @properties ||= Hash.new )[ name ]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Set a named property on the channel.
|
|
186
|
+
def set_property( name, value )
|
|
187
|
+
( @properties ||= Hash.new )[ name ] = value
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
alias :[] :property
|
|
191
|
+
alias :[]= :set_property
|
|
192
|
+
|
|
193
|
+
#--
|
|
194
|
+
# ====================================================================
|
|
195
|
+
# CHANNEL AFFECTORS
|
|
196
|
+
# ====================================================================
|
|
197
|
+
#++
|
|
198
|
+
|
|
199
|
+
# Closes the channel.
|
|
200
|
+
def close( client_initiated=true )
|
|
201
|
+
unless defined?(@already_closed) && @already_closed
|
|
202
|
+
msg = @buffers.writer
|
|
203
|
+
msg.write_byte CHANNEL_CLOSE
|
|
204
|
+
msg.write_long @remote_id
|
|
205
|
+
@connection.send_message msg
|
|
206
|
+
@already_closed = true
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
unless client_initiated
|
|
210
|
+
@connection.remove_channel( self )
|
|
211
|
+
callback :close, self
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
self
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Send an EOF across the channel. No data should be sent from the client
|
|
218
|
+
# to the server over this channel after this, although packets may still
|
|
219
|
+
# be received from the server.
|
|
220
|
+
def send_eof
|
|
221
|
+
msg = @buffers.writer
|
|
222
|
+
msg.write_byte CHANNEL_EOF
|
|
223
|
+
msg.write_long @remote_id
|
|
224
|
+
@connection.send_message msg
|
|
225
|
+
self
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Send the given signal to process on the other side of the channel. The
|
|
229
|
+
# parameter should be one of the Channel::SIGxxx constants.
|
|
230
|
+
def send_signal( sig, want_reply=false )
|
|
231
|
+
send_request_string "signal", sig, want_reply
|
|
232
|
+
self
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Send a channel request with the given name. It will have one data
|
|
236
|
+
# item, which will be interpreted as a string.
|
|
237
|
+
def send_request_string( request_name, data, want_reply=false )
|
|
238
|
+
msg = @buffers.writer
|
|
239
|
+
msg.write_string data.to_s
|
|
240
|
+
send_request request_name, msg, want_reply
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Send a generic channel request with the given name. The data item will
|
|
244
|
+
# be written directly into the request (after converting it to a string,
|
|
245
|
+
# as necessary).
|
|
246
|
+
def send_request( request_name, data, want_reply=false )
|
|
247
|
+
msg = @buffers.writer
|
|
248
|
+
msg.write_byte CHANNEL_REQUEST
|
|
249
|
+
msg.write_long @remote_id
|
|
250
|
+
msg.write_string request_name
|
|
251
|
+
msg.write_bool want_reply
|
|
252
|
+
msg.write data.to_s
|
|
253
|
+
@connection.send_message msg
|
|
254
|
+
self
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Send a data packet to the server, over the channel.
|
|
258
|
+
def send_data( data )
|
|
259
|
+
msg = @buffers.writer
|
|
260
|
+
msg.write_byte CHANNEL_DATA
|
|
261
|
+
msg.write_long @remote_id
|
|
262
|
+
msg.write_string data.to_s
|
|
263
|
+
@connection.send_message msg
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Send an extended data packet to the server, over the channel.
|
|
267
|
+
# Extended data always has a numeric type associated with it. The
|
|
268
|
+
# only predefined type is 1, whic corresponds to +stderr+ data.
|
|
269
|
+
def send_extended_data( type, data )
|
|
270
|
+
msg = @buffers.writer
|
|
271
|
+
msg.write_byte CHANNEL_EXTENDED_DATA
|
|
272
|
+
msg.write_long @remote_id
|
|
273
|
+
msg.write_long type
|
|
274
|
+
msg.write_string data.to_s
|
|
275
|
+
@connection.send_message msg
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
VALID_PTY_OPTIONS = { :term=>"xterm",
|
|
279
|
+
:chars_wide=>80,
|
|
280
|
+
:chars_high=>24,
|
|
281
|
+
:pixels_wide=>640,
|
|
282
|
+
:pixels_high=>480,
|
|
283
|
+
:modes=>{},
|
|
284
|
+
:want_reply=>false }
|
|
285
|
+
|
|
286
|
+
# Request that a pty be opened for this channel. Valid options are
|
|
287
|
+
# :term, :chars_wide, :chars_high, :pixels_wide, :pixels_high, :modes,
|
|
288
|
+
# and :want_reply. :modes is a Hash, where the keys are constants from
|
|
289
|
+
# Net::SSH::Service::Term, and values are integers describing the
|
|
290
|
+
# corresponding key.
|
|
291
|
+
def request_pty( opts = {} )
|
|
292
|
+
invalid_opts = opts.keys - VALID_PTY_OPTIONS.keys
|
|
293
|
+
unless invalid_opts.empty?
|
|
294
|
+
raise ArgumentError,
|
|
295
|
+
"invalid option(s) to request_pty: #{invalid_opts.inspect}"
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
VALID_PTY_OPTIONS.keys.each do |opt|
|
|
299
|
+
opts[ opt ] ||= VALID_PTY_OPTIONS[ opt ]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
msg = @buffers.writer
|
|
303
|
+
msg.write_string opts[ :term ]
|
|
304
|
+
msg.write_long opts[ :chars_wide ]
|
|
305
|
+
msg.write_long opts[ :chars_high ]
|
|
306
|
+
msg.write_long opts[ :pixels_wide ]
|
|
307
|
+
msg.write_long opts[ :pixels_high ]
|
|
308
|
+
|
|
309
|
+
modes = @buffers.writer
|
|
310
|
+
opts[ :modes ].each do |mode, data|
|
|
311
|
+
modes.write_byte mode
|
|
312
|
+
modes.write_long data
|
|
313
|
+
end
|
|
314
|
+
modes.write_byte Term::TTY_OP_END
|
|
315
|
+
|
|
316
|
+
msg.write_string modes.to_s
|
|
317
|
+
|
|
318
|
+
send_request "pty-req", msg, opts[:want_reply]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Execute the given remote command over the channel. This should be
|
|
322
|
+
# invoked in the "on_confirm" callback of a channel. This method will
|
|
323
|
+
# return immediately.
|
|
324
|
+
def exec( command, want_reply=false )
|
|
325
|
+
send_request_string "exec", command, want_reply
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Request the given subsystem. This method will return immediately.
|
|
329
|
+
def subsystem( subsystem, want_reply=true )
|
|
330
|
+
send_request_string "subsystem", subsystem, want_reply
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
#--
|
|
334
|
+
# ====================================================================
|
|
335
|
+
# CHANNEL EVENTS
|
|
336
|
+
# ====================================================================
|
|
337
|
+
#++
|
|
338
|
+
|
|
339
|
+
# A convenience method for defining new event callbacks.
|
|
340
|
+
def self.event( event, *parameters )
|
|
341
|
+
define_method "do_#{event}" do |*args|
|
|
342
|
+
callback event, self, *args
|
|
343
|
+
self
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Invoked when the server confirms the opening of a channel.
|
|
348
|
+
def do_confirm_open( remote_id, window_size, packet_size )
|
|
349
|
+
@remote_id = remote_id
|
|
350
|
+
@window_size = window_size
|
|
351
|
+
@maximum_packet_size = packet_size
|
|
352
|
+
callback :confirm_open, self
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Invoked when the server failed to confirm the opening of a channel.
|
|
356
|
+
def do_confirm_failed( reason_code, description, language )
|
|
357
|
+
@local_id = nil
|
|
358
|
+
@connection = nil
|
|
359
|
+
callback :confirm_failed, self, reason_code, description, language
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Invoked when the server asks to adjust the window size. This in turn
|
|
363
|
+
# calls the "on_window_adjust" callback.
|
|
364
|
+
def do_window_adjust( bytes_to_add )
|
|
365
|
+
@window_size += bytes_to_add
|
|
366
|
+
callback :window_adjust, self, bytes_to_add
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Invoked when the server sends a data packet. This in turn calls the
|
|
370
|
+
# "on_data" callback.
|
|
371
|
+
event :data, :data
|
|
372
|
+
|
|
373
|
+
# Invoked when the server sends an extended data packet. This in turn
|
|
374
|
+
# calls the "on_extended_data" callback.
|
|
375
|
+
event :extended_data, :type, :data
|
|
376
|
+
|
|
377
|
+
# Invoked when the server sends an EOF packet. This in turn calls the
|
|
378
|
+
# "on_eof" callback.
|
|
379
|
+
event :eof
|
|
380
|
+
|
|
381
|
+
# Invoked when the server sends a request packet. This in turn calls
|
|
382
|
+
# the "on_request" callback.
|
|
383
|
+
event :request, :want_reply, :data
|
|
384
|
+
|
|
385
|
+
# Invoked when the server sends confirmation of a successful operation.
|
|
386
|
+
# This in turn invokes the "on_success" callback, if set.
|
|
387
|
+
event :success
|
|
388
|
+
|
|
389
|
+
# Invoked when the server sends notification of a failed operation.
|
|
390
|
+
# This in turn invokes the "on_failure" callback, if set.
|
|
391
|
+
event :failure
|
|
392
|
+
|
|
393
|
+
#--
|
|
394
|
+
# ====================================================================
|
|
395
|
+
# PRIVATE UTILITIES
|
|
396
|
+
# ====================================================================
|
|
397
|
+
#++
|
|
398
|
+
|
|
399
|
+
# A convenience utility method for invoking a named callback with a
|
|
400
|
+
# set of arguments.
|
|
401
|
+
def callback( which, *args )
|
|
402
|
+
block = instance_variable_get( "@on_#{which.to_s}" )
|
|
403
|
+
block.call( *args ) if block
|
|
404
|
+
end
|
|
405
|
+
private :callback
|
|
406
|
+
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
end
|