I’m writing a little expect-like piece of code and trying to test it
by connecting to a telnet port.
Not working at all for me.
Code is shown below.
And here’s the result:
[hal@dhcppc3]$ ruby repro.rb
"\377\375\030\377\375\037\377\375#\377\375’\377\375$"
repro.rb:14:in `wait’: Timed out waiting for login: (RuntimeError)
from repro.rb:37
What’s up??
Thanks,
Hal
require "socket"
class Talk
def initialize(input,wait=nil) @in, @out, @wait = input, input, wait @data = ""
end
def wait(str)
pos = nil
tmp = ""
until pos = @data.index(str)
unless IO.select([@in],nil,nil,@wait)
p @data
raise "Timed out waiting for #{str}"
end
begin @data << tmp = @in.getc
rescue EOFError, TypeError
raise "EOF…"
end
end
end
def send(str)
unless IO.select(nil, [@out], nil, @wait)
raise "Timed out writing #{str}"
end @out.syswrite(str)
end
end
I’m writing a little expect-like piece of code and trying to test it
by connecting to a telnet port.
Not working at all for me.
I made the obvious changes to make it connect to the SMTP daemon on my
machine and it works fine on Linux with Ruby 1.8.1 (2004-02-06).
Nothing is ever discarded from @data, and you search from the beginning
each time, so you’ll never find the second occurence of any string, but
that’s not the problem you’re having here.
Are you sure your telnet daemon is behaving? That trash string found at
the beginning is not right.
While I know your question is already answered, I just wanted to point
out that what you experienced here is tty negotiation. Expect
encapsulates all processes in a pty so that you could run the telnet
program or anything else and have it work as one would want.
Dan
···
On Apr 23, 2004, at 19:41, Hal Fulton wrote:
And here’s the result:
[hal@dhcppc3]$ ruby repro.rb
“\377\375\030\377\375\037\377\375#\377\375’\377\375$”
repro.rb:14:in `wait’: Timed out waiting for login: (RuntimeError)
from repro.rb:37
I’m writing a little expect-like piece of code and trying to test it
by connecting to a telnet port.
Not working at all for me.
I made the obvious changes to make it connect to the SMTP daemon on my
machine and it works fine on Linux with Ruby 1.8.1 (2004-02-06).
Nothing is ever discarded from @data, and you search from the beginning
each time, so you’ll never find the second occurence of any string, but
that’s not the problem you’re having here.
That’s a significant bug, thank you.
Are you sure your telnet daemon is behaving? That trash string found at
the beginning is not right.
Apparently the server is trying to negotiate with the client.
I tried to answer properly, to no avail.
Then I tried to use Net::Telnet to do it and then pretend to be an
ordinary socket. May work later, but not yet.
Hmm. How hard would it be to write a little program (say, a tiny
text adventure) to which I could connect via telnet? I’ve never
written anything like a telnet server, but it doesn’t seem hard
if we skip the “real” functionality of it. Am I wrong?
While I know your question is already answered, I just wanted to point
out that what you experienced here is tty negotiation. Expect
encapsulates all processes in a pty so that you could run the telnet
program or anything else and have it work as one would want.
Yes, I found a doc about that (or had it pointed out to me).
I couldn’t figure out how to answer successfully, though. It seemed
trivial, but didn’t work for me.
Then I thought: Maybe I can get Net::Telnet to do it for me, and then
I’ll let the connection serve as the socket. That didn’t work for me
either.
For now, I’m just opening sockets onto my little customized server –
a text adventure that currently has only five rooms.
threads =
cmd_buffer =
threads << Thread.new do
cmd = “”
puts “Started thread” if $DEBUG
call the proc object that creates the io object
f = io.call
while ! cmd.match(/^quit|q/i)
f.print “HA>”
f.flush
cmd = f.readline.chomp
next if cmd.empty?
puts “Got command #{cmd}” if $DEBUG
(f.close; next) if cmd.match(/^(quit|q)$/i)
# lock access to cmd_buffer since another thread will
# be reading it
mutex.synchronize {cmd_buffer << cmd }
end
end
threads.each { |t| t.join }
END
On the server:
···
===========
$ ruby -d test
Started thread
On the client:
$ telnet ital.jasonandvivian.net 4033
Trying 192.168.168.20…
Connected to ital.
Escape character is ‘^]’.
testing
this is a test
quit
Connection closed by foreign host.
On the server:
Got command testing
Got command this is a test
Got command quit
I wonder: How hard is it to write a server to which one would connect
with telnet?
Writing your own server is much easier and also more secure, not that
clear text is anything to brag about.
I had to write an expect program (I’m a long time TCL programmer) the
other day and was thinking about how nice it would be to have
ExpectRuby. It is pretty great to run sub-processes in a pty.
Dan
···
On Apr 27, 2004, at 01:02, Hal Fulton wrote:
Dan Janowski wrote:
While I know your question is already answered, I just wanted to
point out that what you experienced here is tty negotiation. Expect
encapsulates all processes in a pty so that you could run the telnet
program or anything else and have it work as one would want.
Yes, I found a doc about that (or had it pointed out to me).
I couldn’t figure out how to answer successfully, though. It seemed
trivial, but didn’t work for me.
Then I thought: Maybe I can get Net::Telnet to do it for me, and then
I’ll let the connection serve as the socket. That didn’t work for me
either.
For now, I’m just opening sockets onto my little customized server –
a text adventure that currently has only five rooms.
il Tue, 27 Apr 2004 14:24:08 +0900, Dan Janowski danj@3skel.com ha scritto::
I had to write an expect program (I’m a long time TCL programmer) the
other day and was thinking about how nice it would be to have
ExpectRuby. It is pretty great to run sub-processes in a pty.
You might find this interesting too. That was actually part of my
attempt to generalize IO for taking commands from multiple sources.
It is still not generalized enough (if FIFO checks) but work is still
in process. This code starts a thread listening on three different
sources. It currently only works on *nix but I hope to generalize the
FIFO listener to also work on windows:
# start servers to listen for commands on FIFO, TCP PORT, and STDIO
# FIXME make listen OS independant, use windows named pipe on windows
def listen(*listeners)
# if no arguments then listen on STDIN
listeners = ["STDIO"] if listeners.size == 0
#capitalize list of listeners
listeners.map!{ |l| l.upcase }
mutex = Mutex.new
#restart all threads if we aren't running the threads we think we are
#FIXME
#restart(@threads.keys) if @threads.values.sort != (Thread.list
[Thread.main]).sort
# TODO turn mkfifo into OS independant method that returns
# set an IO object for each listener to be called later
io = {}
io["FIFO"] = Proc.new {
File.open(FIFO_CONTROL, File::NONBLOCK | File::RDONLY ) }
io["STDIO"] = Proc.new { IO.new(1) }
io["TCP"] = Proc.new{ TCPServer.new('localhost', PORT).accept }
writeable=%w(STDIO TCP)
# thread to aggregate cmd_buffer and process it
···
Thread.new do
puts "Started Command Buffer processing thread" if $DEBUG
cmd=""
# run until we get a quit command
#
while ! cmd.match(/^(quit|q)$/i)
# join buffers and zero them out
mutex.synchronize do
VALID_LISTENERS.each do |vl|
@cmd_buffer["MAIN"] += @cmd_buffer[vl]
@cmd_buffer[vl] = []
end
end
# step through aggregate buffer, clean it, and run it
while @cmd_buffer["MAIN"].size > 0
puts "CMD BUFFER: " + @cmd_buffer["MAIN"].join(":") if $DEBUG
mutex.synchronize do
cmd=@cmd_buffer["MAIN"].shift
end
# next if string is characters or numbers
#FIXME (how do you internationalize untainting?)
next if cmd.match(/[^A-Za-z0-9 ]/)
cmd.untaint
run_cmd(cmd)
end
sleep 1
end
end
listeners.sort.each do |listener|
# next unless we have a handler for this type
next unless VALID_LISTENERS.include?(listener)
# do we already have a thread listening?
unless @threads[listener].respond_to?("alive") &&
@threads[listener].alive?
@threads[listener] = Thread.new do
cmd = ""
puts "Started #{listener} thread" if $DEBUG
# call the proc object that creates the io object
f = io[listener].call
while ! cmd.match(/^quit|q/i)
# Have to poll FIFO's and will get eof if nothing there
(sleep(1);next) if listener == "FIFO" and f.eof
# FIFO's are read only in server thread
(f.print "HA>";f.flush) if writeable.include?(listener)
cmd = f.readline.chomp
next if cmd.empty?
puts "Got command #{cmd} from #{listener}" if $DEBUG
(f.close; next) if cmd.match(/^(quit|q)$/i)
mutex.synchronize { @cmd_buffer[listener] << cmd }
end
end
end
end
# prompt user or give focus to STDIO thread if it exists
#
if @threads["STDIO"].nil?
puts "Listening on " + listeners.join(" and ")
puts "Enter quit to exit."
until gets.match(/^(quit|q)$/)
end
else
@threads["STDIO"].join
end
end
Yup. Looks like it (it is mostly there). Hadn’t caught that pty was
added in 1.8.
Hal, see if this thing works. Even if it needs some clean up, it is
pretty far along.
Dan
···
On Apr 27, 2004, at 02:39, gabriele renzi wrote:
il Tue, 27 Apr 2004 14:24:08 +0900, Dan Janowski danj@3skel.com ha
scritto::
I had to write an expect program (I’m a long time TCL programmer) the
other day and was thinking about how nice it would be to have
ExpectRuby. It is pretty great to run sub-processes in a pty.
Yup. Looks like it (it is mostly there). Hadn’t caught that pty was
added in 1.8.
Hal, see if this thing works. Even if it needs some clean up, it is
pretty far along.
Any suggestions you’d have would be greatly appreciated. I’ve added
some things that made it work better for me, but unfortunately Forces
Beyond My Control™ forced me to switch first to Python, then to
Python on Windows and therefore PTY objects weren’t really an option.
Instead, I had to use PySerial, and roll my own ‘expect’ function around
that.