net-ssh 0.6.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data/doc/manual-html/chapter-1.html +59 -24
  2. data/doc/manual-html/chapter-2.html +116 -77
  3. data/doc/manual-html/chapter-3.html +80 -41
  4. data/doc/manual-html/chapter-4.html +111 -71
  5. data/doc/manual-html/chapter-5.html +267 -155
  6. data/doc/manual-html/chapter-6.html +211 -75
  7. data/doc/manual-html/chapter-7.html +331 -0
  8. data/doc/manual-html/index.html +39 -13
  9. data/doc/manual-html/{manual.css → stylesheets/manual.css} +81 -8
  10. data/doc/manual-html/stylesheets/ruby.css +17 -0
  11. data/doc/manual/chapter.erb +20 -0
  12. data/doc/manual/manual.rb +80 -9
  13. data/doc/manual/manual.yml +12 -2
  14. data/doc/manual/page.erb +1 -1
  15. data/doc/manual/parts/channels_callbacks.txt +11 -11
  16. data/doc/manual/parts/channels_loop.txt +6 -6
  17. data/doc/manual/parts/channels_open.txt +9 -9
  18. data/doc/manual/parts/exec_channels.txt +15 -15
  19. data/doc/manual/parts/exec_open.txt +17 -18
  20. data/doc/manual/parts/exec_popen3.txt +18 -18
  21. data/doc/manual/parts/forward_direct.txt +16 -16
  22. data/doc/manual/parts/forward_intro.txt +7 -7
  23. data/doc/manual/parts/forward_local.txt +9 -9
  24. data/doc/manual/parts/forward_remote.txt +9 -9
  25. data/doc/manual/parts/intro_getting.txt +11 -11
  26. data/doc/manual/parts/proxy_http.txt +27 -27
  27. data/doc/manual/parts/proxy_socks.txt +17 -17
  28. data/doc/manual/parts/session_key.txt +13 -14
  29. data/doc/manual/parts/session_options.txt +14 -14
  30. data/doc/manual/parts/session_session.txt +9 -9
  31. data/doc/manual/parts/session_start.txt +27 -27
  32. data/doc/manual/parts/shells_channels.txt +72 -0
  33. data/doc/manual/parts/shells_clients.txt +51 -0
  34. data/doc/manual/parts/shells_intro.txt +7 -0
  35. data/doc/manual/parts/shells_shell.txt +50 -0
  36. data/doc/manual/parts/shells_sync.txt +42 -0
  37. data/doc/manual/{manual.css → stylesheets/manual.css} +81 -8
  38. data/doc/manual/stylesheets/ruby.css +17 -0
  39. data/examples/channel-demo.rb +1 -1
  40. data/examples/port-forward.rb +1 -1
  41. data/examples/process-demo.rb +1 -1
  42. data/examples/remote-net-port-forward.rb +1 -1
  43. data/examples/remote-port-forward.rb +1 -1
  44. data/examples/shell-demo.rb +46 -0
  45. data/examples/ssh-client.rb +67 -0
  46. data/examples/sync-shell-demo.rb +69 -0
  47. data/examples/tail-demo.rb +1 -1
  48. data/lib/net/ssh.rb +1 -1
  49. data/lib/net/ssh/connection/channel.rb +61 -7
  50. data/lib/net/ssh/connection/constants.rb +1 -1
  51. data/lib/net/ssh/connection/driver.rb +61 -8
  52. data/lib/net/ssh/connection/services.rb +1 -1
  53. data/lib/net/ssh/connection/term.rb +1 -1
  54. data/lib/net/ssh/errors.rb +1 -1
  55. data/lib/net/ssh/proxy/errors.rb +1 -1
  56. data/lib/net/ssh/proxy/http.rb +1 -1
  57. data/lib/net/ssh/proxy/socks4.rb +1 -1
  58. data/lib/net/ssh/proxy/socks5.rb +1 -1
  59. data/lib/net/ssh/service/forward/driver.rb +1 -1
  60. data/lib/net/ssh/service/forward/local-network-handler.rb +1 -1
  61. data/lib/net/ssh/service/forward/remote-network-handler.rb +1 -1
  62. data/lib/net/ssh/service/forward/services.rb +1 -1
  63. data/lib/net/ssh/service/process/driver.rb +1 -1
  64. data/lib/net/ssh/service/process/open.rb +1 -1
  65. data/lib/net/ssh/service/process/popen3.rb +20 -2
  66. data/lib/net/ssh/service/process/services.rb +1 -1
  67. data/lib/net/ssh/service/services.rb +3 -1
  68. data/lib/net/ssh/service/shell/driver.rb +86 -0
  69. data/lib/net/ssh/service/shell/services.rb +54 -0
  70. data/lib/net/ssh/service/shell/shell.rb +213 -0
  71. data/lib/net/ssh/service/shell/sync.rb +114 -0
  72. data/lib/net/ssh/session.rb +9 -1
  73. data/lib/net/ssh/transport/algorithm-negotiator.rb +1 -1
  74. data/lib/net/ssh/transport/compress/compressor.rb +1 -1
  75. data/lib/net/ssh/transport/compress/decompressor.rb +1 -1
  76. data/lib/net/ssh/transport/compress/none-compressor.rb +1 -1
  77. data/lib/net/ssh/transport/compress/none-decompressor.rb +1 -1
  78. data/lib/net/ssh/transport/compress/services.rb +1 -1
  79. data/lib/net/ssh/transport/compress/zlib-compressor.rb +1 -1
  80. data/lib/net/ssh/transport/compress/zlib-decompressor.rb +1 -1
  81. data/lib/net/ssh/transport/constants.rb +1 -1
  82. data/lib/net/ssh/transport/errors.rb +1 -1
  83. data/lib/net/ssh/transport/identity-cipher.rb +1 -1
  84. data/lib/net/ssh/transport/kex/dh-gex.rb +1 -1
  85. data/lib/net/ssh/transport/kex/dh.rb +1 -1
  86. data/lib/net/ssh/transport/kex/services.rb +1 -1
  87. data/lib/net/ssh/transport/ossl/buffer-factory.rb +1 -1
  88. data/lib/net/ssh/transport/ossl/buffer.rb +1 -1
  89. data/lib/net/ssh/transport/ossl/cipher-factory.rb +1 -1
  90. data/lib/net/ssh/transport/ossl/digest-factory.rb +1 -1
  91. data/lib/net/ssh/transport/ossl/hmac-factory.rb +1 -1
  92. data/lib/net/ssh/transport/ossl/hmac/hmac.rb +1 -1
  93. data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +1 -1
  94. data/lib/net/ssh/transport/ossl/hmac/md5.rb +1 -1
  95. data/lib/net/ssh/transport/ossl/hmac/none.rb +1 -1
  96. data/lib/net/ssh/transport/ossl/hmac/services.rb +1 -1
  97. data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +1 -1
  98. data/lib/net/ssh/transport/ossl/hmac/sha1.rb +1 -1
  99. data/lib/net/ssh/transport/ossl/key-factory.rb +5 -2
  100. data/lib/net/ssh/transport/ossl/services.rb +1 -1
  101. data/lib/net/ssh/transport/packet-stream.rb +1 -1
  102. data/lib/net/ssh/transport/services.rb +1 -1
  103. data/lib/net/ssh/transport/session.rb +10 -1
  104. data/lib/net/ssh/transport/version-negotiator.rb +1 -1
  105. data/lib/net/ssh/userauth/agent.rb +1 -1
  106. data/lib/net/ssh/userauth/constants.rb +1 -1
  107. data/lib/net/ssh/userauth/driver.rb +1 -1
  108. data/lib/net/ssh/userauth/methods/hostbased.rb +1 -1
  109. data/lib/net/ssh/userauth/methods/keyboard-interactive.rb +104 -0
  110. data/lib/net/ssh/userauth/methods/password.rb +1 -1
  111. data/lib/net/ssh/userauth/methods/publickey.rb +1 -1
  112. data/lib/net/ssh/userauth/methods/services.rb +28 -6
  113. data/lib/net/ssh/userauth/services.rb +8 -5
  114. data/lib/net/ssh/userauth/userkeys.rb +1 -1
  115. data/lib/net/ssh/util/buffer.rb +1 -1
  116. data/lib/net/ssh/util/openssl.rb +1 -1
  117. data/lib/net/ssh/util/prompter.rb +1 -1
  118. data/lib/net/ssh/version.rb +2 -2
  119. data/test/ALL-TESTS.rb +1 -1
  120. data/test/connection/tc_channel.rb +1 -1
  121. data/test/connection/tc_driver.rb +1 -1
  122. data/test/connection/tc_integration.rb +1 -1
  123. data/test/proxy/tc_http.rb +1 -1
  124. data/test/proxy/tc_socks4.rb +1 -1
  125. data/test/proxy/tc_socks5.rb +1 -1
  126. data/test/service/forward/tc_driver.rb +1 -1
  127. data/test/service/forward/tc_local_network_handler.rb +1 -1
  128. data/test/service/forward/tc_remote_network_handler.rb +1 -1
  129. data/test/service/process/tc_driver.rb +1 -1
  130. data/test/service/process/tc_integration.rb +1 -1
  131. data/test/service/process/tc_open.rb +1 -1
  132. data/test/service/process/tc_popen3.rb +13 -13
  133. data/test/tc_integration.rb +1 -1
  134. data/test/transport/compress/tc_none_compress.rb +1 -1
  135. data/test/transport/compress/tc_none_decompress.rb +1 -1
  136. data/test/transport/compress/tc_zlib_compress.rb +1 -1
  137. data/test/transport/compress/tc_zlib_decompress.rb +1 -1
  138. data/test/transport/kex/tc_dh.rb +2 -1
  139. data/test/transport/kex/tc_dh_gex.rb +1 -1
  140. data/test/transport/ossl/hmac/tc_hmac.rb +1 -1
  141. data/test/transport/ossl/hmac/tc_md5.rb +1 -1
  142. data/test/transport/ossl/hmac/tc_md5_96.rb +1 -1
  143. data/test/transport/ossl/hmac/tc_none.rb +1 -1
  144. data/test/transport/ossl/hmac/tc_sha1.rb +1 -1
  145. data/test/transport/ossl/hmac/tc_sha1_96.rb +1 -1
  146. data/test/transport/ossl/tc_buffer.rb +1 -1
  147. data/test/transport/ossl/tc_buffer_factory.rb +1 -1
  148. data/test/transport/ossl/tc_cipher_factory.rb +1 -1
  149. data/test/transport/ossl/tc_digest_factory.rb +1 -1
  150. data/test/transport/ossl/tc_hmac_factory.rb +1 -1
  151. data/test/transport/ossl/tc_key_factory.rb +1 -1
  152. data/test/transport/tc_algorithm_negotiator.rb +1 -1
  153. data/test/transport/tc_identity_cipher.rb +1 -1
  154. data/test/transport/tc_integration.rb +1 -1
  155. data/test/transport/tc_packet_stream.rb +1 -1
  156. data/test/transport/tc_session.rb +1 -1
  157. data/test/transport/tc_version_negotiator.rb +1 -1
  158. data/test/userauth/methods/tc_hostbased.rb +1 -1
  159. data/test/userauth/methods/tc_password.rb +1 -1
  160. data/test/userauth/methods/tc_publickey.rb +1 -1
  161. data/test/userauth/tc_agent.rb +1 -1
  162. data/test/userauth/tc_driver.rb +1 -1
  163. data/test/userauth/tc_integration.rb +15 -1
  164. data/test/userauth/tc_userkeys.rb +1 -1
  165. data/test/util/tc_buffer.rb +5 -5
  166. metadata +26 -6
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head>
3
- <title>Net::SSH Manual :: Chapter 5: Port Forwarding</title>
4
- <link type="text/css" rel="stylesheet" href="manual.css" />
3
+ <title>Net::SSH Manual :: Chapter 5: User Shells</title>
4
+ <link type="text/css" rel="stylesheet" href="stylesheets/manual.css" />
5
5
  </head>
6
6
 
7
7
  <body>
@@ -14,8 +14,8 @@
14
14
  </div>
15
15
  </td><td valign='middle' align='right'>
16
16
  <div class="info">
17
- Net::SSH Version: <strong>0.6.0</strong><br />
18
- Manual Last Updated: <strong>2004-12-02 05:13 GMT</strong>
17
+ Net::SSH Version: <strong>0.9.0</strong><br />
18
+ Manual Last Updated: <strong>2005-01-11 21:39 GMT</strong>
19
19
  </div>
20
20
  </td></tr>
21
21
  </table>
@@ -110,36 +110,56 @@
110
110
 
111
111
  <li><strong>
112
112
  <a href="chapter-5.html">
113
- Port Forwarding
113
+ User Shells
114
114
  </a>
115
115
  </strong> <big>&larr;</big>
116
116
  <ol type="1">
117
117
 
118
118
  <li><a href="chapter-5.html#s1">Introduction</a></li>
119
119
 
120
- <li><a href="chapter-5.html#s2">Local-to-Remote</a></li>
120
+ <li><a href="chapter-5.html#s2">Using Channels</a></li>
121
121
 
122
- <li><a href="chapter-5.html#s3">Remote-to-Local</a></li>
122
+ <li><a href="chapter-5.html#s3">Shell Service</a></li>
123
123
 
124
- <li><a href="chapter-5.html#s4">Direct Channels</a></li>
124
+ <li><a href="chapter-5.html#s4">SyncShell Service</a></li>
125
125
 
126
- <li><a href="chapter-5.html#s5">Remote-to-Local Handlers</a></li>
126
+ <li><a href="chapter-5.html#s5">Terminal Clients</a></li>
127
127
 
128
128
  </ol>
129
129
  </li>
130
130
 
131
131
  <li>
132
132
  <a href="chapter-6.html">
133
- Using Proxies
133
+ Port Forwarding
134
134
  </a>
135
135
 
136
136
  <ol type="1">
137
137
 
138
138
  <li><a href="chapter-6.html#s1">Introduction</a></li>
139
139
 
140
- <li><a href="chapter-6.html#s2"><span class="caps">HTTP</span></a></li>
140
+ <li><a href="chapter-6.html#s2">Local-to-Remote</a></li>
141
+
142
+ <li><a href="chapter-6.html#s3">Remote-to-Local</a></li>
143
+
144
+ <li><a href="chapter-6.html#s4">Direct Channels</a></li>
145
+
146
+ <li><a href="chapter-6.html#s5">Remote-to-Local Handlers</a></li>
147
+
148
+ </ol>
149
+ </li>
150
+
151
+ <li>
152
+ <a href="chapter-7.html">
153
+ Using Proxies
154
+ </a>
155
+
156
+ <ol type="1">
157
+
158
+ <li><a href="chapter-7.html#s1">Introduction</a></li>
159
+
160
+ <li><a href="chapter-7.html#s2"><span class="caps">HTTP</span></a></li>
141
161
 
142
- <li><a href="chapter-6.html#s3"><span class="caps">SOCKS</span></a></li>
162
+ <li><a href="chapter-7.html#s3"><span class="caps">SOCKS</span></a></li>
143
163
 
144
164
  </ol>
145
165
  </li>
@@ -170,7 +190,17 @@
170
190
 
171
191
  <div id="content">
172
192
 
173
- <h1>5. Port Forwarding</h1>
193
+ <div class="top"><div class="prevnext">
194
+
195
+ <a href="chapter-4.html">Previous (4. Executing Commands)</a> |
196
+
197
+ <a href="index.html">Up</a>
198
+
199
+ | <a href="chapter-6.html">Next (6. Port Forwarding)</a>
200
+
201
+ </div></div>
202
+
203
+ <h1>5. User Shells</h1>
174
204
 
175
205
 
176
206
 
@@ -182,208 +212,290 @@
182
212
 
183
213
 
184
214
  <div class="section">
185
- <p>Port forwarding is a feature of the <span class="caps">SSH</span> 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 <span class="caps">SSH</span> connection as a proxy. There are basically two ways to use this forwarding:</p>
186
- <ol>
187
- <li>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.</li>
188
- <li>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.</li>
189
- </ol>
215
+ <p>A user&#8217;s <em>shell</em> is the environment in which commands are executed on a remote machine. There are a variety of different shells, including <a href="http://www.gnu.org/software/bash/bash.html">bash</a>, csh, tcsh, <a href="http://www.kornshell.com/">ksh</a>, and many others.</p>
190
216
 
191
- <p>All port forwarding in the Net::SSH library is managed by the <code>#forward</code> service. Just invoke methods on that service to set up any of various port forwarding configurations.</p>
217
+ <p>A shell may be executed like any other program, and when run, it (more-or-less) enters a read-execute-prompt cycle in which the user may interactively run commands.</p>
192
218
 
219
+ <p><span class="caps">SSH</span> has special support for shells, allowing you to start a shell on a channel and have all subsequent data sent to that channel interpreted as the user&#8217;s input to the shell. Also, <span class="caps">SSH</span> supports pty&#8217;s (<em>pseudo-tty</em>&#8217;s, or terminals), which allow the shell to act as if it were running locally on the users own machine.</p>
193
220
 
194
- <pre>
195
- Net::SSH.start( 'host' ) do |session|
196
- forward = session.forward
197
- ...
198
- session.loop
199
- end
200
- </pre>
201
- <p>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&#8217;t <span class="caps">SSH</span> lovely?)</p>
202
-
203
- <p>Naturally, you can also have remote processes, <span class="caps">SFTP</span> sessions, and more all working at the same time on the connection.</p>
221
+ <p>Because a shell is just a program, you can always start a shell simply by executing it (as described in the previous chapter). However, you can also take advantage of <span class="caps">SSH</span>&#8217;s builtin shell support to execute the user&#8217;s preferred shell. This chapter will discuss this approach.</p>
204
222
  </div>
205
223
 
206
224
 
207
225
 
208
226
  <h2>
209
227
  <a name="s2"></a>
210
- 5.2. Local-to-Remote
228
+ 5.2. Using Channels
211
229
  </h2>
212
230
 
213
231
 
214
232
 
215
233
  <div class="section">
216
- <p>Forwarding a local connection to a remote destination is simply a matter of invoking the <code>#local</code> method of the <code>#forward</code> service. The simplest version of the method just takes three parameters: the local port to listen on, and the remote host and port to forward the connection to:</p>
234
+ <p>At the lowest level, starting a shell is a matter of sending a &#8220;shell&#8221; request over a channel.</p>
235
+
236
+ <div class='figure'>
237
+ <span class='caption'>Sending a shell request [ruby]</span>
238
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="ident">host</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
239
+
240
+ <span class="ident">session</span><span class="punct">.</span><span class="ident">open_channel</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">channel</span><span class="punct">|</span>
241
+
242
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_success</span> <span class="keyword">do</span>
243
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell was started successfully!</span><span class="punct">&quot;</span>
244
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">send_data</span> <span class="punct">&quot;</span><span class="string">exit</span><span class="expr">\n</span><span class="punct">&quot;</span> <span class="comment"># tell the shell to exit</span>
245
+ <span class="keyword">end</span>
246
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_failure</span> <span class="keyword">do</span>
247
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell could not be started!</span><span class="punct">&quot;</span>
248
+ <span class="keyword">end</span>
249
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_data</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">ch</span><span class="punct">,</span><span class="ident">data</span><span class="punct">|</span>
250
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">recieved </span><span class="expr">#{data}</span><span class="string"> from shell</span><span class="punct">&quot;</span>
251
+ <span class="keyword">end</span>
252
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_close</span> <span class="keyword">do</span>
253
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell terminated</span><span class="punct">&quot;</span>
254
+ <span class="keyword">end</span>
255
+
256
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">send_request</span> <span class="punct">&quot;</span><span class="string">shell</span><span class="punct">&quot;,</span> <span class="constant">nil</span><span class="punct">,</span> <span class="constant">true</span>
257
+
258
+ <span class="keyword">end</span>
259
+
260
+ <span class="ident">session</span><span class="punct">.</span><span class="ident">loop</span>
261
+
262
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
263
+
264
+ <p>The <code>#send_request</code> method accepts three parameters&#8212;the name of the request (in this case, &#8220;shell&#8221;), any additional data to send with the request (none, in this case), and whether or not you want the server to reply with the success or failure of the request. In general, it is a good idea to ask for the server to reply, so that you know when you can start sending data to the shell.</p>
265
+
266
+ <p>If you want to open a pty before starting the shell, you can use the #request_pty method of the channel:</p>
267
+
268
+ <div class='figure'>
269
+ <span class='caption'>Opening a pty on a channel [ruby]</span>
270
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="ident">host</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
271
+
272
+ <span class="ident">session</span><span class="punct">.</span><span class="ident">open_channel</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">channel</span><span class="punct">|</span>
217
273
 
274
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_success</span> <span class="keyword">do</span>
275
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">pty was requested successfully!</span><span class="punct">&quot;</span>
218
276
 
219
- <pre>
220
- Net::SSH.start( 'host' ) do |session|
221
- session.forward.local( 1234, 'www.google.com', 80 )
222
- session.loop
223
- end
224
- </pre>
225
- <p>In the above example, then, any connection received on port 1234 will be forwarded to port 80 on &#8220;www.google.com&#8221;. This means that if you were to point a browser at &#8220;http://localhost:1234&#8221;, it would pull up <a href="http://www.google.com">Google</a>.</p>
277
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_success</span> <span class="keyword">do</span>
278
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell was started successfully!</span><span class="punct">&quot;</span>
279
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">send_data</span> <span class="punct">&quot;</span><span class="string">exit</span><span class="expr">\n</span><span class="punct">&quot;</span> <span class="comment"># tell the shell to exit</span>
280
+ <span class="keyword">end</span>
226
281
 
227
- <p>By default, only connections <em>from the local host</em> are accepted. This is because the default bind address is 127.0.0.1. You can specify any bind address you want (including 0.0.0.0 to allow connections from anywhere) by specifying that address as the first parameter to <code>#local</code>, with the local port number immediately following.</p>
282
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">send_request</span> <span class="punct">&quot;</span><span class="string">shell</span><span class="punct">&quot;,</span> <span class="constant">nil</span><span class="punct">,</span> <span class="constant">true</span>
283
+ <span class="keyword">end</span>
228
284
 
285
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_failure</span> <span class="keyword">do</span>
286
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell could not be started!</span><span class="punct">&quot;</span>
287
+ <span class="keyword">end</span>
288
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_data</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">ch</span><span class="punct">,</span><span class="ident">data</span><span class="punct">|</span>
289
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">recieved </span><span class="expr">#{data}</span><span class="string"> from shell</span><span class="punct">&quot;</span>
290
+ <span class="keyword">end</span>
291
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">on_close</span> <span class="keyword">do</span>
292
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">shell terminated</span><span class="punct">&quot;</span>
293
+ <span class="keyword">end</span>
229
294
 
230
- <pre>
231
- session.forward.local( '0.0.0.0', 1234, 'www.google.com', 80 )
232
- </pre>
233
- <p>In this configuration, anyone from anywhere can connect to your machine on port 1234 and be forwarded to Google.</p>
295
+ <span class="ident">channel</span><span class="punct">.</span><span class="ident">request_pty</span> <span class="symbol">:want_reply</span> <span class="punct">=&gt;</span> <span class="constant">true</span>
296
+
297
+ <span class="keyword">end</span>
298
+
299
+ <span class="ident">session</span><span class="punct">.</span><span class="ident">loop</span>
300
+
301
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
302
+
303
+ <p>First, the pty is requested (with an indicator to the server that it should return a &#8220;success&#8221; or &#8220;failure&#8221; notification). When the pty is successfully opened, the &#8220;on_success&#8221; callback is changed, and the shell is then requested.</p>
304
+
305
+ <p>It&#8217;s a lot of hoops to jump through, but it gives you the finest-grained control over opening a shell. For most things, though, you can live with less control. For those tasks, there are the <em>shell</em> and <em>sync</em> services.</p>
234
306
  </div>
235
307
 
236
308
 
237
309
 
238
310
  <h2>
239
311
  <a name="s3"></a>
240
- 5.3. Remote-to-Local
312
+ 5.3. Shell Service
241
313
  </h2>
242
314
 
243
315
 
244
316
 
245
317
  <div class="section">
246
- <p>Forwarding remote connections to the local host is also straightforward; simply call the <code>#remote_to</code> method of the <code>#forward</code> service. This takes three (or four) parameters: the local port and host to be forwarded to (in that order), and the remote port to listen on. The fourth parameter is optional, and is the bind address on the remote machine; this defaults to &#8220;127.0.0.1&#8221;.</p>
318
+ <p>To make interacting with shells, simpler, version 0.9 of Net::SSH introduced the <em>shell service</em>. This allows you to open a shell (with or without a pty), send a series of commands to the shell, and then wait for the output from the shell.</p>
319
+
320
+ <div class='figure'>
321
+ <span class='caption'>Using the shell service [ruby]</span>
322
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="punct">'</span><span class="string">localhost</span><span class="punct">'</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
323
+
324
+ <span class="ident">shell</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">.</span><span class="ident">shell</span><span class="punct">.</span><span class="ident">open</span>
325
+
326
+ <span class="comment"># script what we want to do</span>
327
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">pwd</span>
328
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">cd</span> <span class="punct">&quot;</span><span class="string">/</span><span class="punct">&quot;</span>
329
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">pwd</span>
330
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">test</span> <span class="punct">&quot;</span><span class="string">-e foo</span><span class="punct">&quot;</span>
331
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">cd</span> <span class="punct">&quot;</span><span class="string">/really/bogus/directory</span><span class="punct">&quot;</span>
332
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">send_data</span> <span class="punct">&quot;</span><span class="string">/sbin/ifconfig</span><span class="expr">\n</span><span class="punct">&quot;</span>
333
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">pwd</span>
334
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">ruby</span> <span class="punct">&quot;</span><span class="string">-v</span><span class="punct">&quot;</span>
335
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">cd</span> <span class="punct">&quot;</span><span class="string">/usr/lib</span><span class="punct">&quot;</span>
336
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">pwd</span>
337
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">exit</span>
338
+
339
+ <span class="comment"># give the above commands sufficient time to terminate</span>
340
+ <span class="ident">sleep</span> <span class="number">0.5</span>
247
341
 
342
+ <span class="comment"># display the output</span>
343
+ <span class="global">$stdout</span><span class="punct">.</span><span class="ident">print</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stdout</span> <span class="keyword">while</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stdout?</span>
344
+ <span class="global">$stderr</span><span class="punct">.</span><span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">-- stderr: --</span><span class="punct">&quot;</span>
345
+ <span class="global">$stderr</span><span class="punct">.</span><span class="ident">print</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stderr</span> <span class="keyword">while</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stderr?</span>
248
346
 
249
- <pre>
250
- Net::SSH.start( 'host' ) do |session|
251
- session.forward.remote_to( 80, 'www.google.com', 1234 )
252
- session.loop
253
- end
254
- </pre>
255
- <p>The above example causes any connection on port 1234 of the remote machine (<em>from</em> the remote machine) to be forwarded via the local host to port 80 at www.google.com. To make things a bit more open, you could specify a bind address of 0.0.0.0:</p>
347
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
256
348
 
349
+ <p>Any unrecognized method that is sent to the shell object is interpreted as a command to send to the server. To explicitly send a command, use the <code>#send_data</code> method (but remember to add a newline!). The <code>#send_data</code> method may also be used to send data to any process running in the shell as that process&#8217; <code>stdin</code> stream.</p>
257
350
 
258
- <pre>
259
- session.forward.remote_to( 80, 'www.google.com', 1234, '0.0.0.0' )
260
- </pre>
351
+ <p>You can also specify that a pty should be allocated for this shell:</p>
352
+
353
+ <div class='figure'>
354
+ <span class='caption'>Allocating a pty for the shell [ruby]</span>
355
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="punct">'</span><span class="string">localhost</span><span class="punct">'</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
356
+
357
+ <span class="ident">shell</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">.</span><span class="ident">shell</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span> <span class="symbol">:pty</span> <span class="punct">=&gt;</span> <span class="constant">true</span> <span class="punct">)</span>
358
+
359
+ <span class="comment"># or</span>
360
+
361
+ <span class="ident">shell</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">.</span><span class="ident">shell</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span> <span class="symbol">:pty</span> <span class="punct">=&gt;</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">}</span> <span class="punct">)</span>
362
+
363
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
364
+
365
+ <p>If you give a hash for the <code>:pty</code> option, it must be a map of the options that describe the new pty. See the <span class="caps">API</span> documentation for the Channel#request_pty method for more information.</p>
366
+
367
+ <p>Note that this is still an asynchronous approach. You send all the commands through the pipe and then wait for the output. (And be sure to give sufficient time or the processes to terminate!) This is fine for scripts that you just want to throw at the server, but many times you want a more interactive interface, for executing a command and receiving its output before moving on.</p>
261
368
  </div>
262
369
 
263
370
 
264
371
 
265
372
  <h2>
266
373
  <a name="s4"></a>
267
- 5.4. Direct Channels
374
+ 5.4. SyncShell Service
268
375
  </h2>
269
376
 
270
377
 
271
378
 
272
379
  <div class="section">
273
- <p>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 <code>#direct_channel</code> method.</p>
274
-
275
- <p>The <code>#direct_channel</code> method looks similar to <code>#local</code>: 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 <em>handler</em>, an object that is used as a callback for a variety of different events.</p>
276
-
277
- <p>The handler for the <code>#direct_channel</code> method may implement any of the following callbacks (all are optional, though you probably want to implement at least one or two of them):</p>
278
-
279
- <table class="list">
280
- <tr>
281
- <th>Callback </th>
282
- <th>Description </th>
283
- </tr>
284
- <tr>
285
- <td style="vertical-align:top;text-align:center;"><code>confirm</code> </td>
286
- <td> 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.)</td>
287
- </tr>
288
- <tr>
289
- <td style="vertical-align:top;text-align:center;"><code>process</code> </td>
290
- <td> 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.</td>
291
- </tr>
292
- <tr>
293
- <td style="vertical-align:top;text-align:center;"><code>on_close</code> </td>
294
- <td> 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.</td>
295
- </tr>
296
- <tr>
297
- <td style="vertical-align:top;text-align:center;"><code>on_eof</code> </td>
298
- <td> When the remote machine indicates it will send no more data, this callback will be invoked. It accepts a single parameter, the channel itself.</td>
299
- </tr>
300
- <tr>
301
- <td style="vertical-align:top;text-align:center;"><code>on_receive</code> </td>
302
- <td> This is invoked when data is received from the remote machine. It accepts two parameters: the channel handle, and the data that was received.</td>
303
- </tr>
304
- </table>
305
-
306
-
307
-
308
- <p>For example, the following example pretends to be a client that has connected to the local host on a forwarded port:</p>
309
-
310
-
311
- <pre>
312
- class Handler
313
- def on_receive( channel, data )
314
- puts "got data: #{data.inspect}"
315
- channel.send_data "subsequent request"
316
- end
317
-
318
- def process( channel )
319
- channel.send_data "initial request"
320
- end
321
- end
322
-
323
- Net::SSH.start( 'host' ) do |session|
324
- session.forward.direct_channel( 1234, 'somewhere.else.net',
325
- 4321, Handler.new )
326
-
327
- session.loop
328
- end
329
- </pre>
330
- <p>The local port number for <code>#direct_channel</code> has no real purpose, other than to report to the <span class="caps">SSH</span> server that the &#8220;virtual&#8221; connection occurred on that port.</p>
380
+ <p>The SyncShell service allows you to execute commands on the shell and block until they finish. It is not fool-proof&#8212;it has to use some tricks to accomplish this task, and some commands may foul it up. But for most tasks, it works admirably.</p>
381
+
382
+ <div class='figure'>
383
+ <span class='caption'>Using the SyncShell service [ruby]</span>
384
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="punct">'</span><span class="string">localhost</span><span class="punct">'</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
385
+
386
+ <span class="ident">shell</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">.</span><span class="ident">shell</span><span class="punct">.</span><span class="ident">sync</span>
387
+
388
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">pwd</span>
389
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">stdout</span>
390
+
391
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">test</span> <span class="punct">&quot;</span><span class="string">-e foo</span><span class="punct">&quot;</span>
392
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">status</span>
393
+
394
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">cd</span> <span class="punct">&quot;</span><span class="string">/really/bogus/directory</span><span class="punct">&quot;</span>
395
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">stderr</span>
396
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">status</span>
397
+
398
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">ruby</span> <span class="punct">&quot;</span><span class="string">-v</span><span class="punct">&quot;</span>
399
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">stdout</span>
400
+
401
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">cd</span> <span class="punct">&quot;</span><span class="string">/usr/lib</span><span class="punct">&quot;</span>
402
+
403
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">ls</span> <span class="punct">&quot;</span><span class="string">-l</span><span class="punct">&quot;</span>
404
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">stdout</span>
405
+
406
+ <span class="ident">out</span> <span class="punct">=</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">send_command</span><span class="punct">(</span> <span class="punct">&quot;</span><span class="string">bc</span><span class="punct">&quot;,</span> <span class="punct">&lt;&lt;</span><span class="constant">CMD</span><span class="string"> )
407
+ 5+5
408
+ 10*2
409
+ scale=5
410
+ 3/4
411
+ quit
412
+ </span><span class="constant">CMD</span>
413
+ <span class="ident">p</span> <span class="ident">out</span><span class="punct">.</span><span class="ident">stdout</span>
414
+
415
+ <span class="ident">p</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">exit</span>
416
+
417
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
418
+
419
+ <p>The result of executing each command is an object that encapsulates the <code>stdout</code> and <code>stderr</code> streams, and the exit status of the command.</p>
420
+
421
+ <p>To explicitly execute a command, use the <code>#send_command</code> instead of <code>#send_data</code>&#8212;otherwise, the command will be executed asynchronously, which is not what you want. Also, if you pass a second parameter to the <code>#send_command</code> method, it is interpreted as the <code>stdin</code> data to send to the new process.</p>
331
422
  </div>
332
423
 
333
424
 
334
425
 
335
426
  <h2>
336
427
  <a name="s5"></a>
337
- 5.5. Remote-to-Local Handlers
428
+ 5.5. Terminal Clients
338
429
  </h2>
339
430
 
340
431
 
341
432
 
342
433
  <div class="section">
343
- <p>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 <code>#remote</code> 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 &#8216;127.0.0.1&#8217;.</p>
344
-
345
- <p>(Incidentally, if the port is 0, a new port will be allocated for you automatically by the server.)</p>
346
-
347
- <p>Whenever connections are received on the remote port, they will be forwarded to the handler, which may implement the following callbacks:</p>
348
-
349
- <table class="list">
350
- <tr>
351
- <th>Callback </th>
352
- <th>Description </th>
353
- </tr>
354
- <tr>
355
- <td style="vertical-align:top;text-align:center;"><code>error</code> </td>
356
- <td> This is invoked if the forward could not be initiated. It accepts a single parameter, which is the error message. </td>
357
- </tr>
358
- <tr>
359
- <td style="vertical-align:top;text-align:center;"><code>on_close</code> </td>
360
- <td> 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. </td>
361
- </tr>
362
- <tr>
363
- <td style="vertical-align:top;text-align:center;"><code>on_eof</code> </td>
364
- <td> 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.</td>
365
- </tr>
366
- <tr>
367
- <td style="vertical-align:top;text-align:center;"><code>on_open</code> </td>
368
- <td> 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. </td>
369
- </tr>
370
- <tr>
371
- <td style="vertical-align:top;text-align:center;"><code>on_receive</code> </td>
372
- <td> 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. </td>
373
- </tr>
374
- <tr>
375
- <td style="vertical-align:top;text-align:center;"><code>setup</code> </td>
376
- <td> 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 <code>#remote</code> 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. </td>
377
- </tr>
378
- </table>
379
-
380
-
381
-
382
- <p>Note that the <code>on_receive</code> handler is required&#8212;all other callbacks may remain unimplemented by the handler.</p>
434
+ <p>Using the shell service and pty&#8217;s, you can now create a simple <span class="caps">SSH</span> terminal client. (You&#8217;ll also want to download and install the <a href="http://arika.org/ruby/termios">ruby-termios</a> library so that your input is not interpreted in a linewise fashion.)</p>
435
+
436
+ <div class='figure'>
437
+ <span class='caption'>A simple SSH terminal client in Ruby [ruby]</span>
438
+ <div class='body'><table border='0' cellpadding='0' cellspacing='0'><tr><td class='lineno'>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br /></td><td width='100%'><link rel='stylesheet' type='text/css' href='stylesheets/ruby.css' /><div class='ruby'><pre><span class="keyword">begin</span>
439
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">termios</span><span class="punct">'</span>
440
+ <span class="keyword">rescue</span> <span class="constant">LoadError</span>
441
+ <span class="keyword">end</span>
442
+
443
+ <span class="keyword">def </span><span class="method">stdin_buffer</span><span class="punct">(</span> <span class="ident">enable</span> <span class="punct">)</span>
444
+ <span class="keyword">return</span> <span class="keyword">unless</span> <span class="keyword">defined?</span><span class="punct">(</span> <span class="constant">Termios</span> <span class="punct">)</span>
445
+ <span class="ident">attr</span> <span class="punct">=</span> <span class="constant">Termios</span><span class="punct">::</span><span class="ident">getattr</span><span class="punct">(</span> <span class="global">$stdin</span> <span class="punct">)</span>
446
+ <span class="keyword">if</span> <span class="ident">enable</span>
447
+ <span class="ident">attr</span><span class="punct">.</span><span class="ident">c_lflag</span> <span class="punct">|=</span> <span class="constant">Termios</span><span class="punct">::</span><span class="constant">ICANON</span> <span class="punct">|</span> <span class="constant">Termios</span><span class="punct">::</span><span class="constant">ECHO</span>
448
+ <span class="keyword">else</span>
449
+ <span class="ident">attr</span><span class="punct">.</span><span class="ident">c_lflag</span> <span class="punct">&amp;=</span> ~<span class="punct">(</span><span class="constant">Termios</span><span class="punct">::</span><span class="constant">ICANON</span><span class="punct">|</span><span class="constant">Termios</span><span class="punct">::</span><span class="constant">ECHO</span><span class="punct">)</span>
450
+ <span class="keyword">end</span>
451
+ <span class="constant">Termios</span><span class="punct">::</span><span class="ident">setattr</span><span class="punct">(</span> <span class="global">$stdin</span><span class="punct">,</span> <span class="constant">Termios</span><span class="punct">::</span><span class="constant">TCSANOW</span><span class="punct">,</span> <span class="ident">attr</span> <span class="punct">)</span>
452
+ <span class="keyword">end</span>
453
+
454
+ <span class="ident">host</span> <span class="punct">=</span> <span class="constant">ARGV</span><span class="punct">.</span><span class="ident">shift</span> <span class="keyword">or</span> <span class="ident">abort</span> <span class="punct">&quot;</span><span class="string">You must specify the [user@]host to connect to</span><span class="punct">&quot;</span>
455
+ <span class="keyword">if</span> <span class="ident">host</span> <span class="punct">=~</span> <span class="punct">/</span><span class="regex">@</span><span class="punct">/</span>
456
+ <span class="ident">user</span><span class="punct">,</span> <span class="ident">host</span> <span class="punct">=</span> <span class="ident">host</span><span class="punct">.</span><span class="ident">match</span><span class="punct">(</span> <span class="punct">/</span><span class="regex">(.*?)@(.*)</span><span class="punct">/</span> <span class="punct">)[</span><span class="number">1</span><span class="punct">,</span><span class="number">2</span><span class="punct">]</span>
457
+ <span class="keyword">else</span>
458
+ <span class="ident">user</span> <span class="punct">=</span> <span class="constant">ENV</span><span class="punct">['</span><span class="string">USER</span><span class="punct">']</span> <span class="punct">||</span> <span class="constant">ENV</span><span class="punct">['</span><span class="string">USER_NAME</span><span class="punct">']</span>
459
+ <span class="keyword">end</span>
460
+
461
+ <span class="constant">Net</span><span class="punct">::</span><span class="constant">SSH</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span> <span class="ident">host</span><span class="punct">,</span> <span class="ident">user</span> <span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">session</span><span class="punct">|</span>
462
+
463
+ <span class="keyword">begin</span>
464
+ <span class="ident">stdin_buffer</span> <span class="constant">false</span>
465
+
466
+ <span class="ident">shell</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">.</span><span class="ident">shell</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span> <span class="symbol">:pty</span> <span class="punct">=&gt;</span> <span class="constant">true</span> <span class="punct">)</span>
467
+
468
+ <span class="ident">loop</span> <span class="keyword">do</span>
469
+ <span class="keyword">break</span> <span class="keyword">unless</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">open?</span>
470
+ <span class="keyword">if</span> <span class="constant">IO</span><span class="punct">.</span><span class="ident">select</span><span class="punct">([</span><span class="global">$stdin</span><span class="punct">],</span><span class="constant">nil</span><span class="punct">,</span><span class="constant">nil</span><span class="punct">,</span><span class="number">0.01</span><span class="punct">)</span>
471
+ <span class="ident">data</span> <span class="punct">=</span> <span class="global">$stdin</span><span class="punct">.</span><span class="ident">sysread</span><span class="punct">(</span><span class="number">1</span><span class="punct">)</span>
472
+ <span class="ident">shell</span><span class="punct">.</span><span class="ident">send_data</span> <span class="ident">data</span>
473
+ <span class="keyword">end</span>
474
+
475
+ <span class="global">$stdout</span><span class="punct">.</span><span class="ident">print</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stdout</span> <span class="keyword">while</span> <span class="ident">shell</span><span class="punct">.</span><span class="ident">stdout?</span>
476
+ <span class="global">$stdout</span><span class="punct">.</span><span class="ident">flush</span>
477
+ <span class="keyword">end</span>
478
+ <span class="keyword">ensure</span>
479
+ <span class="ident">stdin_buffer</span> <span class="constant">true</span>
480
+ <span class="keyword">end</span>
481
+
482
+ <span class="keyword">end</span></pre></div></td></tr></table></div></div>
483
+
484
+ <p>The above code is also available as an example script in the Net::SSH distribution (<code>examples/ssh-client.rb</code>).</p>
383
485
  </div>
384
486
 
385
487
 
386
488
 
489
+ <div class="bottom"><div class="prevnext">
490
+
491
+ <a href="chapter-4.html">Previous (4. Executing Commands)</a> |
492
+
493
+ <a href="index.html">Up</a>
494
+
495
+ | <a href="chapter-6.html">Next (6. Port Forwarding)</a>
496
+
497
+ </div></div>
498
+
387
499
 
388
500
  </div>
389
501