apps/telnetd/telnetd.c

00001 /*
00002  * Copyright (c) 2003, Adam Dunkels.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. The name of the author may not be used to endorse or promote
00014  *    products derived from this software without specific prior
00015  *    written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00018  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00021  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00023  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00025  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00026  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  * This file is part of the uIP TCP/IP stack
00030  *
00031  * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $
00032  *
00033  */
00034 
00035 #include "uip.h"
00036 #include "telnetd.h"
00037 #include "memb.h"
00038 #include "shell.h"
00039 
00040 #include <string.h>
00041 
00042 #define ISO_nl       0x0a
00043 #define ISO_cr       0x0d
00044 
00045 struct telnetd_line {
00046   char line[TELNETD_CONF_LINELEN];
00047 };
00048 MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES);
00049 
00050 #define STATE_NORMAL 0
00051 #define STATE_IAC    1
00052 #define STATE_WILL   2
00053 #define STATE_WONT   3
00054 #define STATE_DO     4
00055 #define STATE_DONT   5
00056 #define STATE_CLOSE  6
00057 
00058 static struct telnetd_state s;
00059 
00060 #define TELNET_IAC   255
00061 #define TELNET_WILL  251
00062 #define TELNET_WONT  252
00063 #define TELNET_DO    253
00064 #define TELNET_DONT  254
00065 /*---------------------------------------------------------------------------*/
00066 static char *
00067 alloc_line(void)
00068 {
00069   return memb_alloc(&linemem);
00070 }
00071 /*---------------------------------------------------------------------------*/
00072 static void
00073 dealloc_line(char *line)
00074 {
00075   memb_free(&linemem, line);
00076 }
00077 /*---------------------------------------------------------------------------*/
00078 void
00079 shell_quit(char *str)
00080 {
00081   s.state = STATE_CLOSE;
00082 }
00083 /*---------------------------------------------------------------------------*/
00084 static void
00085 sendline(char *line)
00086 {
00087   static unsigned int i;
00088   
00089   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
00090     if(s.lines[i] == NULL) {
00091       s.lines[i] = line;
00092       break;
00093     }
00094   }
00095   if(i == TELNETD_CONF_NUMLINES) {
00096     dealloc_line(line);
00097   }
00098 }
00099 /*---------------------------------------------------------------------------*/
00100 void
00101 shell_prompt(char *str)
00102 {
00103   char *line;
00104   line = alloc_line();
00105   if(line != NULL) {
00106     strncpy(line, str, TELNETD_CONF_LINELEN);
00107     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
00108     sendline(line);
00109   }
00110 }
00111 /*---------------------------------------------------------------------------*/
00112 void
00113 shell_output(char *str1, char *str2)
00114 {
00115   static unsigned len;
00116   char *line;
00117 
00118   line = alloc_line();
00119   if(line != NULL) {
00120     len = strlen(str1);
00121     strncpy(line, str1, TELNETD_CONF_LINELEN);
00122     if(len < TELNETD_CONF_LINELEN) {
00123       strncpy(line + len, str2, TELNETD_CONF_LINELEN - len);
00124     }
00125     len = strlen(line);
00126     if(len < TELNETD_CONF_LINELEN - 2) {
00127       line[len] = ISO_cr;
00128       line[len+1] = ISO_nl;
00129       line[len+2] = 0;
00130     }
00131     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
00132     sendline(line);
00133   }
00134 }
00135 /*---------------------------------------------------------------------------*/
00136 void
00137 telnetd_init(void)
00138 {
00139   uip_listen(HTONS(23));
00140   memb_init(&linemem);
00141   shell_init();
00142 }
00143 /*---------------------------------------------------------------------------*/
00144 static void
00145 acked(void)
00146 {
00147   static unsigned int i;
00148   
00149   while(s.numsent > 0) {
00150     dealloc_line(s.lines[0]);
00151     for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) {
00152       s.lines[i - 1] = s.lines[i];
00153     }
00154     s.lines[TELNETD_CONF_NUMLINES - 1] = NULL;
00155     --s.numsent;
00156   }
00157 }
00158 /*---------------------------------------------------------------------------*/
00159 static void
00160 senddata(void)
00161 {
00162   static char *bufptr, *lineptr;
00163   static int buflen, linelen;
00164   
00165   bufptr = uip_appdata;
00166   buflen = 0;
00167   for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES &&
00168         s.lines[s.numsent] != NULL ; ++s.numsent) {
00169     lineptr = s.lines[s.numsent];
00170     linelen = strlen(lineptr);
00171     if(linelen > TELNETD_CONF_LINELEN) {
00172       linelen = TELNETD_CONF_LINELEN;
00173     }
00174     if(buflen + linelen < uip_mss()) {
00175       memcpy(bufptr, lineptr, linelen);
00176       bufptr += linelen;
00177       buflen += linelen;
00178     } else {
00179       break;
00180     }
00181   }
00182   uip_send(uip_appdata, buflen);
00183 }
00184 /*---------------------------------------------------------------------------*/
00185 static void
00186 closed(void)
00187 {
00188   static unsigned int i;
00189   
00190   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
00191     if(s.lines[i] != NULL) {
00192       dealloc_line(s.lines[i]);
00193     }
00194   }
00195 }
00196 /*---------------------------------------------------------------------------*/
00197 static void
00198 get_char(u8_t c)
00199 {
00200   if(c == ISO_cr) {
00201     return;
00202   }
00203   
00204   s.buf[(int)s.bufptr] = c;
00205   if(s.buf[(int)s.bufptr] == ISO_nl ||
00206      s.bufptr == sizeof(s.buf) - 1) {
00207     if(s.bufptr > 0) {
00208       s.buf[(int)s.bufptr] = 0;
00209       /*      petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/
00210     }
00211     shell_input(s.buf);
00212     s.bufptr = 0;
00213   } else {
00214     ++s.bufptr;
00215   }
00216 }
00217 /*---------------------------------------------------------------------------*/
00218 static void
00219 sendopt(u8_t option, u8_t value)
00220 {
00221   char *line;
00222   line = alloc_line();
00223   if(line != NULL) {
00224     line[0] = TELNET_IAC;
00225     line[1] = option;
00226     line[2] = value;
00227     line[3] = 0;
00228     sendline(line);
00229   }
00230 }
00231 /*---------------------------------------------------------------------------*/
00232 static void
00233 newdata(void)
00234 {
00235   u16_t len;
00236   u8_t c;
00237   char *dataptr;
00238     
00239   
00240   len = uip_datalen();
00241   dataptr = (char *)uip_appdata;
00242   
00243   while(len > 0 && s.bufptr < sizeof(s.buf)) {
00244     c = *dataptr;
00245     ++dataptr;
00246     --len;
00247     switch(s.state) {
00248     case STATE_IAC:
00249       if(c == TELNET_IAC) {
00250         get_char(c);
00251         s.state = STATE_NORMAL;
00252       } else {
00253         switch(c) {
00254         case TELNET_WILL:
00255           s.state = STATE_WILL;
00256           break;
00257         case TELNET_WONT:
00258           s.state = STATE_WONT;
00259           break;
00260         case TELNET_DO:
00261           s.state = STATE_DO;
00262           break;
00263         case TELNET_DONT:
00264           s.state = STATE_DONT;
00265           break;
00266         default:
00267           s.state = STATE_NORMAL;
00268           break;
00269         }
00270       }
00271       break;
00272     case STATE_WILL:
00273       /* Reply with a DONT */
00274       sendopt(TELNET_DONT, c);
00275       s.state = STATE_NORMAL;
00276       break;
00277       
00278     case STATE_WONT:
00279       /* Reply with a DONT */
00280       sendopt(TELNET_DONT, c);
00281       s.state = STATE_NORMAL;
00282       break;
00283     case STATE_DO:
00284       /* Reply with a WONT */
00285       sendopt(TELNET_WONT, c);
00286       s.state = STATE_NORMAL;
00287       break;
00288     case STATE_DONT:
00289       /* Reply with a WONT */
00290       sendopt(TELNET_WONT, c);
00291       s.state = STATE_NORMAL;
00292       break;
00293     case STATE_NORMAL:
00294       if(c == TELNET_IAC) {
00295         s.state = STATE_IAC;
00296       } else {
00297         get_char(c);
00298       }
00299       break;
00300     }
00301 
00302     
00303   }
00304   
00305 }
00306 /*---------------------------------------------------------------------------*/
00307 void
00308 telnetd_appcall(void)
00309 {
00310   static unsigned int i;
00311   if(uip_connected()) {
00312     /*    tcp_markconn(uip_conn, &s);*/
00313     for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
00314       s.lines[i] = NULL;
00315     }
00316     s.bufptr = 0;
00317     s.state = STATE_NORMAL;
00318 
00319     shell_start();
00320   }
00321 
00322   if(s.state == STATE_CLOSE) {
00323     s.state = STATE_NORMAL;
00324     uip_close();
00325     return;
00326   }
00327   
00328   if(uip_closed() ||
00329      uip_aborted() ||
00330      uip_timedout()) {
00331     closed();
00332   }
00333   
00334   if(uip_acked()) {
00335     acked();
00336   }
00337   
00338   if(uip_newdata()) {
00339     newdata();
00340   }
00341   
00342   if(uip_rexmit() ||
00343      uip_newdata() ||
00344      uip_acked() ||
00345      uip_connected() ||
00346      uip_poll()) {
00347     senddata();
00348   }
00349 }
00350 /*---------------------------------------------------------------------------*/

Generated on Mon Jun 12 10:23:01 2006 for uIP 1.0 by  doxygen 1.4.6