Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
Diff: libs/Network/uip/telnetd/telnetd.cpp
- Revision:
- 3:f151d08d335c
- Parent:
- 2:1df0b61d3b5a
--- a/libs/Network/uip/telnetd/telnetd.cpp Fri Feb 28 18:52:52 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,413 +0,0 @@ -/* - * Copyright (c) 2003, Adam Dunkels. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This file is part of the uIP TCP/IP stack - * - * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ - * - */ - -#include "uip.h" -#include "telnetd.h" -#include "shell.h" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#define ISO_nl 0x0a -#define ISO_cr 0x0d - -#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 - -#define TELNET_IAC 255 -#define TELNET_WILL 251 -#define TELNET_WONT 252 -#define TELNET_DO 253 -#define TELNET_DONT 254 - -#define TELNET_LINEMODE 0x22 -#define TELNET_GA 0x03 -#define TELNET_X_PROMPT 0x55 - -//#define DEBUG_PRINTF(...) -#define DEBUG_PRINTF printf - -static char *alloc_line(int size) -{ - return (char *)malloc(size); -} - -static void dealloc_line(char *line) -{ - free(line); -} - -void Telnetd::close() -{ - state = STATE_CLOSE; -} - -int Telnetd::sendline(char *line) -{ - int i; - for (i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - if (lines[i] == NULL) { - lines[i] = line; - return i; - } - } - if (i == TELNETD_CONF_NUMLINES) { - dealloc_line(line); - } - return TELNETD_CONF_NUMLINES; -} - -void Telnetd::output_prompt(const char *str) -{ - if(prompt) output(str); -} - -int Telnetd::output(const char *str) -{ - if(state == STATE_CLOSE) return -1; - - unsigned chunk = 256; // small chunk size so we don't allocate huge blocks, and must be less than mss - unsigned len = strlen(str); - char *line; - if (len < chunk) { - // can be sent in one tcp buffer - line = alloc_line(len + 1); - if (line != NULL) { - strcpy(line, str); - return sendline(line); - }else{ - // out of memory treat like full - return TELNETD_CONF_NUMLINES; - } - } else { - // need to split line over multiple send lines - int size = chunk; // size to copy - int off = 0; - int n= 0; - while (len >= chunk) { - line = alloc_line(chunk + 1); - if (line != NULL) { - memcpy(line, str + off, size); - line[size] = 0; - n= sendline(line); - len -= size; - off += size; - }else{ - // out of memory treat like full - return TELNETD_CONF_NUMLINES; - } - } - if (len > 0) { - // send rest - line = alloc_line(len + 1); - if (line != NULL) { - strcpy(line, str + off); - n= sendline(line); - }else{ - // out of memory treat like full - return TELNETD_CONF_NUMLINES; - } - } - return n; - } -} - -// check if we can queue or if queue is full -int Telnetd::can_output() -{ - if(state == STATE_CLOSE) return -1; - - int i; - int cnt = 0; - for (i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - if (lines[i] == NULL) cnt++; - } - return cnt < 4 ? 0 : 1; -} - -void Telnetd::acked(void) -{ - while (numsent > 0) { - dealloc_line(lines[0]); - for (int i = 1; i < TELNETD_CONF_NUMLINES; ++i) { - lines[i - 1] = lines[i]; - } - lines[TELNETD_CONF_NUMLINES - 1] = NULL; - --numsent; - } -} - -void Telnetd::senddata(void) -{ - // NOTE this sends as many lines as it can fit in one tcp frame - // we need to keep the lines under the size of the tcp frame - char *bufptr, *lineptr; - int buflen, linelen; - - bufptr = (char *)uip_appdata; - buflen = 0; - for (numsent = 0; numsent < TELNETD_CONF_NUMLINES && lines[numsent] != NULL ; ++numsent) { - lineptr = lines[numsent]; - linelen = strlen(lineptr); - if (buflen + linelen < uip_mss()) { - memcpy(bufptr, lineptr, linelen); - bufptr += linelen; - buflen += linelen; - } else { - break; - } - } - uip_send(uip_appdata, buflen); -} - -void Telnetd::get_char(u8_t c) -{ - if (c == ISO_cr) { - return; - } - - buf[(int)bufptr] = c; - if (buf[(int)bufptr] == ISO_nl || bufptr == sizeof(buf) - 1) { - if (bufptr > 0) { - buf[(int)bufptr] = 0; - } - shell->input(buf); - bufptr = 0; - - } else { - ++bufptr; - } -} - -// static void sendopt(u8_t option, u8_t value) -// { -// char *line; -// line = alloc_line(4); -// if (line != NULL) { -// line[0] = TELNET_IAC; -// line[1] = option; -// line[2] = value; -// line[3] = 0; -// sendline(line); -// } -// } - -void Telnetd::newdata(void) -{ - u16_t len; - u8_t c; - char *dataptr; - - len = uip_datalen(); - dataptr = (char *)uip_appdata; - - while (len > 0 && bufptr < sizeof(buf)) { - c = *dataptr; - ++dataptr; - --len; - switch (state) { - case STATE_IAC: - if (c == TELNET_IAC) { - get_char(c); - state = STATE_NORMAL; - } else { - switch (c) { - case TELNET_WILL: - state = STATE_WILL; - break; - case TELNET_WONT: - state = STATE_WONT; - break; - case TELNET_DO: - state = STATE_DO; - break; - case TELNET_DONT: - state = STATE_DONT; - break; - default: - state = STATE_NORMAL; - break; - } - } - break; - case STATE_WILL: - if (c == TELNET_LINEMODE) { - //sendopt(TELNET_DO, c); - } - state = STATE_NORMAL; - break; - - case STATE_WONT: - /* Reply with a DONT */ - //sendopt(TELNET_DONT, c); - state = STATE_NORMAL; - break; - case STATE_DO: - if (c == TELNET_X_PROMPT) { - prompt= true; - }else if (c == TELNET_GA) { - // enable prompt if telnet client running - prompt= true; - shell->setConsole(); // tell shell we are a console, as this is sent be telnet clients - }else{ - /* Reply with a WONT */ - //sendopt(TELNET_WONT, c); - } - state = STATE_NORMAL; - break; - case STATE_DONT: - if (c == TELNET_X_PROMPT) { - prompt= false; - }else{ - /* Reply with a WONT */ - //sendopt(TELNET_WONT, c); - } - state = STATE_NORMAL; - break; - case STATE_NORMAL: - if (c == TELNET_IAC) { - state = STATE_IAC; - } else { - get_char(c); - } - break; - } - } - - // if the command queue is getting too big we stop TCP - if(shell->queue_size() > 20) { - DEBUG_PRINTF("Telnet: stopped: %d\n", shell->queue_size()); - uip_stop(); - } -} - -void Telnetd::poll() -{ - if(first_time) { - first_time= false; - shell->start(); - senddata(); - } -} - -Telnetd::Telnetd() -{ - DEBUG_PRINTF("Telnetd: ctor %p\n", this); - for (int i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - lines[i] = NULL; - } - - first_time= true; - bufptr = 0; - state = STATE_NORMAL; - prompt= false; - shell= new Shell(this); -} - -Telnetd::~Telnetd() -{ - DEBUG_PRINTF("Telnetd: dtor %p\n", this); - for (int i = 0; i < TELNETD_CONF_NUMLINES; ++i) { - if (lines[i] != NULL) dealloc_line(lines[i]); - } - delete shell; -} - -// static -void Telnetd::appcall(void) -{ - Telnetd *instance= reinterpret_cast<Telnetd *>(uip_conn->appstate); - - if (uip_connected()) { - // create a new telnet class instance - instance= new Telnetd; - DEBUG_PRINTF("Telnetd new instance: %p\n", instance); - uip_conn->appstate= instance; // and store it in the appstate of the connection - instance->rport= uip_conn->rport; - } - - if (uip_closed() || uip_aborted() || uip_timedout()) { - DEBUG_PRINTF("Telnetd: closed: %p\n", instance); - if(instance != NULL) { - delete instance; - uip_conn->appstate= NULL; - } - return; - } - - // sanity check - if(instance == NULL || instance->rport != uip_conn->rport) { - DEBUG_PRINTF("Telnetd: ERROR Null instance or rport is wrong: %p - %u, %d\n", instance, HTONS(uip_conn->rport), uip_flags); - uip_abort(); - return; - } - - if (instance->state == STATE_CLOSE) { - uip_close(); - } - - - if (uip_acked()) { - instance->acked(); - } - - if (uip_newdata()) { - instance->newdata(); - } - - if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll()) { - instance->senddata(); - } - - if(uip_poll() && uip_stopped(uip_conn) && instance->shell->queue_size() < 5) { - DEBUG_PRINTF("restarted %d - %p\n", instance->shell->queue_size(), instance); - uip_restart(); - } - - if(uip_poll()) { - instance->poll(); - } -} - -// static -void Telnetd::init(void) -{ - uip_listen(HTONS(23)); -}