Net-SSH Threaded PortForward Script Problems

jamis,

i reversed order and still no luck i get the following error message
from the below code irb is telling me that the thread is still being
killed prior
to anything starting:

BEGIN ERROR MESSAGE

···

----------

[root@falcon1 src]# ./example.rb
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`initialize': Connection refused - connect(2) (Errno::ECONNREFUSED)
from
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`open'
from
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`initialize'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:175:in `new'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:175:in `open'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:93:in `start'
from ./example.rb:19
---------
END ERROR MESSAGE

BEGIN CODE
-------------

#!/usr/local/bin/ruby

require 'thread'
require 'net/ssh'
require 'net/ssh/service/forward'

threads =

t = Thread.new do
Net::SSH.start( 'localhost', 'localuser', 'passwd' ) do |session|
mgr = PortForwardManager.new( session )
mgr.forward_local( 1236, '10.0.0.4', 22 )
session.main_loop
end
end

Net::SSH.start( 'localhost', 1236, 'remoteuser', 'passwd' ) do

session>

result = session.exec("hostname; uptime")
puts result.data
end

threads.push( t )
threads.each { |t| t.join }

------
END

Take this with a grain of salt because I have't used the Ruby Thread
library, but is is possible that you have a race condition?

Your thread has 4 Ruby instructions to execute before you get to the
next SSH.start. That seems like a race condition to me. You need
sometype of event to signal after the secondary thread has gotten
started.

Maybe something like this...

m = Mutex.new()
cv = ConditionVariable.new()

t = Thread.new do
m.synchronize {
   Net::SSH.start( 'localhost', 'localuser', 'passwd' ) do |session|
   mgr = PortForwardManager.new( session )
   mgr.forward_local( 1236, '10.0.0.4', 22 )

   cv.signal
}
session.main_loop
end
end

# let other threads work
Thread.pass
m.synchronize {
   cv.wait(m)
}

Net::SSH.start( 'localhost', 1236, 'remoteuser', 'passwd' ) do

session>

result = session.exec("hostname; uptime")
puts result.data
end

threads.push( t )
threads.each { |t| t.join }

···

On Sun, 12 Sep 2004 00:54:59 +0900, otaku <justin@gezuinc.com> wrote:

jamis,

i reversed order and still no luck i get the following error message
from the below code irb is telling me that the thread is still being
killed prior
to anything starting:

BEGIN ERROR MESSAGE
----------

[root@falcon1 src]# ./example.rb
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`initialize': Connection refused - connect(2) (Errno::ECONNREFUSED)
from
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`open'
from
/usr/local/lib/ruby/site_ruby/1.8/net/ssh/transport/session.rb:132:in
`initialize'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:175:in `new'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:175:in `open'
from /usr/local/lib/ruby/site_ruby/1.8/net/ssh.rb:93:in `start'
from ./example.rb:19
---------
END ERROR MESSAGE

BEGIN CODE
-------------

#!/usr/local/bin/ruby

require 'thread'
require 'net/ssh'
require 'net/ssh/service/forward'

threads =

t = Thread.new do
Net::SSH.start( 'localhost', 'localuser', 'passwd' ) do |session|
mgr = PortForwardManager.new( session )
mgr.forward_local( 1236, '10.0.0.4', 22 )
session.main_loop
end
end

Net::SSH.start( 'localhost', 1236, 'remoteuser', 'passwd' ) do
>session>
result = session.exec("hostname; uptime")
puts result.data
end

threads.push( t )
threads.each { |t| t.join }

------
END

--
Justin Rudd
http://seagecko.org/thoughts/

Justin,

advise taken investigating
i am wondering why it dies
with only 1 thread
i scaled the script down to
1 thread
which should not be creating any race condition
so i am becoming confused with this one
i think i will leave it alone for a while
and come back to it

folks,

i am not sure i am going any further down this threading road
i am going to rework the script to do everything without threading
if it is at all possible

thank you to all

otaku

otaku wrote:

Justin,

advise taken investigating
i am wondering why it dies
with only 1 thread
i scaled the script down to
1 thread
which should not be creating any race condition
so i am becoming confused with this one
i think i will leave it alone for a while and come back to it

If you are doing even one call to Thread.new, then there are always at least two threads: the new one, and the main one (which started the new one). And if you're dealing with more than one thread, you are faced with the possibility of race conditions.

Consider:

Your main thread (A) starts. It spawns a new thread (B) and continues on. B is intended to start a forwarded port.

Before thread B can begin executing, A does Net::SSH.start to connect to the forwarded port that B was supposed to start, but B hasn't started it yet.

Hence, a race condition. This is where the condition variable is necessary. You let B signal A that it has started the server and set up a forwarded port. A waits until it receives that signal, and once it does, it then tries to connect. This way, you know that A never tries to connect until the forwarded ports are available.

Does that make sense?

- Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

"I use octal until I get to 8, and then I switch to decimal."