Can I write a telnet server?

I mean, I know it can be done, but … wow.

I’m writing a MUD from scratch. I started out by writing a client (really more of a middleman between the user’s client and the server) and server, so that when one connects to my computer, the “middleman” automatically starts, and it handles all the screen drawing, using the ncurses library. That is, it gets data one character at a time, refreshes the screen, sends it to the server when the user hits enter, and accepts data from the server, and draws it on the screen. This is not what I want.

What I want is to let the user’s telnet client handle all the grunt work, and let the server just worry about sending and receiving messages (and, of course, doing the behind-scenes MUD stuff). It seems like I’ll have to rewrite the server to accept telnet connections. No problem, I thought. Went to groups.google.com and looked around for a while. People kept saying, “Look at the RFC.” So I did.

Oh my god. Looking at it was about all I could do. Whatever language it’s in, my brain couldn’t even see. My eyes kept bouncing off the page.

My questions for you, erudite and generous dopers, are:

Is there another way to solve my problem? Say, by accepting telnet logins via the already-installed telnet daemon (this is RedHat 9, if it makes a difference) and (writing and) running a program that will just pass messages back and forth between the telnet connection and my server? Similar to the setup I have now, but removing any screen-writing functions from the “middleman” program.

If I must configure the server to be directly connected to a telnet connection, … uh, how? Any references to which you can point me? I’m not even sure what to search for. I guess the source for a telnet server, or maybe another MUD server.

I’m familiar, though not exceedingly proficient with, socket programming, which is what I was using for client/server communication up to this point. If you’d like to email me directly, that would certainly be welcome.

Uh, that’s about it, I guess. Thanks for any help you can give.

Umm, it’s been awhile, but let me take a stab at it. How about have a .login script that runs your program, then your program just executes a “get”() function loop waiting for user input, then writes back via “put”()? Will that work? Not sure.

You could have people login to your machine via telnet and then have your program set to run in place of a shell. When your program exits the telnet session will close automatically.

Cool. Can I ask about the MUD? I used to play those all the time. I liked LPMud the best.

friedo, that’s what I’ve got going on now. Thanks for the input, though.

ccwaterback, like friedo said, it’s a shell running, which I prefer to just starting it via .login or .bashrc, because I’m not too good with security, and I’m paranoid that someone will break out into a shell and wreak havoc. I think I tried the get()/put() solution initially, but didn’t have much luck. I just tried again, modifying the client slightly, and, while it didn’t do exactly what I wanted, it did kind of work, so I’m going to investigate that angle. I don’t know what problem I was having the first time around, but thanks for bringing it up - maybe that’s all I need. I sure hope so.

Stephanos - right now it’s mostly conceptual, but we’ve got a lot of really bright, really creative people working on it, and I’m very pleased with the ideas we have so far. If you want, feel free to email me, I’ll give you an overview.

Check out www.dillfrog.com

Rock: Crashed Plane is a homegrown MUD (built from scratch even) with 7-8 years of experience behind it. Check out the telnet client he uses, I believe its freeware and it works about 90% as well as you could ever expect a telnet client to work.

The guy is pretty cool, if you send him an e-mail he will reply and I attest to his guruness :slight_smile:

I don’t totally understand your need, but I’ve written a fair number of servers. I suggest you check out “xinetd” and “tcp wrappers”. here’s a sample http server written as a shell script to get you started:

in /etc/xinetd.d, create a file called myhttpd, containing

then set yourself up an index.html in /usr/local/var/myhttpd. (make sure it’s readable, for this example, set it as 666)

Then, here’s your daemon. It’s called /usr/local/sbin/myhttpd:



#!/bin/sh
DOCROOT=/usr/local/var/myhttp
 
 print_header() {
    echo -e "HTTP/1.0 200 OK\r"
    echo -e "Server: myhttp/0.1\r"    
    echo -e "Date: `date`\r"
}
 
print_error() {
    echo -e "HTTP/1.0 $1 $2\r"
    echo -e "Content-type: text/html\r"
    echo -e "Connection: close\r"
    echo -e "Date: `date`\r"
    echo -e "\r"
    echo -e "$2\r"
    exit 1
}
 
do_get() {
    local DIR
    local NURL
    local LEN
    
    if [ ! -d $DOCROOT ]; then
        print_error 404 "No such file or directory"
    fi
    
    if [ -z "${URL##*/}" ]; then
        URL=${URL}index.html
    fi
    
    DIR="`dirname $URL`"
    if [ ! -d ${DOCROOT}/${DIR} ]; then
        print_error 404 "Directory not found"
    else
        cd ${DOCROOT}/${DIR}
        NURL="`pwd`/`basename ${URL}`"
        URL=${NURL}
    fi
    
    if [ ! -f ${URL} ]; then
        print_error 404 "Document not found"
    fi
    
    print_header

    echo -e "Content-type: text/html"

    LEN="`ls -l ${URL} | tr -s ' ' | cut -d ' ' -f 5`"
    echo -e "Content-length: $LEN
\r"
    cat ${URL}
    sleep 3
}
 
read_request() {
    local JUNK
    local COMMAND
 
    read REQUEST
    read JUNK
    
    REQUEST="`echo ${REQUEST} | tr -s [:blank:]`"
    COMMAND="`echo ${REQUEST} | cut -d ' ' -f 1`"
    URL="`echo ${REQUEST} | cut -d ' ' -f 2`"
    PROTOCOL="`echo ${REQUEST} | cut -d ' ' -f 3`"
 
    case $COMMAND in
        HEAD)
            print_error 501 "Not implemented"
            ;;
        GET)
            do_get
            ;;
        *)
            print_error 501 "Not Implemented"
            ;;
    esac
}
 
read_request
 
exit 0


So all you worry about is reading input and writing output. TCP wrappers takes care of all the tcp handshaking, and xinetd takes care of some security issues. the reading and writing can be done by anything, such as c, perl, or in this case bash.

Of course, if you actually implement this, you’ll want to make sure that iptables/ipfilter has your chosen port (in this case “www” above which is 80) is open. And if you already have something answering to 80 (like apache), you’ll want to disable it. And after you create the files above, you’ll need to restart xinetd ("/sbin/service xinetd restart").

Wow Bill H. very elegant indeed. Might be a bit hard to debug though. But, a standing ovation on the approach.

Bill, the problem is that the telnet protocol demands a great deal of negotiation and handshaking before the connection is made. I appreciate the code, but, if I understand correctly, it’s not really applicable to a telnet server, except on a very basic level. I’m pursuing the “write your own shell” avenue, and running into the problem I had the first time around, of reading input without blocking. I think that’s what got me using the ncurses library in the first place. I’m going to try using ncurses again, but only the getch() function, which can be set non-blocking.

typo mna, when you said “before the connection is made,” did you mean the tcp connection? If so, the example I gave takes care of all that. All you need to do is wait for a character (or characters) to come in, then respond apropriately.

Please define “the ‘write your own shell’ avenue.” Do you mean that you want a shell script at the back end that can do all the things a shell can with a telnet connection to the rest of the world? If so, that’s what I defined above. The script above accepts HTTP commands like “GET /silly/directory/picture.jpg”, and pushes out a file in response. But it could just as easily accept a command “pick up wand”, make the necessary back end calculations and spit out a proper response.

I should say that I have no idea what a “MUD” is; I only know that it relates to gaming. So, I’m not sure if you’re looking for a way for text to be entered, and text responses sent, or mouse input to be received and 3d image updates sent back, or what. If you can give me a bit more background on what you’re looking to do, perhaps I can help better.