net-ssh 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. data/doc/LICENSE-BSD +27 -0
  2. data/doc/LICENSE-GPL +280 -0
  3. data/doc/LICENSE-RUBY +56 -0
  4. data/doc/README +13 -0
  5. data/doc/manual-html/chapter-1.html +333 -0
  6. data/doc/manual-html/chapter-2.html +455 -0
  7. data/doc/manual-html/chapter-3.html +413 -0
  8. data/doc/manual-html/chapter-4.html +353 -0
  9. data/doc/manual-html/chapter-5.html +393 -0
  10. data/doc/manual-html/chapter-6.html +296 -0
  11. data/doc/manual-html/index.html +217 -0
  12. data/doc/manual-html/manual.css +192 -0
  13. data/doc/manual/chapter.erb +18 -0
  14. data/doc/manual/example.erb +18 -0
  15. data/doc/manual/index.erb +29 -0
  16. data/doc/manual/manual.css +192 -0
  17. data/doc/manual/manual.rb +240 -0
  18. data/doc/manual/manual.yml +67 -0
  19. data/doc/manual/page.erb +87 -0
  20. data/doc/manual/parts/channels_callbacks.txt +32 -0
  21. data/doc/manual/parts/channels_loop.txt +14 -0
  22. data/doc/manual/parts/channels_open.txt +20 -0
  23. data/doc/manual/parts/channels_operations.txt +15 -0
  24. data/doc/manual/parts/channels_types.txt +3 -0
  25. data/doc/manual/parts/channels_what_are.txt +7 -0
  26. data/doc/manual/parts/exec_channels.txt +28 -0
  27. data/doc/manual/parts/exec_open.txt +51 -0
  28. data/doc/manual/parts/exec_popen3.txt +35 -0
  29. data/doc/manual/parts/forward_direct.txt +37 -0
  30. data/doc/manual/parts/forward_handlers.txt +16 -0
  31. data/doc/manual/parts/forward_intro.txt +18 -0
  32. data/doc/manual/parts/forward_local.txt +18 -0
  33. data/doc/manual/parts/forward_remote.txt +14 -0
  34. data/doc/manual/parts/intro_author.txt +1 -0
  35. data/doc/manual/parts/intro_getting.txt +39 -0
  36. data/doc/manual/parts/intro_license.txt +6 -0
  37. data/doc/manual/parts/intro_support.txt +7 -0
  38. data/doc/manual/parts/intro_what_is.txt +7 -0
  39. data/doc/manual/parts/intro_what_is_not.txt +3 -0
  40. data/doc/manual/parts/proxy_http.txt +52 -0
  41. data/doc/manual/parts/proxy_intro.txt +1 -0
  42. data/doc/manual/parts/proxy_socks.txt +23 -0
  43. data/doc/manual/parts/session_key.txt +66 -0
  44. data/doc/manual/parts/session_options.txt +42 -0
  45. data/doc/manual/parts/session_session.txt +14 -0
  46. data/doc/manual/parts/session_start.txt +49 -0
  47. data/doc/manual/tutorial.erb +30 -0
  48. data/examples/channel-demo.rb +81 -0
  49. data/examples/port-forward.rb +51 -0
  50. data/examples/process-demo.rb +91 -0
  51. data/examples/remote-net-port-forward.rb +45 -0
  52. data/examples/remote-port-forward.rb +80 -0
  53. data/examples/tail-demo.rb +49 -0
  54. data/lib/net/ssh.rb +52 -0
  55. data/lib/net/ssh/connection/channel.rb +411 -0
  56. data/lib/net/ssh/connection/constants.rb +47 -0
  57. data/lib/net/ssh/connection/driver.rb +343 -0
  58. data/lib/net/ssh/connection/services.rb +72 -0
  59. data/lib/net/ssh/connection/term.rb +90 -0
  60. data/lib/net/ssh/errors.rb +27 -0
  61. data/lib/net/ssh/proxy/errors.rb +34 -0
  62. data/lib/net/ssh/proxy/http.rb +126 -0
  63. data/lib/net/ssh/proxy/socks4.rb +83 -0
  64. data/lib/net/ssh/proxy/socks5.rb +160 -0
  65. data/lib/net/ssh/service/forward/driver.rb +319 -0
  66. data/lib/net/ssh/service/forward/local-network-handler.rb +74 -0
  67. data/lib/net/ssh/service/forward/remote-network-handler.rb +81 -0
  68. data/lib/net/ssh/service/forward/services.rb +76 -0
  69. data/lib/net/ssh/service/process/driver.rb +153 -0
  70. data/lib/net/ssh/service/process/open.rb +193 -0
  71. data/lib/net/ssh/service/process/popen3.rb +160 -0
  72. data/lib/net/ssh/service/process/services.rb +66 -0
  73. data/lib/net/ssh/service/services.rb +44 -0
  74. data/lib/net/ssh/session.rb +242 -0
  75. data/lib/net/ssh/transport/algorithm-negotiator.rb +267 -0
  76. data/lib/net/ssh/transport/compress/compressor.rb +53 -0
  77. data/lib/net/ssh/transport/compress/decompressor.rb +53 -0
  78. data/lib/net/ssh/transport/compress/none-compressor.rb +39 -0
  79. data/lib/net/ssh/transport/compress/none-decompressor.rb +39 -0
  80. data/lib/net/ssh/transport/compress/services.rb +68 -0
  81. data/lib/net/ssh/transport/compress/zlib-compressor.rb +60 -0
  82. data/lib/net/ssh/transport/compress/zlib-decompressor.rb +52 -0
  83. data/lib/net/ssh/transport/constants.rb +66 -0
  84. data/lib/net/ssh/transport/errors.rb +47 -0
  85. data/lib/net/ssh/transport/identity-cipher.rb +61 -0
  86. data/lib/net/ssh/transport/kex/dh-gex.rb +106 -0
  87. data/lib/net/ssh/transport/kex/dh.rb +231 -0
  88. data/lib/net/ssh/transport/kex/services.rb +60 -0
  89. data/lib/net/ssh/transport/ossl/buffer-factory.rb +52 -0
  90. data/lib/net/ssh/transport/ossl/buffer.rb +87 -0
  91. data/lib/net/ssh/transport/ossl/cipher-factory.rb +98 -0
  92. data/lib/net/ssh/transport/ossl/digest-factory.rb +51 -0
  93. data/lib/net/ssh/transport/ossl/hmac-factory.rb +71 -0
  94. data/lib/net/ssh/transport/ossl/hmac/hmac.rb +62 -0
  95. data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +44 -0
  96. data/lib/net/ssh/transport/ossl/hmac/md5.rb +46 -0
  97. data/lib/net/ssh/transport/ossl/hmac/none.rb +46 -0
  98. data/lib/net/ssh/transport/ossl/hmac/services.rb +68 -0
  99. data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +44 -0
  100. data/lib/net/ssh/transport/ossl/hmac/sha1.rb +45 -0
  101. data/lib/net/ssh/transport/ossl/key-factory.rb +113 -0
  102. data/lib/net/ssh/transport/ossl/services.rb +149 -0
  103. data/lib/net/ssh/transport/packet-stream.rb +210 -0
  104. data/lib/net/ssh/transport/services.rb +146 -0
  105. data/lib/net/ssh/transport/session.rb +296 -0
  106. data/lib/net/ssh/transport/version-negotiator.rb +73 -0
  107. data/lib/net/ssh/userauth/agent.rb +218 -0
  108. data/lib/net/ssh/userauth/constants.rb +35 -0
  109. data/lib/net/ssh/userauth/driver.rb +176 -0
  110. data/lib/net/ssh/userauth/methods/hostbased.rb +119 -0
  111. data/lib/net/ssh/userauth/methods/password.rb +70 -0
  112. data/lib/net/ssh/userauth/methods/publickey.rb +137 -0
  113. data/lib/net/ssh/userauth/methods/services.rb +63 -0
  114. data/lib/net/ssh/userauth/services.rb +126 -0
  115. data/lib/net/ssh/userauth/userkeys.rb +258 -0
  116. data/lib/net/ssh/util/buffer.rb +274 -0
  117. data/lib/net/ssh/util/openssl.rb +146 -0
  118. data/lib/net/ssh/util/prompter.rb +73 -0
  119. data/lib/net/ssh/version.rb +29 -0
  120. data/test/ALL-TESTS.rb +21 -0
  121. data/test/connection/tc_channel.rb +136 -0
  122. data/test/connection/tc_driver.rb +287 -0
  123. data/test/connection/tc_integration.rb +85 -0
  124. data/test/proxy/tc_http.rb +209 -0
  125. data/test/proxy/tc_socks4.rb +148 -0
  126. data/test/proxy/tc_socks5.rb +214 -0
  127. data/test/service/forward/tc_driver.rb +289 -0
  128. data/test/service/forward/tc_local_network_handler.rb +123 -0
  129. data/test/service/forward/tc_remote_network_handler.rb +108 -0
  130. data/test/service/process/tc_driver.rb +79 -0
  131. data/test/service/process/tc_integration.rb +117 -0
  132. data/test/service/process/tc_open.rb +179 -0
  133. data/test/service/process/tc_popen3.rb +164 -0
  134. data/test/tc_integration.rb +79 -0
  135. data/test/transport/compress/tc_none_compress.rb +41 -0
  136. data/test/transport/compress/tc_none_decompress.rb +45 -0
  137. data/test/transport/compress/tc_zlib_compress.rb +61 -0
  138. data/test/transport/compress/tc_zlib_decompress.rb +48 -0
  139. data/test/transport/kex/tc_dh.rb +304 -0
  140. data/test/transport/kex/tc_dh_gex.rb +70 -0
  141. data/test/transport/ossl/fixtures/dsa-encrypted +15 -0
  142. data/test/transport/ossl/fixtures/dsa-encrypted-bad +15 -0
  143. data/test/transport/ossl/fixtures/dsa-unencrypted +12 -0
  144. data/test/transport/ossl/fixtures/dsa-unencrypted-bad +12 -0
  145. data/test/transport/ossl/fixtures/dsa-unencrypted.pub +1 -0
  146. data/test/transport/ossl/fixtures/not-a-private-key +4 -0
  147. data/test/transport/ossl/fixtures/not-supported +2 -0
  148. data/test/transport/ossl/fixtures/rsa-encrypted +18 -0
  149. data/test/transport/ossl/fixtures/rsa-encrypted-bad +18 -0
  150. data/test/transport/ossl/fixtures/rsa-unencrypted +15 -0
  151. data/test/transport/ossl/fixtures/rsa-unencrypted-bad +15 -0
  152. data/test/transport/ossl/fixtures/rsa-unencrypted.pub +1 -0
  153. data/test/transport/ossl/hmac/tc_hmac.rb +58 -0
  154. data/test/transport/ossl/hmac/tc_md5.rb +50 -0
  155. data/test/transport/ossl/hmac/tc_md5_96.rb +50 -0
  156. data/test/transport/ossl/hmac/tc_none.rb +50 -0
  157. data/test/transport/ossl/hmac/tc_sha1.rb +50 -0
  158. data/test/transport/ossl/hmac/tc_sha1_96.rb +50 -0
  159. data/test/transport/ossl/tc_buffer.rb +97 -0
  160. data/test/transport/ossl/tc_buffer_factory.rb +67 -0
  161. data/test/transport/ossl/tc_cipher_factory.rb +84 -0
  162. data/test/transport/ossl/tc_digest_factory.rb +39 -0
  163. data/test/transport/ossl/tc_hmac_factory.rb +72 -0
  164. data/test/transport/ossl/tc_key_factory.rb +199 -0
  165. data/test/transport/tc_algorithm_negotiator.rb +169 -0
  166. data/test/transport/tc_identity_cipher.rb +52 -0
  167. data/test/transport/tc_integration.rb +110 -0
  168. data/test/transport/tc_packet_stream.rb +183 -0
  169. data/test/transport/tc_session.rb +283 -0
  170. data/test/transport/tc_version_negotiator.rb +86 -0
  171. data/test/userauth/methods/tc_hostbased.rb +136 -0
  172. data/test/userauth/methods/tc_password.rb +89 -0
  173. data/test/userauth/methods/tc_publickey.rb +167 -0
  174. data/test/userauth/tc_agent.rb +223 -0
  175. data/test/userauth/tc_driver.rb +190 -0
  176. data/test/userauth/tc_integration.rb +81 -0
  177. data/test/userauth/tc_userkeys.rb +265 -0
  178. data/test/util/tc_buffer.rb +217 -0
  179. metadata +256 -0
@@ -0,0 +1,67 @@
1
+ --- !jamisbuck.org,2004/^manual
2
+
3
+ # This content is made available under the Attribution-ShareAlike 2.0
4
+ # license from the Create Commons:
5
+ #
6
+ # http://creativecommons.org/licenses/by-sa/2.0/
7
+
8
+ meta: !^meta
9
+ copyright: 2004
10
+ author: Jamis Buck
11
+ email: jgb3@email.byu.edu
12
+
13
+ product: !^product
14
+ name: Net::SSH
15
+ tagline: Secure Shell for Ruby
16
+ version: !!eval require "../../lib/net/ssh/version"; Net::SSH::Version::STRING
17
+ #logo: net-ssh.png
18
+ urls:
19
+ - Project Page: http://rubyforge.org/projects/net-ssh
20
+ - User Manual: http://net-ssh.rubyforge.org
21
+ - API Documentation: http://net-ssh.rubyforge.org/api
22
+ - FAQ Document: http://net-ssh.rubyforge.org/faq.html
23
+ - Net::SSH Wiki: http://net-ssh.rubyforge.org/wiki/wiki.pl
24
+
25
+ recent_updates:
26
+ - "New Net::SSH Version"
27
+
28
+ chapters:
29
+
30
+ - Introduction:
31
+ - "What is Net::SSH?": !!file parts/intro_what_is.txt
32
+ - "What isn't Net::SSH?": !!file parts/intro_what_is_not.txt
33
+ - "Getting Net::SSH": !!file parts/intro_getting.txt
34
+ - License Information: !!file parts/intro_license.txt
35
+ - Support: !!file parts/intro_support.txt
36
+ - About the Author: !!file parts/intro_author.txt
37
+
38
+ - Starting a Session:
39
+ - "Using Net::SSH.start": !!file parts/session_start.txt
40
+ - Using a Public/Private Key: !!file parts/session_key.txt
41
+ - Options: !!file parts/session_options.txt
42
+ - "Using Net::SSH::Session": !!file parts/session_session.txt
43
+
44
+ - Channels:
45
+ - What are Channels?: !!file parts/channels_what_are.txt
46
+ - Session.loop: !!file parts/channels_loop.txt
47
+ - Channel Types: !!file parts/channels_types.txt
48
+ - Opening a Channel: !!file parts/channels_open.txt
49
+ - Callbacks: !!file parts/channels_callbacks.txt
50
+ - Channel Operations: !!file parts/channels_operations.txt
51
+
52
+ - Executing Commands:
53
+ - Using Channels: !!file parts/exec_channels.txt
54
+ - "Using #process.open": !!file parts/exec_open.txt
55
+ - "Using #process.popen3": !!file parts/exec_popen3.txt
56
+
57
+ - Port Forwarding:
58
+ - Introduction: !!file parts/forward_intro.txt
59
+ - Local-to-Remote: !!file parts/forward_local.txt
60
+ - Remote-to-Local: !!file parts/forward_remote.txt
61
+ - Direct Channels: !!file parts/forward_direct.txt
62
+ - Remote-to-Local Handlers: !!file parts/forward_handlers.txt
63
+
64
+ - Using Proxies:
65
+ - Introduction: !!file parts/proxy_intro.txt
66
+ - HTTP: !!file parts/proxy_http.txt
67
+ - SOCKS: !!file parts/proxy_socks.txt
@@ -0,0 +1,87 @@
1
+ <html>
2
+ <head>
3
+ <title><%= manual.product.name %> Manual<% if object %> :: <%= object.page_title %><% end %></title>
4
+ <link type="text/css" rel="stylesheet" href="manual.css" />
5
+ </head>
6
+
7
+ <body>
8
+ <div id="banner">
9
+ <table border='0' cellpadding='0' cellspacing='0' width='100%'>
10
+ <tr><td valign='top' align='left'>
11
+ <div class="title">
12
+ <span class="product"><%= manual.product.name %>&mdash;</span><br />
13
+ <span class="tagline"><%= manual.product.tagline %></span>
14
+ </div>
15
+ </td><td valign='middle' align='right'>
16
+ <div class="info">
17
+ <%= manual.product.name %> Version: <strong><%= manual.product.version %></strong><br />
18
+ Manual Last Updated: <strong><%= Time.now.gmtime.strftime('%Y-%m-%d %H:%M %Z') %></strong>
19
+ </div>
20
+ </td></tr>
21
+ </table>
22
+ </div>
23
+
24
+ <table border='0' width='100%' cellpadding='0' cellspacing='0'>
25
+ <tr><td valign='top'>
26
+
27
+ <div id="navigation">
28
+ <h1><%= manual.product.name %> Manual</h1>
29
+
30
+ <h2>Chapters</h2>
31
+ <ol type="I">
32
+ <% manual.chapters.each do |c| %>
33
+ <li><%= "<strong>" if c == object %>
34
+ <a href="chapter-<%= c.index %>.html">
35
+ <%= c.title %>
36
+ </a>
37
+ <%= "</strong> <big>&larr;</big>" if c == object %>
38
+ <ol type="1">
39
+ <% c.sections.each do |s|
40
+ next unless s.title %>
41
+ <li><a href="chapter-<%= c.index %>.html#s<%= s.index %>"><%= s.title %></a></li>
42
+ <% end %>
43
+ </ol>
44
+ </li>
45
+ <% end %>
46
+ </ol>
47
+
48
+ <h2>Other Documentation</h2>
49
+
50
+ <ul>
51
+ <li><a href="http://net-ssh.rubyforge.org/api/index.html">Net::SSH API</a></li>
52
+ <li><a href="http://rubyforge.org/tracker/?atid=1842&group_id=274&func=browse">Net::SSH FAQ</a></li>
53
+ </ul>
54
+
55
+ <h2>Tutorials</h2>
56
+ <ol>
57
+ <% manual.tutorials.each do |t| %>
58
+ <li><%= "<strong>" if t == object %>
59
+ <a href="tutorial-<%= t.index %>.html">
60
+ <%= t.title %>
61
+ </a>
62
+ <%= "</strong> <big>&larr;</big>" if t == object %><br />
63
+ <%= t.brief.to_html %>
64
+ </li>
65
+ <% end %>
66
+ </ol>
67
+
68
+ <p align="center"><strong>More To Come...</strong></p>
69
+
70
+ <div class="license">
71
+ <a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
72
+ This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
73
+ </div>
74
+ </div>
75
+
76
+ </td><td valign='top' width="100%">
77
+
78
+ <div id="content">
79
+
80
+ <%= guts %>
81
+
82
+ </div>
83
+
84
+ </td></tr>
85
+ </table>
86
+ </body>
87
+ </html>
@@ -0,0 +1,32 @@
1
+ There are various callbacks that may be registered on a channel. Registering a callback is as simple as invoking the corresponding method on the channel and giving it a block that should be invoked when the named action occurs. The following table describes each callback and how it is used.
2
+
3
+ table(list).
4
+ |_. Name |_. Description |
5
+ |=^. @on_close@ | This callback should accept a single parameter: the channel being closed. It is called immediately after the channel is removed from the connection. The callback should not send any data through the channel, since at this point the channel is no longer connected to the remote host.|
6
+ |=^. @on_confirm_failed@ | This callback should accept four parameters: the channel instance, the reason code, a description of why the confirm failed, and the language code for the message. It is called immediately after the server has indicated that a channel could not be opened.|
7
+ |=^. @on_confirm_open@ | This callback should accept a single parameter: the channel being opened. It is called immediately after the server has confirmed that the channel has been opened. This callback is typically set by a block passed to an @#open_channel@ call.|
8
+ |=^. @on_data@ | This callback is invoked when data is received over the channel from the remote server. This data typically corresponds to the remote process's @stdout@ stream. The channel should accept two parameters: the channel itself, and the data being received.|
9
+ |=^. @on_eof@ | This callback is called when the server indicates that no more data will be sent _from the server_ over this channel. Your program is still welcome to send data to the server, but you are guaranteed at this point that your @on_data@ and @on_extended_data@ callbacks will no longer be called for this channel. The callback should accept a single parameter, the channel itself.|
10
+ |=^. @on_extended_data@ | This callback is called when _extended data_ is received from the server. There are (potentially) many _types_ of extended data. The callback should accept three parameters: the channel, an integer indicating the type of the data, and the data itself. Right now, you can pretty much count on the data type being a "1", which corresponds to the remote process's @stderr@ stream. Other data types are not defined in the SSH specification, but that does not mean some SSH servers won't try to invent their own.|
11
+ |=^. @on_failure@ | When a request is sent over a channel (via the @send_request@ or @send_request_string@ methods), it may either succeed or fail. If it fails, this callback will be invoked. It should take a single parameter: the channel itself.|
12
+ |=^. @on_request@ | When the server sends a "channel request" to the client, this callback will be invoked. Channel requests from the server typically indicate things like the exit status of a process. This callback should take three parameters: the channel, a boolean (indicating whether or not the server wants an explicit reply to this request), and the data from the request.|
13
+ |=^. @on_success@ | When a request is sent over a channel (via the @send_request@ or @send_request_string@ methods), it may either succeed or fail. If it succeeds, this callback will be invoked. It should take a single parameter: the channel itself.|
14
+ |=^. @on_window_adjust@ | When the server asks the client to adjust this channel's window size, this callback will be invoked. It should accept two parameters: the channel, and the number of bytes to add the channel's window size.|
15
+
16
+ In general, you will never need to register callbacks for @on_failure@, @on_request@, @on_success@, or @on_window_adjust@, unless you are needing to implement support for some subservice or piggy-backed protocol (like SFTP).
17
+
18
+ Following is an example of registering callbacks on a channel:
19
+
20
+ <pre>
21
+ Net::SSH.start( 'host' ) do |session|
22
+ session.open_channel do |channel|
23
+ channel.on_close do |ch|
24
+ puts "channel closed successfully."
25
+ end
26
+ puts "closing channel..."
27
+ channel.close
28
+ end
29
+
30
+ session.loop
31
+ end
32
+ </pre>
@@ -0,0 +1,14 @@
1
+ Because a session may be composed of multiple simultaneously operating channels, the Net::SSH interface works by means of _callbacks_. You specify actions that need to occur in response to various events, and when those events occur, the framework invokes the corresonding callbacks.
2
+
3
+ In order to allow the events to be processed in a continuous manner, you need to be sure to call the @loop@ method of your session handle, after setting up any callbacks that you want to be executed. If you do not call the @loop@ method, your session will terminate as soon as the block is exited, which means none of your carefully laid callbacks will ever be called.
4
+
5
+ The @loop@ method is easy to invoke:
6
+
7
+ <pre>
8
+ Net::SSH.start( 'host' ) do |session|
9
+ ...
10
+ session.loop
11
+ end
12
+ </pre>
13
+
14
+ Incidentally, the @loop@ method accepts an optional block, which if specified should return a "false" value when the loop should terminate. In the absense of a block, the loop will continue until there are no more open channels. Sometimes, however, you only want the loop to continue until some action occurs, at which time you then do some processing and then start the loop again.
@@ -0,0 +1,20 @@
1
+ The simplest way to open a channel is via the @open_channel@ method of Net::SSH::Session. By default, the channel will be of type "session", but you can optionally specify the channel type and any extra data to initialize the channel with. You also pass a block to the @open_channel@ invocation. This block will be called after the server has confirmed that the channel is valid and has been opened successfully.
2
+
3
+ The @open_channel@ method always returns immediately--all it does is inform the server that a channel needs to be opened and then registers the associated block as the callback to be invoked when the channel is confirmed.
4
+
5
+ This behavior is typical of most of the methods in the Net::SSH API; they simply send a request to the server and then (optionally) register a callback. Very few of them actually block (pause) until the server responds.
6
+
7
+ Here is an example of opening a channel:
8
+
9
+ <pre>
10
+ Net::SSH.start( 'host' ) do |session|
11
+ session.open_channel do |channel|
12
+ puts "channel successfully opened... closing..."
13
+ channel.close
14
+ end
15
+
16
+ session.loop
17
+ end
18
+ </pre>
19
+
20
+ Note the use of the @close@ method for the channel. Just like most methods in the Net::SSH API, it does not immediately close the channel, but instead sends a close request to the server and returns. When the server responds that the channel has been closed, the framework will then call any final callbacks for the channel and then remove it.
@@ -0,0 +1,15 @@
1
+ There are a variety of operations that may be performed on a channel. Some we've already mentioned, like registering callbacks, or closing the channel. Some of the other more common operations are listed (and described) in the following table.
2
+
3
+ table(list).
4
+ |_. Operation |_. Description |
5
+ | @#exec@ | Executes a command asynchronously on this channel.|
6
+ | @#request_pty@ | Requests that a pseudo-terminal (pty) be opened for this channel.|
7
+ | @#send_data@ | Sends the given data string to the server via this channel. This is useful for sending data to a remote process, or sending an SFTP packet to the SFTP subsystem.|
8
+ | @#send_eof@ | Tells the server that no further data will be sent from the client to the server. The client must honor this by not sending any more data (either normal or extended) to the server over this channel.|
9
+ | @#send_extended_data@ | Sends a data string to the server, along with an integer describing its type. This is typically used to send @stderr@ data.|
10
+ | @#send_request@ | Sends a named request to the server for this channel. This is primarily used by implementations of protocols and subsystems that run on top of SSH.|
11
+ | @#send_signal@ | Indicates that the server should send the given signal to the process on the other end of the channel.|
12
+ | @#subsystem@ | Requests that the server start the given subsystem on this channel. This is how (for instance) the SFTP subsystem is invoked. |
13
+
14
+ See the API documentation for an exhaustive reference of all available channel
15
+ operations.
@@ -0,0 +1,3 @@
1
+ Each channel has a _type_. Usually, you will use "session" channels, but there are also "x11" channels, "forwarded-tcpip" channels, and "direct-tcpip" channels. Net::SSH currently has no support for "x11" channels. The "forwarded-tcpip" and "direct-tcpip" channels are managed internally via the port-forwarding interfaces.
2
+
3
+ The "session" channel type allows for a broad range of actions, including (but not limited to) SFTP requests and remote process execution.
@@ -0,0 +1,7 @@
1
+ The SSH protocol requires that requests for services on a remote machine be made over _channels_. A single SSH connection may contain multiple channels, all run simultaneously over that connection.
2
+
3
+ Each channel, in turn, represents the processing of a single service. When you invoke a process on the remote host with Net::SSH, a channel is opened for that invocation, and all input and output relevant to that process is sent through that channel. The connection itself simply manages the packets of all of the channels that it has open.
4
+
5
+ This means that, for instance, over a single SSH connection you could execute a process, download a file via SFTP, and forward any number of ports, all (seemingly) at the same time!
6
+
7
+ Naturally, they do not occur simultaneously, but rather work in a "time-share" fashion by sharing the bandwidth of the connection. Nevertheless, the fact that these channels exist make working with the SSH protocol a bit more challenging than simpler protocols (like FTP, HTTP, or Telnet).
@@ -0,0 +1,28 @@
1
+ To run multiple processes in parallel, you can access the channel API directly, setting up multiple channels and callbacks in order to process the output from the channel.
2
+
3
+ Suppose, for example, that you wanted to run multiple "tail" commands on various logs on the remote machine, combining them all into the output on the client. Something like the following would suffice:
4
+
5
+ <pre>
6
+ def do_tail( session, file )
7
+ session.open_channel do |channel|
8
+ channel.on_data do |ch, data|
9
+ puts "[#{file}] -> #{data}"
10
+ end
11
+ channel.exec "tail -f #{file}"
12
+ end
13
+ end
14
+
15
+ Net::SSH.start( 'host' ) do |session|
16
+ do_tail session, "/var/log/messages"
17
+ do_tail session, "/var/log/XFree86.0.log"
18
+ do_tail session, "/var/log/tomcat/catalina.log"
19
+ do_tail session, "/var/log/mysql/mysql.err"
20
+ session.loop
21
+ end
22
+ </pre>
23
+
24
+ As you can see, four different logs are tailed on four separate channels. Each channel registers an @on_data@ callback (which simply displays the data it recieves, together with the name of the log file it came from). The @exec@ method of the channel is then invoked, which simply sends the request to execute the process to the server, and then returns.
25
+
26
+ The @loop@ method then blocks while packets and processed and callbacks are invoked, completing the program.
27
+
28
+ This approach works fine for processing data coming from the server, and with a little work and coordination can work well for sending data _to_ the server as well, by calling the @send_data@ method of the channel at the appropriate times. However, it requires a bit of forethought, since you have to come up with a simple state machine to manage most interactive sessions, and many times that's more effort than it is worth.
@@ -0,0 +1,51 @@
1
+ The @#process.open@ interface provides a simpler way to manage interactive sessions. It still works via callbacks, and it still requires a kind of state machine in order to process input, but it does simplify things a little bit.
2
+
3
+ Just open an SSH session. The @#process@ service of the session manages access to convenience methods for handling and communicating with remote processes. In particular the @#open@ method of the @#process@ service allows you to constuct callbacks for dealing with remote processes, more conveniently than using channels directly.
4
+
5
+ Consider the "bc" command. It is a command-line calculator that accepts expressions on @stdin@ and writes the results to @stdout@. When it encounters the word @quit@ on the input, it exits. Sounds like a great way to demonstrate the @process@ service...
6
+
7
+ <pre>
8
+ Net::SSH.start( 'host' ) do |session|
9
+
10
+ session.process.open( "bc" ) do |bc|
11
+ dialog = [ "5+5", "7*12", "sqrt(2.000000)", "quit" ]
12
+
13
+ bc.on_success do |p|
14
+ puts "requesting result of #{dialog.first}"
15
+ p.puts dialog.shift
16
+ end
17
+
18
+ bc.on_stdout do |p,data|
19
+ puts "--> #{data}"
20
+ unless dialog.empty?
21
+ puts "requesting result of #{dialog.first}"
22
+ p.puts dialog.shift
23
+ end
24
+ end
25
+
26
+ bc.on_exit do |p, status|
27
+ puts "process finished with exit status: #{status}"
28
+ end
29
+ end
30
+
31
+ end
32
+ </pre>
33
+
34
+
35
+ Notice the progression. First, the session itself is started. Then, while the session is active, the process is invoked (via @#process.open@). After we have a handle to the process (which is yielded to the block, in this case), we set up the callbacks on the process. These are reminiscent of, but different from, the callbacks that we set up on the channel itself in the previous section.
36
+
37
+ The following callbacks are defined for a process handle:
38
+
39
+ table(list).
40
+ |_. Name |_. Description |
41
+ |=^. @on_exit@ | This callback is invoked when the process terminates normally. The block should accept two parameters: the process handle itself, and the exit status of the process.|
42
+ |=^. @on_failure@ | This callback is invoked when the process could not be invoked. It should take two parameters: the process handle itself, and a status string (which currently always @nil@).|
43
+ |=^. @on_success@ | This callback is invoked after the process has been successfully started. The callback should take a single parameter: the process handle itself.|
44
+ |=^. @on_stderr@ | This callback is invoked when data is received from the process's @stderr@ stream. The callback should have two parameters: the process handle, and the data.|
45
+ |=^. @on_stdout@ | This callback is invoked when data is received from the process's @stdout@ stream. The callback should have two parameters: the process handle, and the data.|
46
+
47
+ Sending data to the process is as simple as calling @puts@ on the process handle. If you don't want a newline appended to your data, use @write@ instead.
48
+
49
+ Notice that, when sending a block to @#process.open@, you do not have to explicitly invoke @session.loop@. It is implicitly called at the end of the block. If you ever want to set up multiple processes to run in parallel, simply use @#process.open@ without a block. The process handle will be returned, and you will be required to execute @session.loop@ manually.
50
+
51
+ For more information on the @#process.open@ service, see the API documentation for @Net::SSH::Service::Process::Open@.
@@ -0,0 +1,35 @@
1
+ The last approach to interacting with remote processes is the @#popen3@ method of @#process@ service. It is a _synchronous_ approach, meaning that each method call _may_ (potentially) block until data is received; you can't be using other features of the Net::SSH package while using it, but you don't have to mess with callbacks.
2
+
3
+ If you are familiar with the "popen3" Ruby module, this will seem familiar. It's not a perfect clone of the "popen3" module's functionality, but it's close. What you do is you specify the process to invoke, and then you get three pseudo-IO objects back: the process's input stream, it's output stream, and it's error stream. You can write to the input stream to send data to the process, or read from the output and error streams. Reading from the output or error streams will block until data is available, which makes it very convenient for interacting with a single remote process.
4
+
5
+ Here's the previous "bc" example, rewritten to use @#popen3@:
6
+
7
+ <pre>
8
+ Net::SSH.start( 'host' ) do |session|
9
+
10
+ input, output, error = session.process.popen3( "bc" )
11
+
12
+ [ "5+5", "7*12", "sqrt(2.000000)" ].each do |formula|
13
+ input.puts formula
14
+ puts "#{formula}=#{output.read}"
15
+ end
16
+
17
+ input.puts "quit"
18
+
19
+ end
20
+ </pre>
21
+
22
+ Much more concise, isn't it? One caveat, though: there is no way to kill the process (unless the process can terminate itself, such as through the use of issuing bc's "quit" command as used above) without closing the session. To remedy this, there is also a block version of popen3 that provides an explicit scope for the three data streams:
23
+
24
+ <pre>
25
+ Net::SSH.start( 'host' ) do |session|
26
+ session.process.popen3( "bc" ) do |input, output, error|
27
+ [ "5+5", "7*12", "sqrt(2.000000)" ].each do |formula|
28
+ input.puts formula
29
+ puts "#{formula}=#{output.read}"
30
+ end
31
+ end
32
+ end
33
+ </pre>
34
+
35
+ The three streams will be closed and process explicitly terminated when the block ends.
@@ -0,0 +1,37 @@
1
+ Sometimes it might be nice to programmatically simulate a network connection on a local port and have it forwarded to the remote host. You can do this by means of the @#direct_channel@ method.
2
+
3
+ The @#direct_channel@ method looks similar to @#local@: the first three parameters are the local port to simulate the connection from, and the remote host and port that the connection should be forwarded to. The fourth parameter, however, is a _handler_, an object that is used as a callback for a variety of different events.
4
+
5
+ The handler for the @#direct_channel@ method may implement any of the following callbacks (all are optional, though you probably want to implement at least one or two of them):
6
+
7
+ table(list).
8
+ |_. Callback |_. Description |
9
+ |=^. @confirm@ | This is invoked when the channel has been opened and the remote host has confirmed it. This accepts four parameters: the channel itself, the local port, remote host, and remote port. (In this way, the same handler may be used for multiple forward requests.)|
10
+ |=^. @process@ | After the channel has been confirmed, this is invoked, to process the channel. This callback will be invoked in a new Thread, so that if your handler needs to listen to a socket and then send data received from it over the channel, it can do so without blocking the main loop. The callback accepts a single parameter, the channel handle itself.|
11
+ |=^. @on_close@ | This is called when the channel over which this forwarded connection is being processed has been closed. The callback accepts a single parameter, the channel itself.|
12
+ |=^. @on_eof@ | When the remote machine indicates it will send no more data, this callback will be invoked. It accepts a single parameter, the channel itself.|
13
+ |=^. @on_receive@ | This is invoked when data is received from the remote machine. It accepts two parameters: the channel handle, and the data that was received.|
14
+
15
+ For example, the following example pretends to be a client that has connected to the local host on a forwarded port:
16
+
17
+ <pre>
18
+ class Handler
19
+ def on_receive( channel, data )
20
+ puts "got data: #{data.inspect}"
21
+ channel.send_data "subsequent request"
22
+ end
23
+
24
+ def process( channel )
25
+ channel.send_data "initial request"
26
+ end
27
+ end
28
+
29
+ Net::SSH.start( 'host' ) do |session|
30
+ session.forward.direct_channel( 1234, 'somewhere.else.net',
31
+ 4321, Handler.new )
32
+
33
+ session.loop
34
+ end
35
+ </pre>
36
+
37
+ The local port number for @#direct_channel@ has no real purpose, other than to report to the SSH server that the "virtual" connection occurred on that port.
@@ -0,0 +1,16 @@
1
+ You can use handlers going in the other direction, too. If you want to programmatically process forwarded data from a remote host, you can use the @#remote@ method. This takes two parameters, with an optional third parameter. The two required parameters are the handler to use, and the remote port that should be listened to. The optional parameter is the remote bind address, which defaults to '127.0.0.1'.
2
+
3
+ (Incidentally, if the port is 0, a new port will be allocated for you automatically by the server.)
4
+
5
+ Whenever connections are received on the remote port, they will be forwarded to the handler, which may implement the following callbacks:
6
+
7
+ table(list).
8
+ |_. Callback |_. Description |
9
+ |=^. @error@ | This is invoked if the forward could not be initiated. It accepts a single parameter, which is the error message. |
10
+ |=^. @on_close@ | This is invoked when the channel that was assigned to process this forwarded connection has been closed. The callback takes one parameter: the channel itself. |
11
+ |=^. @on_eof@ | This is invoked when the remote end of the connection has promised not to send any more data. The local end of the channel may continue to send data, however. This callback takes on parameter: the channel itself.|
12
+ |=^. @on_open@ | This is invoked when a new connection is received over the forwarded channel. It accepts five parameters: the channel object, the connected address, the connected port, the originator address, and the originator port. |
13
+ |=^. @on_receive@ | This is invoked when data is received over the channel from the remote connection. It accepts two parameters: the channel object, and the data that was received. |
14
+ |=^. @setup@ | This is invoked immediately after the forward request has been acknowledged as successful. It accepts a single parameter, which is the port that was assigned to this forward. If the port parameter to @#remote@ was not 0, then that same value will be passed to the callback. Otherwise, the newly allocated port number will be passed to the callback. |
15
+
16
+ Note that the @on_receive@ handler is required--all other callbacks may remain unimplemented by the handler.
@@ -0,0 +1,18 @@
1
+ Port forwarding is a feature of the SSH protocol that allows you to specify a port on one of the hosts, and have network connections on that port forwarded to a port on a different host, using the SSH connection as a proxy. There are basically two ways to use this forwarding:
2
+
3
+ # A port on the local host is forwarded via the remote host to another machine. Any connection to the specified port will cause all subsequent data to be sent over the connection to the remote host, where it will then be forwarded to the requested destination host.
4
+ # A port on the remote host is forwarded over the connection to the local host, and from there to (potentially) some other remote destination. Any connection to the specified port on the remote host is forwarded over the connection to the local host, which then makes a connection to the specified remote destination and sends the data there.
5
+
6
+ All port forwarding in the Net::SSH library is managed by the @#forward@ service. Just invoke methods on that service to set up any of various port forwarding configurations.
7
+
8
+ <pre>
9
+ Net::SSH.start( 'host' ) do |session|
10
+ forward = session.forward
11
+ ...
12
+ session.loop
13
+ end
14
+ </pre>
15
+
16
+ You can define any number of forwards before invoking the main loop, in which case all of those forwards will be handled transparently (and silently) in parallel, over the same connection. (Isn't SSH lovely?)
17
+
18
+ Naturally, you can also have remote processes, SFTP sessions, and more all working at the same time on the connection.