]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/uIP_Demo_IAR_ARM7/uip/telnetd.c
dba522271a8b2cb1ef2e84a90760091384a19f22
[freertos] / FreeRTOS / Demo / uIP_Demo_IAR_ARM7 / uip / telnetd.c
1 /**\r
2  * \addtogroup exampleapps\r
3  * @{\r
4  */\r
5 \r
6 /**\r
7  * \defgroup telnetd Telnet server\r
8  * @{\r
9  *\r
10  * The uIP telnet server provides a command based interface to uIP. It\r
11  * allows using the "telnet" application to access uIP, and implements\r
12  * the required telnet option negotiation.\r
13  *\r
14  * The code is structured in a way which makes it possible to add\r
15  * commands without having to rewrite the main telnet code. The main\r
16  * telnet code calls two callback functions, telnetd_connected() and\r
17  * telnetd_input(), when a telnet connection has been established and\r
18  * when a line of text arrives on a telnet connection. These two\r
19  * functions can be implemented in a way which suits the particular\r
20  * application or environment in which the uIP system is intended to\r
21  * be run.\r
22  *\r
23  * The uIP distribution contains an example telnet shell\r
24  * implementation that provides a basic set of commands.\r
25  */\r
26 \r
27 /**\r
28  * \file\r
29  * Implementation of the Telnet server.\r
30  * \author Adam Dunkels <adam@dunkels.com>\r
31  */\r
32 \r
33 /*\r
34  * Copyright (c) 2003, Adam Dunkels.\r
35  * All rights reserved. \r
36  *\r
37  * Redistribution and use in source and binary forms, with or without \r
38  * modification, are permitted provided that the following conditions \r
39  * are met: \r
40  * 1. Redistributions of source code must retain the above copyright \r
41  *    notice, this list of conditions and the following disclaimer. \r
42  * 2. Redistributions in binary form must reproduce the above copyright \r
43  *    notice, this list of conditions and the following disclaimer in the \r
44  *    documentation and/or other materials provided with the distribution. \r
45  * 3. The name of the author may not be used to endorse or promote\r
46  *    products derived from this software without specific prior\r
47  *    written permission.  \r
48  *\r
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
50  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
51  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
53  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
55  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
56  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
57  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
58  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
59  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  \r
60  *\r
61  * This file is part of the uIP TCP/IP stack.\r
62  *\r
63  * $Id: telnetd.c,v 1.1.2.2 2003/10/07 13:47:50 adam Exp $\r
64  *\r
65  */\r
66 \r
67 #include "uip.h"\r
68 #include "memb.h"\r
69 #include "telnetd.h"\r
70 #include <string.h>\r
71 \r
72 #define ISO_nl       0x0a\r
73 #define ISO_cr       0x0d\r
74 \r
75 MEMB(linemem, TELNETD_LINELEN, TELNETD_NUMLINES);\r
76 \r
77 static u8_t i;\r
78 \r
79 #define STATE_NORMAL 0\r
80 #define STATE_IAC    1\r
81 #define STATE_WILL   2\r
82 #define STATE_WONT   3\r
83 #define STATE_DO     4  \r
84 #define STATE_DONT   5\r
85 #define STATE_CLOSE  6\r
86 \r
87 #define TELNET_IAC   255\r
88 #define TELNET_WILL  251\r
89 #define TELNET_WONT  252\r
90 #define TELNET_DO    253\r
91 #define TELNET_DONT  254\r
92 /*-----------------------------------------------------------------------------------*/\r
93 static char *\r
94 alloc_line(void)\r
95 {  \r
96   return memb_alloc(&linemem);\r
97 }\r
98 /*-----------------------------------------------------------------------------------*/\r
99 static void\r
100 dealloc_line(char *line)\r
101 {\r
102   memb_free(&linemem, line);\r
103 }\r
104 /*-----------------------------------------------------------------------------------*/\r
105 static void\r
106 sendline(struct telnetd_state *s, char *line)\r
107 {\r
108   static unsigned int i;\r
109   for(i = 0; i < TELNETD_NUMLINES; ++i) {\r
110     if(s->lines[i] == NULL) {\r
111       s->lines[i] = line;\r
112       break;\r
113     }\r
114   }\r
115   if(i == TELNETD_NUMLINES) {\r
116     dealloc_line(line);\r
117   }\r
118 }\r
119 /*-----------------------------------------------------------------------------------*/\r
120 /**\r
121  * Close a telnet session.\r
122  *\r
123  * This function can be called from a telnet command in order to close\r
124  * the connection.\r
125  *\r
126  * \param s The connection which is to be closed.\r
127  *\r
128  */\r
129 /*-----------------------------------------------------------------------------------*/\r
130 void\r
131 telnetd_close(struct telnetd_state *s)\r
132 {\r
133   s->state = STATE_CLOSE;\r
134 }\r
135 /*-----------------------------------------------------------------------------------*/\r
136 /**\r
137  * Print a prompt on a telnet connection.\r
138  *\r
139  * This function can be called by the telnet command shell in order to\r
140  * print out a command prompt.\r
141  *\r
142  * \param s A telnet connection.\r
143  *\r
144  * \param str The command prompt.\r
145  *\r
146  */\r
147 /*-----------------------------------------------------------------------------------*/\r
148 void\r
149 telnetd_prompt(struct telnetd_state *s, char *str)\r
150 {\r
151   char *line;\r
152   line = alloc_line();\r
153   if(line != NULL) {\r
154     strncpy(line, str, TELNETD_LINELEN);\r
155     sendline(s, line);\r
156   }         \r
157 }\r
158 /*-----------------------------------------------------------------------------------*/\r
159 /**\r
160  * Print out a string on a telnet connection.\r
161  *\r
162  * This function can be called from a telnet command parser in order\r
163  * to print out a string of text on the connection. The two strings\r
164  * given as arguments to the function will be concatenated, a carrige\r
165  * return and a new line character will be added, and the line is\r
166  * sent.\r
167  *\r
168  * \param s The telnet connection.\r
169  *\r
170  * \param str1 The first string.\r
171  *\r
172  * \param str2 The second string.\r
173  *\r
174  */\r
175 /*-----------------------------------------------------------------------------------*/\r
176 void\r
177 telnetd_output(struct telnetd_state *s, char *str1, char *str2)\r
178 {\r
179   static unsigned len;\r
180   char *line;\r
181   \r
182   line = alloc_line();\r
183   if(line != NULL) {\r
184     len = strlen(str1);\r
185     strncpy(line, str1, TELNETD_LINELEN);\r
186     if(len < TELNETD_LINELEN) {\r
187       strncpy(line + len, str2, TELNETD_LINELEN - len);\r
188     }\r
189     len = strlen(line);\r
190     if(len < TELNETD_LINELEN - 2) {\r
191       line[len] = ISO_cr;\r
192       line[len+1] = ISO_nl;\r
193       line[len+2] = 0;\r
194     }\r
195     sendline(s, line);\r
196   }\r
197 }\r
198 /*-----------------------------------------------------------------------------------*/\r
199 /**\r
200  * Initialize the telnet server.\r
201  *\r
202  * This function will perform the necessary initializations and start\r
203  * listening on TCP port 23.\r
204  */\r
205 /*-----------------------------------------------------------------------------------*/\r
206 void\r
207 telnetd_init(void)\r
208 {\r
209   memb_init(&linemem);\r
210   uip_listen(HTONS(23));\r
211 }\r
212 /*-----------------------------------------------------------------------------------*/\r
213 static void\r
214 acked(struct telnetd_state *s)     \r
215 {\r
216   dealloc_line(s->lines[0]);\r
217   for(i = 1; i < TELNETD_NUMLINES; ++i) {\r
218     s->lines[i - 1] = s->lines[i];\r
219   }\r
220 }\r
221 /*-----------------------------------------------------------------------------------*/\r
222 static void\r
223 senddata(struct telnetd_state *s)    \r
224 {\r
225   if(s->lines[0] != NULL) {\r
226     uip_send(s->lines[0], strlen(s->lines[0]));\r
227   }\r
228 }\r
229 /*-----------------------------------------------------------------------------------*/\r
230 static void\r
231 getchar(struct telnetd_state *s, u8_t c)\r
232 {\r
233   if(c == ISO_cr) {\r
234     return;\r
235   }\r
236   \r
237   s->buf[(int)s->bufptr] = c;  \r
238   if(s->buf[(int)s->bufptr] == ISO_nl ||\r
239      s->bufptr == sizeof(s->buf) - 1) {    \r
240     if(s->bufptr > 0) {\r
241       s->buf[(int)s->bufptr] = 0;\r
242     }\r
243     telnetd_input(s, s->buf);\r
244     s->bufptr = 0;\r
245   } else {\r
246     ++s->bufptr;\r
247   }\r
248 }\r
249 /*-----------------------------------------------------------------------------------*/\r
250 static void\r
251 sendopt(struct telnetd_state *s, u8_t option, u8_t value)\r
252 {\r
253   char *line;\r
254   line = alloc_line();\r
255   if(line != NULL) {\r
256     line[0] = TELNET_IAC;\r
257     line[1] = option;\r
258     line[2] = value;\r
259     line[3] = 0;\r
260     sendline(s, line);\r
261   }       \r
262 }\r
263 /*-----------------------------------------------------------------------------------*/\r
264 static void\r
265 newdata(struct telnetd_state *s)\r
266 {\r
267   u16_t len;\r
268   u8_t c;\r
269     \r
270   \r
271   len = uip_datalen();\r
272   \r
273   while(len > 0 && s->bufptr < sizeof(s->buf)) {\r
274     c = *uip_appdata;\r
275     ++uip_appdata;\r
276     --len;\r
277     switch(s->state) {\r
278     case STATE_IAC:\r
279       if(c == TELNET_IAC) {\r
280         getchar(s, c);\r
281         s->state = STATE_NORMAL;\r
282       } else {\r
283         switch(c) {\r
284         case TELNET_WILL:\r
285           s->state = STATE_WILL;\r
286           break;\r
287         case TELNET_WONT:\r
288           s->state = STATE_WONT;\r
289           break;\r
290         case TELNET_DO:\r
291           s->state = STATE_DO;\r
292           break;\r
293         case TELNET_DONT:\r
294           s->state = STATE_DONT;\r
295           break;\r
296         default:\r
297           s->state = STATE_NORMAL;\r
298           break;\r
299         }\r
300       }\r
301       break;\r
302     case STATE_WILL:\r
303       /* Reply with a DONT */\r
304       sendopt(s, TELNET_DONT, c);\r
305       s->state = STATE_NORMAL;\r
306       break;\r
307       \r
308     case STATE_WONT:\r
309       /* Reply with a DONT */\r
310       sendopt(s, TELNET_DONT, c);\r
311       s->state = STATE_NORMAL;\r
312       break;\r
313     case STATE_DO:\r
314       /* Reply with a WONT */\r
315       sendopt(s, TELNET_WONT, c);\r
316       s->state = STATE_NORMAL;\r
317       break;\r
318     case STATE_DONT:\r
319       /* Reply with a WONT */\r
320       sendopt(s, TELNET_WONT, c);\r
321       s->state = STATE_NORMAL;\r
322       break;\r
323     case STATE_NORMAL:\r
324       if(c == TELNET_IAC) {\r
325         s->state = STATE_IAC;\r
326       } else {\r
327         getchar(s, c);\r
328       }      \r
329       break;\r
330     } \r
331 \r
332     \r
333   }  \r
334   \r
335 }\r
336 /*-----------------------------------------------------------------------------------*/\r
337 void\r
338 telnetd_app(void)\r
339 {\r
340   struct telnetd_state *s;\r
341 \r
342   s = (struct telnetd_state *)uip_conn->appstate;\r
343   \r
344   if(uip_connected()) {\r
345 \r
346     for(i = 0; i < TELNETD_NUMLINES; ++i) {\r
347       s->lines[i] = NULL;\r
348     }\r
349     s->bufptr = 0;\r
350     s->state = STATE_NORMAL;\r
351 \r
352     telnetd_connected(s);\r
353     senddata(s);\r
354     return;\r
355   }\r
356 \r
357   if(s->state == STATE_CLOSE) {\r
358     s->state = STATE_NORMAL;\r
359     uip_close();\r
360     return;\r
361   }\r
362   \r
363   if(uip_closed()) {\r
364     telnetd_output(s, "Connection closed", "");\r
365   }\r
366 \r
367   \r
368   if(uip_aborted()) {\r
369     telnetd_output(s, "Connection reset", "");\r
370   }\r
371   \r
372   if(uip_timedout()) {\r
373     telnetd_output(s, "Connection timed out", "");\r
374   }\r
375   \r
376   if(uip_acked()) {\r
377     acked(s);\r
378   }\r
379   \r
380   if(uip_newdata()) {\r
381     newdata(s);\r
382   }\r
383   \r
384   if(uip_rexmit() ||\r
385      uip_newdata() ||\r
386      uip_acked()) {\r
387     senddata(s);\r
388   } else if(uip_poll()) {    \r
389     senddata(s);\r
390   }\r
391 }\r
392 /*-----------------------------------------------------------------------------------*/\r