telnet.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2015 Daniel Campora
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdint.h>
  27. #include "py/mpconfig.h"
  28. #include "py/obj.h"
  29. #include "py/mphal.h"
  30. #include "lib/utils/interrupt_char.h"
  31. #include "telnet.h"
  32. #include "simplelink.h"
  33. #include "modnetwork.h"
  34. #include "modwlan.h"
  35. #include "modusocket.h"
  36. #include "debug.h"
  37. #include "mpexception.h"
  38. #include "serverstask.h"
  39. #include "genhdr/mpversion.h"
  40. #include "irq.h"
  41. /******************************************************************************
  42. DEFINE PRIVATE CONSTANTS
  43. ******************************************************************************/
  44. #define TELNET_PORT 23
  45. // rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256
  46. #define TELNET_RX_BUFFER_SIZE 256
  47. #define TELNET_MAX_CLIENTS 1
  48. #define TELNET_TX_RETRIES_MAX 50
  49. #define TELNET_WAIT_TIME_MS 5
  50. #define TELNET_LOGIN_RETRIES_MAX 3
  51. #define TELNET_CYCLE_TIME_MS (SERVERS_CYCLE_TIME_MS * 2)
  52. /******************************************************************************
  53. DEFINE PRIVATE TYPES
  54. ******************************************************************************/
  55. typedef enum {
  56. E_TELNET_RESULT_OK = 0,
  57. E_TELNET_RESULT_AGAIN,
  58. E_TELNET_RESULT_FAILED
  59. } telnet_result_t;
  60. typedef enum {
  61. E_TELNET_STE_DISABLED = 0,
  62. E_TELNET_STE_START,
  63. E_TELNET_STE_LISTEN,
  64. E_TELNET_STE_CONNECTED,
  65. E_TELNET_STE_LOGGED_IN
  66. } telnet_state_t;
  67. typedef enum {
  68. E_TELNET_STE_SUB_WELCOME,
  69. E_TELNET_STE_SUB_SND_USER_OPTIONS,
  70. E_TELNET_STE_SUB_REQ_USER,
  71. E_TELNET_STE_SUB_GET_USER,
  72. E_TELNET_STE_SUB_REQ_PASSWORD,
  73. E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS,
  74. E_TELNET_STE_SUB_GET_PASSWORD,
  75. E_TELNET_STE_SUB_INVALID_LOGGIN,
  76. E_TELNET_STE_SUB_SND_REPL_OPTIONS,
  77. E_TELNET_STE_SUB_LOGGIN_SUCCESS
  78. } telnet_connected_substate_t;
  79. typedef union {
  80. telnet_connected_substate_t connected;
  81. } telnet_substate_t;
  82. typedef struct {
  83. uint8_t *rxBuffer;
  84. uint32_t timeout;
  85. telnet_state_t state;
  86. telnet_substate_t substate;
  87. int16_t sd;
  88. int16_t n_sd;
  89. // rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256
  90. uint8_t rxWindex;
  91. uint8_t rxRindex;
  92. uint8_t txRetries;
  93. uint8_t logginRetries;
  94. bool enabled;
  95. bool credentialsValid;
  96. } telnet_data_t;
  97. /******************************************************************************
  98. DECLARE PRIVATE DATA
  99. ******************************************************************************/
  100. static telnet_data_t telnet_data;
  101. static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
  102. static const char* telnet_request_user = "Login as: ";
  103. static const char* telnet_request_password = "Password: ";
  104. static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n";
  105. static const char* telnet_loggin_success = "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n";
  106. static const uint8_t telnet_options_user[] = // IAC WONT ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE
  107. { 255, 252, 1, 255, 252, 3, 255, 251, 34 };
  108. static const uint8_t telnet_options_pass[] = // IAC WILL ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE
  109. { 255, 251, 1, 255, 252, 3, 255, 251, 34 };
  110. static const uint8_t telnet_options_repl[] = // IAC WILL ECHO IAC WILL SUPPRESS_GO_AHEAD IAC WONT LINEMODE
  111. { 255, 251, 1, 255, 251, 3, 255, 252, 34 };
  112. /******************************************************************************
  113. DECLARE PRIVATE FUNCTIONS
  114. ******************************************************************************/
  115. static void telnet_wait_for_enabled (void);
  116. static bool telnet_create_socket (void);
  117. static void telnet_wait_for_connection (void);
  118. static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state);
  119. static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len);
  120. static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen);
  121. static void telnet_process (void);
  122. static int telnet_process_credential (char *credential, _i16 rxLen);
  123. static void telnet_parse_input (uint8_t *str, int16_t *len);
  124. static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len);
  125. static void telnet_reset_buffer (void);
  126. /******************************************************************************
  127. DEFINE PUBLIC FUNCTIONS
  128. ******************************************************************************/
  129. void telnet_init (void) {
  130. // Allocate memory for the receive buffer (from the RTOS heap)
  131. ASSERT ((telnet_data.rxBuffer = mem_Malloc(TELNET_RX_BUFFER_SIZE)) != NULL);
  132. telnet_data.state = E_TELNET_STE_DISABLED;
  133. }
  134. void telnet_run (void) {
  135. _i16 rxLen;
  136. switch (telnet_data.state) {
  137. case E_TELNET_STE_DISABLED:
  138. telnet_wait_for_enabled();
  139. break;
  140. case E_TELNET_STE_START:
  141. if (wlan_is_connected() && telnet_create_socket()) {
  142. telnet_data.state = E_TELNET_STE_LISTEN;
  143. }
  144. break;
  145. case E_TELNET_STE_LISTEN:
  146. telnet_wait_for_connection();
  147. break;
  148. case E_TELNET_STE_CONNECTED:
  149. switch (telnet_data.substate.connected) {
  150. case E_TELNET_STE_SUB_WELCOME:
  151. telnet_send_and_proceed((void *)telnet_welcome_msg, strlen(telnet_welcome_msg), E_TELNET_STE_SUB_SND_USER_OPTIONS);
  152. break;
  153. case E_TELNET_STE_SUB_SND_USER_OPTIONS:
  154. telnet_send_and_proceed((void *)telnet_options_user, sizeof(telnet_options_user), E_TELNET_STE_SUB_REQ_USER);
  155. break;
  156. case E_TELNET_STE_SUB_REQ_USER:
  157. // to catch any left over characters from the previous actions
  158. telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen);
  159. telnet_send_and_proceed((void *)telnet_request_user, strlen(telnet_request_user), E_TELNET_STE_SUB_GET_USER);
  160. break;
  161. case E_TELNET_STE_SUB_GET_USER:
  162. if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex,
  163. TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex,
  164. &rxLen)) {
  165. int result;
  166. if ((result = telnet_process_credential (servers_user, rxLen))) {
  167. telnet_data.credentialsValid = result > 0 ? true : false;
  168. telnet_data.substate.connected = E_TELNET_STE_SUB_REQ_PASSWORD;
  169. }
  170. }
  171. break;
  172. case E_TELNET_STE_SUB_REQ_PASSWORD:
  173. telnet_send_and_proceed((void *)telnet_request_password, strlen(telnet_request_password), E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS);
  174. break;
  175. case E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS:
  176. // to catch any left over characters from the previous actions
  177. telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen);
  178. telnet_send_and_proceed((void *)telnet_options_pass, sizeof(telnet_options_pass), E_TELNET_STE_SUB_GET_PASSWORD);
  179. break;
  180. case E_TELNET_STE_SUB_GET_PASSWORD:
  181. if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex,
  182. TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex,
  183. &rxLen)) {
  184. int result;
  185. if ((result = telnet_process_credential (servers_pass, rxLen))) {
  186. if ((telnet_data.credentialsValid = telnet_data.credentialsValid && (result > 0 ? true : false))) {
  187. telnet_data.substate.connected = E_TELNET_STE_SUB_SND_REPL_OPTIONS;
  188. }
  189. else {
  190. telnet_data.substate.connected = E_TELNET_STE_SUB_INVALID_LOGGIN;
  191. }
  192. }
  193. }
  194. break;
  195. case E_TELNET_STE_SUB_INVALID_LOGGIN:
  196. if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_invalid_loggin, strlen(telnet_invalid_loggin))) {
  197. telnet_data.credentialsValid = true;
  198. if (++telnet_data.logginRetries >= TELNET_LOGIN_RETRIES_MAX) {
  199. telnet_reset();
  200. }
  201. else {
  202. telnet_data.substate.connected = E_TELNET_STE_SUB_SND_USER_OPTIONS;
  203. }
  204. }
  205. break;
  206. case E_TELNET_STE_SUB_SND_REPL_OPTIONS:
  207. telnet_send_and_proceed((void *)telnet_options_repl, sizeof(telnet_options_repl), E_TELNET_STE_SUB_LOGGIN_SUCCESS);
  208. break;
  209. case E_TELNET_STE_SUB_LOGGIN_SUCCESS:
  210. if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_loggin_success, strlen(telnet_loggin_success))) {
  211. // clear the current line and force the prompt
  212. telnet_reset_buffer();
  213. telnet_data.state= E_TELNET_STE_LOGGED_IN;
  214. }
  215. default:
  216. break;
  217. }
  218. break;
  219. case E_TELNET_STE_LOGGED_IN:
  220. telnet_process();
  221. break;
  222. default:
  223. break;
  224. }
  225. if (telnet_data.state >= E_TELNET_STE_CONNECTED) {
  226. if (telnet_data.timeout++ > (servers_get_timeout() / TELNET_CYCLE_TIME_MS)) {
  227. telnet_reset();
  228. }
  229. }
  230. }
  231. void telnet_tx_strn (const char *str, int len) {
  232. if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
  233. telnet_send_with_retries(telnet_data.n_sd, str, len);
  234. }
  235. }
  236. bool telnet_rx_any (void) {
  237. return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
  238. telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
  239. }
  240. int telnet_rx_char (void) {
  241. int rx_char = -1;
  242. if (telnet_data.rxRindex != telnet_data.rxWindex) {
  243. // rxRindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically
  244. rx_char = (int)telnet_data.rxBuffer[telnet_data.rxRindex++];
  245. }
  246. return rx_char;
  247. }
  248. void telnet_enable (void) {
  249. telnet_data.enabled = true;
  250. }
  251. void telnet_disable (void) {
  252. telnet_reset();
  253. telnet_data.enabled = false;
  254. telnet_data.state = E_TELNET_STE_DISABLED;
  255. }
  256. void telnet_reset (void) {
  257. // close the connection and start all over again
  258. servers_close_socket(&telnet_data.n_sd);
  259. servers_close_socket(&telnet_data.sd);
  260. telnet_data.state = E_TELNET_STE_START;
  261. }
  262. /******************************************************************************
  263. DEFINE PRIVATE FUNCTIONS
  264. ******************************************************************************/
  265. static void telnet_wait_for_enabled (void) {
  266. // Init telnet's data
  267. telnet_data.n_sd = -1;
  268. telnet_data.sd = -1;
  269. // Check if the telnet service has been enabled
  270. if (telnet_data.enabled) {
  271. telnet_data.state = E_TELNET_STE_START;
  272. }
  273. }
  274. static bool telnet_create_socket (void) {
  275. SlSockNonblocking_t nonBlockingOption;
  276. SlSockAddrIn_t sServerAddress;
  277. _i16 result;
  278. // Open a socket for telnet
  279. ASSERT ((telnet_data.sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_IPPROTO_TCP)) > 0);
  280. if (telnet_data.sd > 0) {
  281. // add the socket to the network administration
  282. modusocket_socket_add(telnet_data.sd, false);
  283. // Enable non-blocking mode
  284. nonBlockingOption.NonblockingEnabled = 1;
  285. ASSERT ((result = sl_SetSockOpt(telnet_data.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
  286. // Bind the socket to a port number
  287. sServerAddress.sin_family = SL_AF_INET;
  288. sServerAddress.sin_addr.s_addr = SL_INADDR_ANY;
  289. sServerAddress.sin_port = sl_Htons(TELNET_PORT);
  290. ASSERT ((result |= sl_Bind(telnet_data.sd, (const SlSockAddr_t *)&sServerAddress, sizeof(sServerAddress))) == SL_SOC_OK);
  291. // Start listening
  292. ASSERT ((result |= sl_Listen (telnet_data.sd, TELNET_MAX_CLIENTS)) == SL_SOC_OK);
  293. if (result == SL_SOC_OK) {
  294. return true;
  295. }
  296. servers_close_socket(&telnet_data.sd);
  297. }
  298. return false;
  299. }
  300. static void telnet_wait_for_connection (void) {
  301. SlSocklen_t in_addrSize;
  302. SlSockAddrIn_t sClientAddress;
  303. // accepts a connection from a TCP client, if there is any, otherwise returns SL_EAGAIN
  304. telnet_data.n_sd = sl_Accept(telnet_data.sd, (SlSockAddr_t *)&sClientAddress, (SlSocklen_t *)&in_addrSize);
  305. if (telnet_data.n_sd == SL_EAGAIN) {
  306. return;
  307. }
  308. else {
  309. if (telnet_data.n_sd <= 0) {
  310. // error
  311. telnet_reset();
  312. return;
  313. }
  314. // close the listening socket, we don't need it anymore
  315. servers_close_socket(&telnet_data.sd);
  316. // add the new socket to the network administration
  317. modusocket_socket_add(telnet_data.n_sd, false);
  318. // client connected, so go on
  319. telnet_data.rxWindex = 0;
  320. telnet_data.rxRindex = 0;
  321. telnet_data.txRetries = 0;
  322. telnet_data.state = E_TELNET_STE_CONNECTED;
  323. telnet_data.substate.connected = E_TELNET_STE_SUB_WELCOME;
  324. telnet_data.credentialsValid = true;
  325. telnet_data.logginRetries = 0;
  326. telnet_data.timeout = 0;
  327. }
  328. }
  329. static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state) {
  330. if (E_TELNET_RESULT_OK == telnet_send_non_blocking(data, Len)) {
  331. telnet_data.substate.connected = next_state;
  332. }
  333. }
  334. static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len) {
  335. int16_t result = sl_Send(telnet_data.n_sd, data, Len, 0);
  336. if (result > 0) {
  337. telnet_data.txRetries = 0;
  338. return E_TELNET_RESULT_OK;
  339. }
  340. else if ((TELNET_TX_RETRIES_MAX >= ++telnet_data.txRetries) && (result == SL_EAGAIN)) {
  341. return E_TELNET_RESULT_AGAIN;
  342. }
  343. else {
  344. // error
  345. telnet_reset();
  346. return E_TELNET_RESULT_FAILED;
  347. }
  348. }
  349. static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen) {
  350. *rxLen = sl_Recv(telnet_data.n_sd, buff, Maxlen, 0);
  351. // if there's data received, parse it
  352. if (*rxLen > 0) {
  353. telnet_data.timeout = 0;
  354. telnet_parse_input (buff, rxLen);
  355. if (*rxLen > 0) {
  356. return E_TELNET_RESULT_OK;
  357. }
  358. }
  359. else if (*rxLen != SL_EAGAIN) {
  360. // error
  361. telnet_reset();
  362. return E_TELNET_RESULT_FAILED;
  363. }
  364. return E_TELNET_RESULT_AGAIN;
  365. }
  366. static void telnet_process (void) {
  367. _i16 rxLen;
  368. _i16 maxLen = (telnet_data.rxWindex >= telnet_data.rxRindex) ? (TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex) :
  369. ((telnet_data.rxRindex - telnet_data.rxWindex) - 1);
  370. // to avoid an overrrun
  371. maxLen = (telnet_data.rxRindex == 0) ? (maxLen - 1) : maxLen;
  372. if (maxLen > 0) {
  373. if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(&telnet_data.rxBuffer[telnet_data.rxWindex], maxLen, &rxLen)) {
  374. // rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically
  375. telnet_data.rxWindex = telnet_data.rxWindex + rxLen;
  376. }
  377. }
  378. }
  379. static int telnet_process_credential (char *credential, _i16 rxLen) {
  380. telnet_data.rxWindex += rxLen;
  381. if (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX) {
  382. telnet_data.rxWindex = SERVERS_USER_PASS_LEN_MAX;
  383. }
  384. uint8_t *p = telnet_data.rxBuffer + SERVERS_USER_PASS_LEN_MAX;
  385. // if a '\r' is found, or the length exceeds the max username length
  386. if ((p = memchr(telnet_data.rxBuffer, '\r', telnet_data.rxWindex)) || (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX)) {
  387. uint8_t len = p - telnet_data.rxBuffer;
  388. telnet_data.rxWindex = 0;
  389. if ((len > 0) && (memcmp(credential, telnet_data.rxBuffer, MAX(len, strlen(credential))) == 0)) {
  390. return 1;
  391. }
  392. return -1;
  393. }
  394. return 0;
  395. }
  396. static void telnet_parse_input (uint8_t *str, int16_t *len) {
  397. int16_t b_len = *len;
  398. uint8_t *b_str = str;
  399. for (uint8_t *_str = b_str; _str < b_str + b_len; ) {
  400. if (*_str <= 127) {
  401. if (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == mp_interrupt_char) {
  402. // raise a keyboard exception
  403. mp_keyboard_interrupt();
  404. (*len)--;
  405. _str++;
  406. }
  407. else if (*_str > 0) {
  408. *str++ = *_str++;
  409. }
  410. else {
  411. _str++;
  412. *len -= 1;
  413. }
  414. }
  415. else {
  416. // in case we have received an incomplete telnet option, unlikely, but possible
  417. _str += MIN(3, *len);
  418. *len -= MIN(3, *len);
  419. }
  420. }
  421. }
  422. static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) {
  423. int32_t retries = 0;
  424. uint32_t delay = TELNET_WAIT_TIME_MS;
  425. // only if we are not within interrupt context and interrupts are enabled
  426. if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
  427. do {
  428. _i16 result = sl_Send(sd, pBuf, len, 0);
  429. if (result > 0) {
  430. return true;
  431. }
  432. else if (SL_EAGAIN != result) {
  433. return false;
  434. }
  435. // start with the default delay and increment it on each retry
  436. mp_hal_delay_ms(delay++);
  437. } while (++retries <= TELNET_TX_RETRIES_MAX);
  438. }
  439. return false;
  440. }
  441. static void telnet_reset_buffer (void) {
  442. // erase any characters present in the current line
  443. memset (telnet_data.rxBuffer, '\b', TELNET_RX_BUFFER_SIZE / 2);
  444. telnet_data.rxWindex = TELNET_RX_BUFFER_SIZE / 2;
  445. // fake an "enter" key pressed to display the prompt
  446. telnet_data.rxBuffer[telnet_data.rxWindex++] = '\r';
  447. }