Telnet Server in Ruby

Does anyone know of a Telnet Server written purely in Ruby? It doesn’t
have to be fully featured. I just need a remote shell for control of an
application that I am working on. Telnet is the preferred method since
the users of the system are used to using Telnet for network application
control and allows simple scripting via a socket.

I thought about writing my own using GServer and IO.popen, but before
embark on that I wanted to avoid re-inventing the wheel.

Thanks in advance.

Dale M.

On Jul 31, 2006, at 9:27 PM, Dale M. wrote:

I thought about writing my own using GServer and IO.popen, but before
embark on that I wanted to avoid re-inventing the wheel.

It’s super easy to get something going with GServer, but my new
favorite is actually EventMachine. I just built a server application
with that library last week and it really rocks. Definitely look it
over.

If all you need is bare bones Telnet handling you can use something
like this:

 def parse_telnet(data)                # minimal Telnet
   data.gsub!(/([^\015])\012/, "\\1")  # ignore bare LFs
   data.gsub!(/\015\0/, "")            # ignore bare CRs
   data.gsub!(/\0/, "")                # ignore bare NULs

   while data.index("\377")            # parse Telnet codes
     if data.sub!(/(^|[^\377])\377[\375\376](.)/, "\\1")
       # answer DOs and DON'Ts with WON'Ts
       send_data("\377\374#{$2}")
     elsif data.sub!(/(^|[^\377])\377[\373\374](.)/, "\\1")
       # answer WILLs and WON'Ts with DON'Ts
       send_data("\377\376#{$2}")
     elsif data.sub!(/(^|[^\377])\377\366/, "\\1")
       # answer "Are You There" codes
       send_data("Still here, yes.")
     elsif data.sub!(/(^|[^\377])\377\364/, "\\1")
       # do nothing - ignore IP Telnet codes
     elsif data.sub!(/(^|[^\377])\377[^\377]/, "\\1")
       # do nothing - ignore other Telnet codes
     elsif data.sub!(/\377\377/, "\377")
       # do nothing - handle escapes
     end
   end

   data
 end

Maybe you could expand that to meet your needs.

Hope that helps.

James Edward G. II

From: “Dale M.” [email protected]

Does anyone know of a Telnet Server written purely in Ruby? It doesn’t
have to be fully featured. I just need a remote shell for control of an
application that I am working on. Telnet is the preferred method since
the users of the system are used to using Telnet for network application
control and allows simple scripting via a socket.

I thought about writing my own using GServer and IO.popen, but before
embark on that I wanted to avoid re-inventing the wheel.

Hi,

For what it’s worth… I have some ANSI/VT100 telnet libraries that
support
partitioning the display into horizontal scrolling regions, and some
reasonably
full featured line-editing handling insert, delete, scrolling long
lines, command
history, scrollback buffers with PgUp/PgDn, etc…

Part of this project:
http://rubyforge.org/cgi-bin/viewvc.cgi/dorkbuster/dbcore/?root=dorkbuster

The relevant files would be:
ansi.rb
ansi-term.rb
term-keys.rb
windowed-term.rb
line-edit.rb

On the plus side, they have unit tests. And on the plus side, each
module
is relatively loosely coupled… On the downside, the lowest level
module,
buffered-io.rb, uses kind of a weird approach I developed back under
ruby 1.6.8 when nonblocking I/O wasn’t well-supported on win32 ruby,
and so buffered-io was an experiment that technically works (it runs
over
thirty servers now, for years with no problems); but it’s more
complicated than it needs to be.

These days, instead of buffered-io, I’d have likely started with
something
something like the EventMachine library JEGII mentioned in his reply
on this thread.

But anyway, that said, ansi-term only relies on a few methods of
the buffered-io object passed into it, mainly #send_nonblock,
#recv_nonblock, and #recv_ready? … hmm, also #eof, #peeraddr,
#wait_recv_ready, #flush … It might not be too hard to adapt.

Well … anyway, maybe the code might be of some use, even if
it could take some massaging to fit into a different I/O model.

The license for the source files mentioned here is LGPL preferably,
or Ruby’s license if LGPL won’t work for you.

Hope this helps,

Bill

To both JEGII and Bill K.:

I’d really like to see a telnet server capability built into and shipped
with EM. Although there hasn’t been a release lately (my fault, just
gotta do it), if you look into the SVN you’ll see where things are
going. We’ve added thread-pools (for handling locally-blocking things
like database calls) and also a “Deferred” object that acts just like
the one in Twisted (you add arbitrary callbacks and errbacks to it). And
there is some structure in the source tree for adding specific
network-protocol handlers. That’s where a telnet server would fit in.
Another possibility, possibly better, is to treat EM as a platform, and
then people can ship servers as separate packages, like RoR.

JEGII: may I use your code posted above to make a first attempt? I’ll
come back to you with annoying questions if I have trouble, of course
;-).

Bill: ditto with your windowing libraries. EM is licensed under either
Ruby terms or LGPL so you would need to allow a relaxation of terms in
order for your stuff to be included. If that’s not poss, then maybe it
could be an outboard library.

Thoughts from anyone?

On Aug 1, 2006, at 7:01 AM, Francis C. wrote:

JEGII: may I use your code posted above to make a first attempt? I’ll
come back to you with annoying questions if I have trouble, of course
;-).

You can use whatever you like. Bill’s stuff is much farther along
though!

James Edward G. II

On Tuesday, August 01, 2006, at 12:26 PM, James Edward G. II wrote:

On Jul 31, 2006, at 9:27 PM, Dale M. wrote:

I thought about writing my own using GServer and IO.popen, but before
embark on that I wanted to avoid re-inventing the wheel.

It’s super easy to get something going with GServer, but my new
favorite is actually EventMachine. I just built a server
application with that library last week and it really rocks.
Definitely look it over.

I will. It sounds like EventMachine maybe the best way to proceed.

Thanks,
Dale M.

On Tuesday, August 01, 2006, at 2:11 PM, Bill K. wrote:

embark on that I wanted to avoid re-inventing the wheel.

Hi,

For what it’s worth… I have some ANSI/VT100 telnet libraries that support
partitioning the display into horizontal scrolling regions, and some
reasonably
full featured line-editing handling insert, delete, scrolling long
lines, command
history, scrollback buffers with PgUp/PgDn, etc…

Fantastic. This is beyond my original intent, but since this is
available, I will look at utilizing what I can.

Thank you,
Dale M.

Dale M. wrote:

I will. It sounds like EventMachine maybe the best way to proceed.

If you go for it and need support, send me email (here or private).

Bill K. wrote:

From: “Francis C.” [email protected]

Bill: ditto with your windowing libraries. EM is licensed under either
Ruby terms or LGPL so you would need to allow a relaxation of terms in
order for your stuff to be included.

No problem!

As of now, consider them “Ruby or LGPL”.

I’ll make a pass through the source and add some sort of header at
the top of the files stating this.

Regards,

Bill

Thanks Bill. I took a look through your code and it’s neat,
there’s a lot of stuff there. When I get a moment I’ll take a pass at
figuring out how to make it run under EM. Seems so far like I can get
away primarily with changes in ansi-term.rb for a start, then
windowed-term.rb later.

Can you give me a hello-world program that runs your code as a telnet
server, that can (for example) serve a remote login? I started figuring
it out from your test cases, but I figure you can rattle it off the top
of your head.

From: “Francis C.” [email protected]

Bill: ditto with your windowing libraries. EM is licensed under either
Ruby terms or LGPL so you would need to allow a relaxation of terms in
order for your stuff to be included.

No problem!

As of now, consider them “Ruby or LGPL”.

I’ll make a pass through the source and add some sort of header at
the top of the files stating this.

Regards,

Bill

From: “Francis C.” [email protected]

Can you give me a hello-world program that runs your code as a telnet
server, that can (for example) serve a remote login? I started figuring
it out from your test cases, but I figure you can rattle it off the top
of your head.

I’ve added a windowed-term-example.rb to the project:

http://rubyforge.org/cgi-bin/viewvc.cgi/dorkbuster/dbcore/windowed-term-example.rb?root=dorkbuster&view=co

It accepts clients, and partitions the client’s window into three
regions.
Lines of text can be entered into the bottom region, with line editing
and
command history, and the data entered is echoed to all clients in the
middle region. PgUp/PgDn should scroll through that data in the middle
region as it accumulates. The top region gets a timestamp printed to it
every second or so.

NOTE: You’ll need to put your telnet into character mode (mode ch)
before connecting. I know there must be a telnet escape sequence
I could send from the server to do that automatically, but, I didn’t
know
what it was.

Hope this helps,

Bill