[En-Nut-Discussion] Telnet server with echo and cursor key support

Tomohiro HARAIKAWA hal at cs.inf.shizuoka.ac.jp
Sun Jul 6 02:04:32 CEST 2003


Hi, all,

  As you know, a telnet client (more accurately, a VT100 emulator like 
\windows\system32\telnet.exe or Tera Term Pro) and a server negotiates 
via an NVT protocol.  A server should support NVT ECHO for the correct 
handling of echo-back.  Otherwise, a character is echoed back twice if 
a client chooses a local echo.

  The following code fragment is to support NVT ECHO and automatically 
determines whether the server should echo or not.

  The code can be reused freely.  I'm very sorry about my puzzly coded 
state machine.  I never supposed the code to be shown to others. :-)

---
Tomohiro Haraikawa
Faculty of Information, Shizuoka University
E-mail: hal at cs.inf.shizuoka.ac.jp


#define NVT_SE          240
#define NVT_SB          250
#define NVT_WILL        251
#define NVT_WONT        252
#define NVT_DO          253
#define NVT_DONT        254
#define NVT_IAC         255
#define NVT_OPT_ECHO      1
#define NVT_OPT_SGA       3

static int nvt_session(TCPSOCKET *sock, u_char req, u_char opt, u_char accept)
{
    u_char nvt[3] = { NVT_IAC, 0 };
    switch (req) {
    case NVT_WILL:
        nvt[1] = accept ? NVT_DO : NVT_DONT;
        break;
    case NVT_WONT:
        nvt[1] = NVT_DONT;
        break;
    case NVT_DO:
        nvt[1] = accept ? NVT_WILL : NVT_WONT;
        break;
    case NVT_DONT:
        nvt[1] = NVT_WONT;
    }
    if (!nvt[1]) return -1;
    nvt[2] = opt;
    return NutTcpSend(sock, nvt, sizeof(nvt));
}

static void telnet_session(TCPSOCKET *sock)
{
    u_char buff[128], ch = '\0', echo = 0, nvt = 0, nvt_sub = NVT_SE;
    const u_char lf = '\n';
    int eol, len;

    do {
        len = 0;
        do {
            if ((eol = NutTcpReceive(sock, buff + len, 1)) >= 0) {
                if (nvt == NVT_IAC) {
                    nvt = 0;
                    switch (buff[len]) {
                    case NVT_IAC:
                        break;
                    case NVT_SB:
                    case NVT_SE:
                        nvt_sub = buff[len];
                        continue;
                    case NVT_WILL:
                    case NVT_WONT:
                    case NVT_DO:
                    case NVT_DONT:
                        nvt = buff[len];
                    default:
                        continue;
                    }
                } else if (nvt_sub == NVT_SB) {
                    nvt = (buff[len] == NVT_IAC) ? NVT_IAC : 0;
                    continue;
                } else if (NVT_WILL <= nvt && nvt <= NVT_DONT) {
                    switch (buff[len]) {
                    case NVT_OPT_ECHO:
                        echo = (nvt == NVT_DO || nvt == NVT_WONT);
                        nvt_session(sock, nvt, buff[len], 1);
                        break;
                    case NVT_OPT_SGA:
                        if (nvt == NVT_WILL || nvt == NVT_DO) {
                            nvt_session(sock, nvt, buff[len], 1);
                        } else {
                            nvt_session(sock, nvt, buff[len], 0);
                        }
                    }
                    nvt = 0;
                    continue;
                } else if (buff[len] == NVT_IAC) {
                    nvt = NVT_IAC;
                    continue;
                }
                if (echo) {
                    if (buff[len] != '\n') NutTcpSend(sock, buff + len, 1);
                    if (buff[len] == '\r') NutTcpSend(sock, &lf, 1);
                }
                switch (buff[len]) {
                case 0x08:
                    if (len >= 1) len--;
                case '\0':
                    continue;
                case '\n':
                    if (ch == '\r') {
                        ch = buff[len];
                        continue;
                    }
                    /* fall through */
                case '\r':
                    eol = 0;
                    /* fall through */
                default:
                    ch = buff[len];
                }
            }
            if (++len >= (int)sizeof(buff) - 1) break;
        } while (eol > 0);
    buff[len] = '\0';

    /*
     * now buff contains a command line */
     */

    } while (eol >= 0);
}





More information about the En-Nut-Discussion mailing list