hoeken / PsychicHttp

Simple + Robust HTTP/S server with websockets for ESP32 based on ESP-IDF http server.
GNU Lesser General Public License v3.0
94 stars 23 forks source link

Crash on event.send() after a while. #97

Open hitecSmartHome opened 1 month ago

hitecSmartHome commented 1 month ago

Hi! Amazing lib. I had a crash on event.send() the last day.

==================== CURRENT THREAD STACK =====================
#0  0x401d1464 in httpd_sess_get (hd=0x40000de8, sockfd=1073743892) at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c:167
#1  0x401d1ddc in httpd_socket_send (hd=0x40000de8, sockfd=1073743892, buf=0x3fff2434 <error: Cannot access memory at address 0x3fff2434>, buf_len=557, flags=0) at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_txrx.c:605
#2  0x401ad5f1 in PsychicEventSourceClient::sendEvent (this=0x3ffe4364, event=0x3fff2434 <error: Cannot access memory at address 0x3fff2434>) at lib/PsychicHttp/src/PsychicEventSource.cpp:151
#3  0x401ad792 in PsychicEventSource::send (this=0x3ffb3c58 <events>, message=<optimized out>, event=<optimized out>, id=1717333565, reconnect=0) at lib/PsychicHttp/src/PsychicEventSource.cpp:123
#4  0x40174017 in HsHServer::sendEvent (this=<optimized out>, type=0x3f409767 "ThermState", doc=...) at src/Server/Event.cpp:60
#5  0x40125f99 in <lambda()>::operator() (__closure=<optimized out>) at src/Components/Thermostat/Thermostat.cpp:156
#6  std::_Function_handler<void(), Thermostat::sendPeriodicData()::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at c:\users\pc\.platformio\packages       oolchain-xtensa-esp32@8.4.0+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:297
#7  0x400d4135 in std::function<void ()>::operator()() const (this=0x3ffd1000) at c:\users\pc\.platformio\packages      oolchain-xtensa-esp32@8.4.0+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:687
#8  0x40193027 in Sys::handleIntervals (this=0x3ffb3eac <hshSystem>) at src/System/SystemInterval.cpp:55
#9  0x4018c9e1 in Sys::loop (this=0x3ffb3eac <hshSystem>) at src/System/System.cpp:545
#10 0x4018ca08 in systemTask (pvParameters=<optimized out>) at src/System/System.cpp:554

I have this wrapper around events.send()

void HsHServer::sendEvent(const char* type, JsonDocument& doc) {
    if (!hasEventClient() && !serverRouter.connected()) { return; }
    const size_t size = measureJson(doc) + 1;
    char* buffer;
    if (!hshSystem.alloc(buffer, size)) { return; }
    serializeJson(doc, buffer, size);
    events.send(buffer, type, hshTime.getEpoch());
    serverRouter.redirect(buffer,type);
    free(buffer);
}

This method called frequently. The crash clearly was in here

#0  0x401d1464 in httpd_sess_get (hd=0x40000de8, sockfd=1073743892) at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c:167
#1  0x401d1ddc in httpd_socket_send (hd=0x40000de8, sockfd=1073743892, buf=0x3fff2434 <error: Cannot access memory at address 0x3fff2434>, buf_len=557, flags=0) at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_txrx.c:605
#2  0x401ad5f1 in PsychicEventSourceClient::sendEvent (this=0x3ffe4364, event=0x3fff2434 <error: Cannot access memory at address 0x3fff2434>) at lib/PsychicHttp/src/PsychicEventSource.cpp:151
#3  0x401ad792 in PsychicEventSource::send (this=0x3ffb3c58 <events>, message=<optimized out>, event=<optimized out>, id=1717333565, reconnect=0) at lib/PsychicHttp/src/PsychicEventSource.cpp:123

The esp was working great. It was up for 2 and a half days but crashed with this error.

Any idea?

hitecSmartHome commented 1 month ago

This portion of the code looks unfinished in PsychicEventSource.cpp

void PsychicEventSourceClient::sendEvent(const char *event) {
  if( !this->server() || !this->socket() ){
    return;
  }
  int result;
  do {
    result = httpd_socket_send(this->server(), this->socket(), event, strlen(event), 0);
  } while (result == HTTPD_SOCK_ERR_TIMEOUT);

  //if (result < 0)
  //error log here
}

httpd_socket_send API states the following

Returns:

Bytes : The number of bytes sent successfully
- HTTPD_SOCK_ERR_INVALID : Invalid arguments
- HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket send()
- HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket send()
- 
Note:
This API is not recommended to be used in any request handler.
Use this only for advanced use cases, wherein some asynchronous data is to be sent over a socket.
This internally calls the default send function, or the function registered by httpd_sess_set_send_override().

Why is there a do while loop? Can't we just do this?

void PsychicEventSourceClient::sendEvent(const char *event) {
  if( !this->server() || !this->socket() ){return;}
  httpd_socket_send(this->server(), this->socket(), event, strlen(event), 0);
}

or better

bool PsychicEventSourceClient::sendEvent(const char *event) {
  if( !this->server() || !this->socket() ){return false;}
  int result = httpd_socket_send(this->server(), this->socket(), event, strlen(event), 0);
  if( result == HTTPD_SOCK_ERR_INVALID || result == HTTPD_SOCK_ERR_TIMEOUT || result == HTTPD_SOCK_ERR_FAIL ){
      return false;
  }
  return true;
}
hitecSmartHome commented 1 month ago

For sure something is fishy in here