Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
5.4 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. /*
  2. TELNET MODULE
  3. Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. Parts of the code have been borrowed from Thomas Sarlandie's NetServer
  5. (https://github.com/sarfata/kbox-firmware/tree/master/src/esp)
  6. Module key prefix: tel
  7. */
  8. #if TELNET_SUPPORT
  9. #include <ESPAsyncTCP.h>
  10. AsyncServer * _telnetServer;
  11. AsyncClient * _telnetClients[TELNET_MAX_CLIENTS];
  12. bool _telnetFirst = true;
  13. // -----------------------------------------------------------------------------
  14. // Private methods
  15. // -----------------------------------------------------------------------------
  16. #if WEB_SUPPORT
  17. void _telnetWebSocketOnSend(JsonObject& root) {
  18. root["telVisible"] = 1;
  19. root["telSTA"] = getSetting("telSTA", TELNET_STA).toInt() == 1;
  20. }
  21. #endif
  22. void _telnetDisconnect(unsigned char clientId) {
  23. _telnetClients[clientId]->free();
  24. _telnetClients[clientId] = NULL;
  25. delete _telnetClients[clientId];
  26. wifiReconnectCheck();
  27. DEBUG_MSG_P(PSTR("[TELNET] Client #%d disconnected\n"), clientId);
  28. }
  29. bool _telnetWrite(unsigned char clientId, void *data, size_t len) {
  30. if (_telnetClients[clientId] && _telnetClients[clientId]->connected()) {
  31. return (_telnetClients[clientId]->write((const char*) data, len) > 0);
  32. }
  33. return false;
  34. }
  35. unsigned char _telnetWrite(void *data, size_t len) {
  36. unsigned char count = 0;
  37. for (unsigned char i = 0; i < TELNET_MAX_CLIENTS; i++) {
  38. if (_telnetWrite(i, data, len)) ++count;
  39. }
  40. return count;
  41. }
  42. void _telnetData(unsigned char clientId, void *data, size_t len) {
  43. // Skip first message since it's always garbage
  44. if (_telnetFirst) {
  45. _telnetFirst = false;
  46. return;
  47. }
  48. // Capture close connection
  49. char * p = (char *) data;
  50. // C-d is sent as two bytes (sometimes repeating)
  51. if (len >= 2) {
  52. if ((p[0] == 0xFF) && (p[1] == 0xEC)) {
  53. _telnetClients[clientId]->close(true);
  54. return;
  55. }
  56. }
  57. if ((strncmp(p, "close", 5) == 0) || (strncmp(p, "quit", 4) == 0)) {
  58. _telnetClients[clientId]->close();
  59. return;
  60. }
  61. // Inject into Embedis stream
  62. settingsInject(data, len);
  63. }
  64. void _telnetNewClient(AsyncClient *client) {
  65. if (client->localIP() != WiFi.softAPIP()) {
  66. // Telnet is always available for the ESPurna Core image
  67. #ifdef ESPURNA_CORE
  68. bool telnetSTA = true;
  69. #else
  70. bool telnetSTA = getSetting("telSTA", TELNET_STA).toInt() == 1;
  71. #endif
  72. if (!telnetSTA) {
  73. DEBUG_MSG_P(PSTR("[TELNET] Rejecting - Only local connections\n"));
  74. client->onDisconnect([](void *s, AsyncClient *c) {
  75. c->free();
  76. delete c;
  77. });
  78. client->close(true);
  79. return;
  80. }
  81. }
  82. for (unsigned char i = 0; i < TELNET_MAX_CLIENTS; i++) {
  83. if (!_telnetClients[i] || !_telnetClients[i]->connected()) {
  84. _telnetClients[i] = client;
  85. client->onAck([i](void *s, AsyncClient *c, size_t len, uint32_t time) {
  86. }, 0);
  87. client->onData([i](void *s, AsyncClient *c, void *data, size_t len) {
  88. _telnetData(i, data, len);
  89. }, 0);
  90. client->onDisconnect([i](void *s, AsyncClient *c) {
  91. _telnetDisconnect(i);
  92. }, 0);
  93. client->onError([i](void *s, AsyncClient *c, int8_t error) {
  94. DEBUG_MSG_P(PSTR("[TELNET] Error %s (%d) on client #%u\n"), c->errorToString(error), error, i);
  95. }, 0);
  96. client->onTimeout([i](void *s, AsyncClient *c, uint32_t time) {
  97. DEBUG_MSG_P(PSTR("[TELNET] Timeout on client #%u at %lu\n"), i, time);
  98. c->close();
  99. }, 0);
  100. DEBUG_MSG_P(PSTR("[TELNET] Client #%u connected\n"), i);
  101. // If there is no terminal support automatically dump info and crash data
  102. #if TERMINAL_SUPPORT == 0
  103. info();
  104. wifiDebug();
  105. debugDumpCrashInfo();
  106. debugClearCrashInfo();
  107. #endif
  108. _telnetFirst = true;
  109. wifiReconnectCheck();
  110. return;
  111. }
  112. }
  113. DEBUG_MSG_P(PSTR("[TELNET] Rejecting - Too many connections\n"));
  114. client->onDisconnect([](void *s, AsyncClient *c) {
  115. c->free();
  116. delete c;
  117. });
  118. client->close(true);
  119. }
  120. bool _telnetKeyCheck(const char * key) {
  121. return (strncmp(key, "telt", 3) == 0);
  122. }
  123. void _telnetBackwards() {
  124. moveSetting("telnetSTA", "telSTA"); // 1.14.0 -- 2018-06-26
  125. }
  126. // -----------------------------------------------------------------------------
  127. // Public API
  128. // -----------------------------------------------------------------------------
  129. bool telnetConnected() {
  130. for (unsigned char i = 0; i < TELNET_MAX_CLIENTS; i++) {
  131. if (_telnetClients[i] && _telnetClients[i]->connected()) return true;
  132. }
  133. return false;
  134. }
  135. unsigned char telnetWrite(unsigned char ch) {
  136. char data[1] = {ch};
  137. return _telnetWrite(data, 1);
  138. }
  139. void telnetSetup() {
  140. // Backwards compatibility
  141. _telnetBackwards();
  142. _telnetServer = new AsyncServer(TELNET_PORT);
  143. _telnetServer->onClient([](void *s, AsyncClient* c) {
  144. _telnetNewClient(c);
  145. }, 0);
  146. _telnetServer->begin();
  147. #if WEB_SUPPORT
  148. wsOnSendRegister(_telnetWebSocketOnSend);
  149. #endif
  150. settingsRegisterKeyCheck(_telnetKeyCheck);
  151. DEBUG_MSG_P(PSTR("[TELNET] Listening on port %d\n"), TELNET_PORT);
  152. }
  153. #endif // TELNET_SUPPORT