liuchao 1 год назад
Родитель
Сommit
22f7573311
1 измененных файлов с 48 добавлено и 24 удалено
  1. 48 24
      telnet/telnet.c

+ 48 - 24
telnet/telnet.c

@@ -59,6 +59,7 @@ static int dev_old_flag;
 #define TELNET_DONT         254
 
 #define TELNET_OPT_ECHO     1
+#define TELNET_OPT_SGA      3
 
 struct telnet_session
 {
@@ -74,7 +75,7 @@ struct telnet_session
 
     /* telnet protocol */
     rt_uint8_t state;
-    rt_uint8_t echo_mode;
+    rt_uint8_t finsh_saved_echo_mode;
 
     rt_sem_t read_notice;
 };
@@ -164,23 +165,45 @@ static void process_rx(struct telnet_session* telnet, rt_uint8_t *data, rt_size_
             }
             break;
 
-            /* don't option */
         case STATE_WILL:
-            send_option_to_client(telnet, TELNET_DO, *data);
+            if (*data == TELNET_OPT_ECHO || *data == TELNET_OPT_SGA)
+            {
+                send_option_to_client(telnet, TELNET_DO, *data);
+            }
+            else
+            {
+                send_option_to_client(telnet, TELNET_DONT, *data);
+            }
             telnet->state = STATE_NORMAL;
             break;
         case STATE_WONT:
-            send_option_to_client(telnet, TELNET_DONT, *data);
+            if (*data == TELNET_OPT_ECHO)
+            {
+                finsh_set_echo(0);
+            }
             telnet->state = STATE_NORMAL;
             break;
 
-            /* won't option */
         case STATE_DO:
-            send_option_to_client(telnet, TELNET_WILL, *data);
+            if (*data == TELNET_OPT_ECHO || *data == TELNET_OPT_SGA)
+            {
+                if (*data == TELNET_OPT_ECHO)
+                {
+                    finsh_set_echo(1);
+                }
+                send_option_to_client(telnet, TELNET_WILL, *data);
+            }
+            else
+            {
+                send_option_to_client(telnet, TELNET_WONT, *data);
+            }
             telnet->state = STATE_NORMAL;
             break;
         case STATE_DONT:
-            send_option_to_client(telnet, TELNET_WONT, *data);
+            if (*data == TELNET_OPT_ECHO)
+            {
+                finsh_set_echo(0);
+            }
             telnet->state = STATE_NORMAL;
             break;
 
@@ -189,6 +212,20 @@ static void process_rx(struct telnet_session* telnet, rt_uint8_t *data, rt_size_
             {
                 telnet->state = STATE_IAC;
             }
+            else if (*data == '\r')
+            {
+                /*
+                 * telnet client(not busybox's telnet) will send 0d00 if not toggle crlf by default,
+                 * change them to 0d0a, so we don't have to toggle
+                 */
+                if ((index + 1) <= length)
+                {
+                    if (data[1] == 0)
+                    {
+                        data[1] = '\n';
+                    }
+                }
+            }
             else if (*data != '\r') /* ignore '\r' */
             {
                 rt_mutex_take(telnet->rx_ringbuffer_lock, RT_WAITING_FOREVER);
@@ -238,7 +275,7 @@ static void client_close(struct telnet_session* telnet)
     closesocket(telnet->client_fd);
 
     /* restore shell option */
-    finsh_set_echo(telnet->echo_mode);
+    finsh_set_echo(telnet->finsh_saved_echo_mode);
 
     rt_kprintf("telnet: resume console to %s\n", RT_CONSOLE_DEVICE_NAME);
 }
@@ -323,18 +360,6 @@ static rt_err_t telnet_control(rt_device_t dev, int cmd, void *args)
     };
 #endif /* RT_USING_DEVICE_OPS */
 
-
-static int telnet_enable_echo(rt_int32_t fd)
-{
-    rt_uint8_t cmd_len = 3;
-    rt_uint8_t cmd_buffer[4];
-
-    cmd_buffer[0] = TELNET_IAC;
-    cmd_buffer[1] = TELNET_WILL;
-    cmd_buffer[2] = TELNET_OPT_ECHO;
-    return send(fd, cmd_buffer, cmd_len, 0);
-}
-
 /* telnet server thread entry */
 static void telnet_thread(void* parameter)
 {
@@ -431,16 +456,15 @@ static void telnet_thread(void* parameter)
         /* set init state */
         telnet->state = STATE_NORMAL;
 
-        telnet->echo_mode = finsh_get_echo();
-        /* enable echo mode */
-        finsh_set_echo(1);
+        telnet->finsh_saved_echo_mode = finsh_get_echo();
+        send_option_to_client(telnet, TELNET_WILL, TELNET_OPT_ECHO);
+
         /* output RT-Thread version and shell prompt */
 #ifdef FINSH_USING_MSH
         msh_exec("version", rt_strlen("version"));
 #endif /* FINSH_USING_MSH */
         rt_kprintf(FINSH_PROMPT);
 
-        telnet_enable_echo(telnet->client_fd);
         while (1)
         {
             /* try to send all data in tx ringbuffer */