uIP 1.0
|
/* * Copyright (c) 2003, Adam Dunkels. * Все права зарезервированы. * * Повторное распространение, использование в исходном и двоичном виде, * с модификацией или без - разрешается, если выполняются следующие * условия: * 1. Распространение исходного кода должно сохранить вышеуказанную пометку * копирайта, этот список условий и следующую правовую оговорку. * 2. Распространение исходного кода должно сохранить вышеуказанную пометку * копирайта, этот список условий и следующую правовую оговорку в * документации и/или других материалах, которые будут предоставлены * вместе с распространяемыми материалами. * 3. Имя автора не может использоваться, чтобы подтвердить или продвинуть * продукты, написанные с использованием этого программного обеспечения * без специального на то разрешения. * * ЭТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ АВТОРОМ ``КАК ЕСТЬ'', БЕЗ * КАКОЙ-ЛИБО ЛЮБОЙ РАСШИРЕННОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ГАРАНТИИ, ВКЛЮЧАЯ, * НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ГАРАНТИИ ВЫСОКОГО СПРОСА И ПРИГОДНОСТИ * ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. АВТОР НИ ПРИ КАКИХ УСЛОВИЯХ НЕ ОТВЕТСТВЕНЕН * ЗА ЛЮБЫЕ УБЫТКИ - ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОБРАЗЦОВЫЕ * ИЛИ ПОСЛЕДОВАТЕЛЬНЫЕ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ТРЕБОВАНИЯ * ЗАМЕНЫ ТОВАРА ИЛИ СЕРВИСА; ПОТЕРИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ВЫГОДЫ; * ИЛИ ПРЕКРАЩЕНИЕ БИЗНЕСА), ОДНАКО ВЫЗВАННЫЕ ПО ЛЮБОЙ ТЕОРИИ ОТВЕТСТВЕННОСТИ, * ЛИБО В КОНТРАКТЕ, ПРЯМОЙ ОТВЕТСТВЕННОСТИ, ЛИБО В НАРУШЕНИИ ЗАКОННЫХ ПРАВ * (ВКЛЮЧАЯ ТАК ИЛИ ИНАЧЕ НЕБРЕЖНОСТЬ), ВОЗНИКАЮЩИЕ ВСЕГДА ИЗ ИСПОЛЬЗОВАНИЯ * ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ БЫЛО ПРЕДУПРЕЖДЕНИЕ О ВОЗМОЖНОСТИ * ТАКОГО ПОВРЕЖДЕНИЯ. * * Этот файл является частью стека uIP TCP/IP. * * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ * */ #include "uip.h" #include "telnetd.h" #include "memb.h" #include "shell.h" #include <string.h> #define ISO_nl 0x0a #define ISO_cr 0x0d struct telnetd_line { char line[TELNETD_CONF_LINELEN]; }; MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); #define STATE_NORMAL 0 #define STATE_IAC 1 #define STATE_WILL 2 #define STATE_WONT 3 #define STATE_DO 4 #define STATE_DONT 5 #define STATE_CLOSE 6 static struct telnetd_state s; #define TELNET_IAC 255 #define TELNET_WILL 251 #define TELNET_WONT 252 #define TELNET_DO 253 #define TELNET_DONT 254 /*---------------------------------------------------------------------------*/ static char * alloc_line(void) { return memb_alloc(&linemem); } /*---------------------------------------------------------------------------*/ static void dealloc_line(char *line) { memb_free(&linemem, line); } /*---------------------------------------------------------------------------*/ void shell_quit(char *str) { s.state = STATE_CLOSE; } /*---------------------------------------------------------------------------*/ static void sendline(char *line) { static unsigned int i; for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { if(s.lines[i] == NULL) { s.lines[i] = line; break; } } if(i == TELNETD_CONF_NUMLINES) { dealloc_line(line); } } /*---------------------------------------------------------------------------*/ void shell_prompt(char *str) { char *line; line = alloc_line(); if(line != NULL) { strncpy(line, str, TELNETD_CONF_LINELEN); /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ sendline(line); } } /*---------------------------------------------------------------------------*/ void shell_output(char *str1, char *str2) { static unsigned len; char *line; line = alloc_line(); if(line != NULL) { len = strlen(str1); strncpy(line, str1, TELNETD_CONF_LINELEN); if(len < TELNETD_CONF_LINELEN) { strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); } len = strlen(line); if(len < TELNETD_CONF_LINELEN - 2) { line[len] = ISO_cr; line[len+1] = ISO_nl; line[len+2] = 0; } /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ sendline(line); } } /*---------------------------------------------------------------------------*/ void telnetd_init(void) { uip_listen(HTONS(23)); memb_init(&linemem); shell_init(); } /*---------------------------------------------------------------------------*/ static void acked(void) { static unsigned int i; while(s.numsent > 0) { dealloc_line(s.lines[0]); for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { s.lines[i - 1] = s.lines[i]; } s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; --s.numsent; } } /*---------------------------------------------------------------------------*/ static void senddata(void) { static char *bufptr, *lineptr; static int buflen, linelen; bufptr = uip_appdata; buflen = 0; for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && s.lines[s.numsent] != NULL ; ++s.numsent) { lineptr = s.lines[s.numsent]; linelen = strlen(lineptr); if(linelen > TELNETD_CONF_LINELEN) { linelen = TELNETD_CONF_LINELEN; } if(buflen + linelen < uip_mss()) { memcpy(bufptr, lineptr, linelen); bufptr += linelen; buflen += linelen; } else { break; } } uip_send(uip_appdata, buflen); } /*---------------------------------------------------------------------------*/ static void closed(void) { static unsigned int i; for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { if(s.lines[i] != NULL) { dealloc_line(s.lines[i]); } } } /*---------------------------------------------------------------------------*/ static void get_char(u8_t c) { if(c == ISO_cr) { return; } s.buf[(int)s.bufptr] = c; if(s.buf[(int)s.bufptr] == ISO_nl || s.bufptr == sizeof(s.buf) - 1) { if(s.bufptr > 0) { s.buf[(int)s.bufptr] = 0; /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ } shell_input(s.buf); s.bufptr = 0; } else { ++s.bufptr; } } /*---------------------------------------------------------------------------*/ static void sendopt(u8_t option, u8_t value) { char *line; line = alloc_line(); if(line != NULL) { line[0] = TELNET_IAC; line[1] = option; line[2] = value; line[3] = 0; sendline(line); } } /*---------------------------------------------------------------------------*/ static void newdata(void) { u16_t len; u8_t c; char *dataptr; len = uip_datalen(); dataptr = (char *)uip_appdata; while(len > 0 && s.bufptr < sizeof(s.buf)) { c = *dataptr; ++dataptr; --len; switch(s.state) { case STATE_IAC: if(c == TELNET_IAC) { get_char(c); s.state = STATE_NORMAL; } else { switch(c) { case TELNET_WILL: s.state = STATE_WILL; break; case TELNET_WONT: s.state = STATE_WONT; break; case TELNET_DO: s.state = STATE_DO; break; case TELNET_DONT: s.state = STATE_DONT; break; default: s.state = STATE_NORMAL; break; } } break; case STATE_WILL: /* Ответ с DONT */ sendopt(TELNET_DONT, c); s.state = STATE_NORMAL; break; case STATE_WONT: /* Ответ с DONT */ sendopt(TELNET_DONT, c); s.state = STATE_NORMAL; break; case STATE_DO: /* Ответ с WONT */ sendopt(TELNET_WONT, c); s.state = STATE_NORMAL; break; case STATE_DONT: /* Ответ с WONT */ sendopt(TELNET_WONT, c); s.state = STATE_NORMAL; break; case STATE_NORMAL: if(c == TELNET_IAC) { s.state = STATE_IAC; } else { get_char(c); } break; } } } /*---------------------------------------------------------------------------*/ void telnetd_appcall(void) { static unsigned int i; if(uip_connected()) { /* tcp_markconn(uip_conn, &s);*/ for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { s.lines[i] = NULL; } s.bufptr = 0; s.state = STATE_NORMAL; shell_start(); } if(s.state == STATE_CLOSE) { s.state = STATE_NORMAL; uip_close(); return; } if(uip_closed() || uip_aborted() || uip_timedout()) { closed(); } if(uip_acked()) { acked(); } if(uip_newdata()) { newdata(); } if(uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll()) { senddata(); } } /*---------------------------------------------------------------------------*/