xref: /nrf52832-nimble/rt-thread/components/net/uip/apps/telnetd/telnetd.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2003, Adam Dunkels.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior
15  *    written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * This file is part of the uIP TCP/IP stack
30  *
31  * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $
32  *
33  */
34 
35 #include "uip.h"
36 #include "telnetd.h"
37 #include "memb.h"
38 #include "shell.h"
39 
40 #include <string.h>
41 
42 #define ISO_nl       0x0a
43 #define ISO_cr       0x0d
44 
45 struct telnetd_line {
46   char line[TELNETD_CONF_LINELEN];
47 };
48 MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES);
49 
50 #define STATE_NORMAL 0
51 #define STATE_IAC    1
52 #define STATE_WILL   2
53 #define STATE_WONT   3
54 #define STATE_DO     4
55 #define STATE_DONT   5
56 #define STATE_CLOSE  6
57 
58 static struct telnetd_state s;
59 
60 #define TELNET_IAC   255
61 #define TELNET_WILL  251
62 #define TELNET_WONT  252
63 #define TELNET_DO    253
64 #define TELNET_DONT  254
65 /*---------------------------------------------------------------------------*/
66 static char *
alloc_line(void)67 alloc_line(void)
68 {
69   return memb_alloc(&linemem);
70 }
71 /*---------------------------------------------------------------------------*/
72 static void
dealloc_line(char * line)73 dealloc_line(char *line)
74 {
75   memb_free(&linemem, line);
76 }
77 /*---------------------------------------------------------------------------*/
78 void
shell_quit(char * str)79 shell_quit(char *str)
80 {
81   s.state = STATE_CLOSE;
82 }
83 /*---------------------------------------------------------------------------*/
84 static void
sendline(char * line)85 sendline(char *line)
86 {
87   static unsigned int i;
88 
89   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
90     if(s.lines[i] == NULL) {
91       s.lines[i] = line;
92       break;
93     }
94   }
95   if(i == TELNETD_CONF_NUMLINES) {
96     dealloc_line(line);
97   }
98 }
99 /*---------------------------------------------------------------------------*/
100 void
shell_prompt(char * str)101 shell_prompt(char *str)
102 {
103   char *line;
104   line = alloc_line();
105   if(line != NULL) {
106     strncpy(line, str, TELNETD_CONF_LINELEN);
107     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
108     sendline(line);
109   }
110 }
111 /*---------------------------------------------------------------------------*/
112 void
shell_output(char * str1,char * str2)113 shell_output(char *str1, char *str2)
114 {
115   static unsigned len;
116   char *line;
117 
118   line = alloc_line();
119   if(line != NULL) {
120     len = strlen(str1);
121     strncpy(line, str1, TELNETD_CONF_LINELEN);
122     if(len < TELNETD_CONF_LINELEN) {
123       strncpy(line + len, str2, TELNETD_CONF_LINELEN - len);
124     }
125     len = strlen(line);
126     if(len < TELNETD_CONF_LINELEN - 2) {
127       line[len] = ISO_cr;
128       line[len+1] = ISO_nl;
129       line[len+2] = 0;
130     }
131     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
132     sendline(line);
133   }
134 }
135 /*---------------------------------------------------------------------------*/
136 void
telnetd_init(void)137 telnetd_init(void)
138 {
139   uip_listen(HTONS(23));
140   memb_init(&linemem);
141   shell_init();
142 }
143 /*---------------------------------------------------------------------------*/
144 static void
acked(void)145 acked(void)
146 {
147   static unsigned int i;
148 
149   while(s.numsent > 0) {
150     dealloc_line(s.lines[0]);
151     for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) {
152       s.lines[i - 1] = s.lines[i];
153     }
154     s.lines[TELNETD_CONF_NUMLINES - 1] = NULL;
155     --s.numsent;
156   }
157 }
158 /*---------------------------------------------------------------------------*/
159 static void
senddata(void)160 senddata(void)
161 {
162   static char *bufptr, *lineptr;
163   static int buflen, linelen;
164 
165   bufptr = uip_appdata;
166   buflen = 0;
167   for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES &&
168 	s.lines[s.numsent] != NULL ; ++s.numsent) {
169     lineptr = s.lines[s.numsent];
170     linelen = strlen(lineptr);
171     if(linelen > TELNETD_CONF_LINELEN) {
172       linelen = TELNETD_CONF_LINELEN;
173     }
174     if(buflen + linelen < uip_mss()) {
175       memcpy(bufptr, lineptr, linelen);
176       bufptr += linelen;
177       buflen += linelen;
178     } else {
179       break;
180     }
181   }
182   uip_send(uip_appdata, buflen);
183 }
184 /*---------------------------------------------------------------------------*/
185 static void
closed(void)186 closed(void)
187 {
188   static unsigned int i;
189 
190   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
191     if(s.lines[i] != NULL) {
192       dealloc_line(s.lines[i]);
193     }
194   }
195 }
196 /*---------------------------------------------------------------------------*/
197 static void
get_char(u8_t c)198 get_char(u8_t c)
199 {
200   if(c == ISO_cr) {
201     return;
202   }
203 
204   s.buf[(int)s.bufptr] = c;
205   if(s.buf[(int)s.bufptr] == ISO_nl ||
206      s.bufptr == sizeof(s.buf) - 1) {
207     if(s.bufptr > 0) {
208       s.buf[(int)s.bufptr] = 0;
209       /*      petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/
210     }
211     shell_input(s.buf);
212     s.bufptr = 0;
213   } else {
214     ++s.bufptr;
215   }
216 }
217 /*---------------------------------------------------------------------------*/
218 static void
sendopt(u8_t option,u8_t value)219 sendopt(u8_t option, u8_t value)
220 {
221   char *line;
222   line = alloc_line();
223   if(line != NULL) {
224     line[0] = TELNET_IAC;
225     line[1] = option;
226     line[2] = value;
227     line[3] = 0;
228     sendline(line);
229   }
230 }
231 /*---------------------------------------------------------------------------*/
232 static void
newdata(void)233 newdata(void)
234 {
235   u16_t len;
236   u8_t c;
237   char *dataptr;
238 
239 
240   len = uip_datalen();
241   dataptr = (char *)uip_appdata;
242 
243   while(len > 0 && s.bufptr < sizeof(s.buf)) {
244     c = *dataptr;
245     ++dataptr;
246     --len;
247     switch(s.state) {
248     case STATE_IAC:
249       if(c == TELNET_IAC) {
250 	get_char(c);
251 	s.state = STATE_NORMAL;
252       } else {
253 	switch(c) {
254 	case TELNET_WILL:
255 	  s.state = STATE_WILL;
256 	  break;
257 	case TELNET_WONT:
258 	  s.state = STATE_WONT;
259 	  break;
260 	case TELNET_DO:
261 	  s.state = STATE_DO;
262 	  break;
263 	case TELNET_DONT:
264 	  s.state = STATE_DONT;
265 	  break;
266 	default:
267 	  s.state = STATE_NORMAL;
268 	  break;
269 	}
270       }
271       break;
272     case STATE_WILL:
273       /* Reply with a DONT */
274       sendopt(TELNET_DONT, c);
275       s.state = STATE_NORMAL;
276       break;
277 
278     case STATE_WONT:
279       /* Reply with a DONT */
280       sendopt(TELNET_DONT, c);
281       s.state = STATE_NORMAL;
282       break;
283     case STATE_DO:
284       /* Reply with a WONT */
285       sendopt(TELNET_WONT, c);
286       s.state = STATE_NORMAL;
287       break;
288     case STATE_DONT:
289       /* Reply with a WONT */
290       sendopt(TELNET_WONT, c);
291       s.state = STATE_NORMAL;
292       break;
293     case STATE_NORMAL:
294       if(c == TELNET_IAC) {
295 	s.state = STATE_IAC;
296       } else {
297 	get_char(c);
298       }
299       break;
300     }
301 
302 
303   }
304 
305 }
306 /*---------------------------------------------------------------------------*/
307 void
telnetd_appcall(void)308 telnetd_appcall(void)
309 {
310   static unsigned int i;
311   if(uip_connected()) {
312     /*    tcp_markconn(uip_conn, &s);*/
313     for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
314       s.lines[i] = NULL;
315     }
316     s.bufptr = 0;
317     s.state = STATE_NORMAL;
318 
319     shell_start();
320   }
321 
322   if(s.state == STATE_CLOSE) {
323     s.state = STATE_NORMAL;
324     uip_close();
325     return;
326   }
327 
328   if(uip_closed() ||
329      uip_aborted() ||
330      uip_timedout()) {
331     closed();
332   }
333 
334   if(uip_acked()) {
335     acked();
336   }
337 
338   if(uip_newdata()) {
339     newdata();
340   }
341 
342   if(uip_rexmit() ||
343      uip_newdata() ||
344      uip_acked() ||
345      uip_connected() ||
346      uip_poll()) {
347     senddata();
348   }
349 }
350 /*---------------------------------------------------------------------------*/
351