@MicroController
@cermak
Now that i changed my reception handler to eliminate static global variables, this error appears when I receive a ping from my app on my phone. Previously, the same ping sent by the app worked perfectly.
Aside from the ping, everything seems to be working fine, both sending and receiving. The ping is received 30 seconds after the client connects. I don't know if this happens with the other control frames, but it probably does.
This error alone When I just wait for the ping without sending anything other than opening the connection and receiving the server state.
W (42702) httpd_ws: httpd_ws_recv_frame: WS frame is not properly masked.
or this error When I send other commands after opening the connection and receiving the server state:
W (145027) httpd_ws: httpd_ws_recv_frame: WS frame is not properly masked.
W (145034) WSS_SERVER: httpd_ws_recv_frame() nao conseguiu pegar o tamanho da mensagem recebida. Error: ESP_ERR_INVALID_STATE
Problem here.
Stack variables and calling httpd_ws_recv_frame() two times:
Code: Select all
static esp_err_t get_clients_message_handler(httpd_req_t* req)
{
ESP_LOGI(TAG, LOG_USER("FUNCTION: %s"), __func__ );
ESP_LOGI(TAG, LOG_USER("[%s]req->method = %d\n"), __func__, req->method);
if (req->method == HTTP_GET)
{
char message[50];
int sockfd = httpd_req_to_sockfd(req);
ESP_LOGI(TAG, LOG_USER("New Connection Was Opened"));
ESP_LOGI(TAG, LOG_USER("New Connection Socket: %d\n"), sockfd);
bool code = ws_server_users_login(req, message, sizeof(message));
if (code)
{
add_ws_client_to_list(sockfd);
resp_Ws_Error_Message_Sync(req, message, command_error);
return ESP_OK;
}
else
{
ESP_LOGI(TAG, LOG_USER("Message: %s\n"), message);
resp_Ws_Error_Message_Sync(req, message, command_error);
ESP_LOGI(TAG, LOG_USER("SEND CLOSE FRAME"));
esp_err_t ret = send_close_frame( unexpected_condition_code, message, sockfd ); // send_close_frame( normal_closure, NULL, sockfd );
ESP_LOGI(TAG, LOG_USER("Send Close Frame: %s\n"), esp_err_to_name(ret));
return ESP_FAIL;
}
}
httpd_ws_frame_t ws_pkt;
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 0);
if (ret != ESP_OK)
{
ESP_LOGW(TAG, "httpd_ws_recv_frame() nao conseguiu pegar o tamanho da mensagem recebida. Error: %s", esp_err_to_name(ret));
return ret;
}
if (ws_pkt.len > 125)
{
ESP_LOGW(TAG, "httpd_ws_recv_frame(), ws_pkt.len > 125 bytes. Rejeitando mensagem. ws_pkt.len: %d", ws_pkt.len);
return ESP_OK;
//return ESP_ERR_INVALID_SIZE;
}
// Garante que o buffer tenha pelo menos 1 byte para evitar erro de compilação/execução se len for 0
size_t buf_capacity = (ws_pkt.len > 0) ? ws_pkt.len : 1;
uint8_t buf[buf_capacity];
memset(buf, 0, buf_capacity);
ws_pkt.payload = buf;
// Passa buf_capacity para garantir que o driver tenha onde escrever se len > 0
// Se len for 0, o driver apenas finaliza a leitura do cabeçalho
ret = httpd_ws_recv_frame(req, &ws_pkt, ws_pkt.len);
if (ret != ESP_OK)
{
#if webSocketDebug
ESP_LOGI(TAG, LOG_USER("httpd_ws_recv_frame failed with: %s\n"), esp_err_to_name(ret));
#endif
return ret;
}
#if webSocketDebug
printFrame(&ws_pkt, "Received Client Frame", req);
#endif
#if enable_handle_ws_control_frames
if (ws_pkt.type == HTTPD_WS_TYPE_PING || ws_pkt.type == HTTPD_WS_TYPE_PONG || ws_pkt.type == HTTPD_WS_TYPE_CLOSE)
return control_frames_handler(req, &ws_pkt); // Control frames = HTTPD_WS_TYPE_PING or HTTPD_WS_TYPE_PONG or HTTPD_WS_TYPE_CLOSE.
#endif
// Other frames types = HTTPD_WS_TYPE_BINARY or HTTPD_WS_TYPE_TEXT or HTTPD_WS_TYPE_CONTINUE.
if (ws_pkt.type != HTTPD_WS_TYPE_BINARY) // if( ws_pkt.type != HTTPD_WS_TYPE_BINARY || ws_pkt.type != HTTPD_WS_TYPE_TEXT )
{
int fd = httpd_req_to_sockfd(req);
ESP_LOGI(TAG, LOG_USER("HTTPD_WS_TYPE != HTTPD_WS_TYPE_BINARY: %d"), ws_pkt.type);
ESP_LOGI(TAG, LOG_USER("SOCKET: %d\n"), fd);
resp_Ws_Error_Message_Sync(req, "WebSocket Type Not Binary!!!", command_error);
return ESP_FAIL;
}
// PROTEÇÃO
// Só entra aqui se for BINARY e tiver pelo menos 1 byte de conteúdo.
// Isso impede que frames BINARY vazios ou resíduos do buffer estático
// disparem o ponteiro de função.
if (ws_pkt.len > 0)
{
uint8_t comando = ws_pkt.payload[0];
if (comando < web_comm_t_array_size_t)
{
// Antes de executar, você pode limpar o buffer para a PRÓXIMA vez
// Mas o mais importante é que agora 'comando' é garantidamente deste frame.
ret = func_pointer[comando](req, comando, &ws_pkt);
#if webSocketDebug
ESP_LOGI(TAG, LOG_USER("ret select_func = %d\n"), ret);
#endif
return ESP_OK;
}
else
{
#if webSocketDebug
ESP_LOGE(TAG, "Error: Function Index out of allowable range!!! ws_pkt.payload[0] = %u\n", ws_pkt.payload[0]);
#endif
char err_msg[100];
snprintf(err_msg, sizeof(err_msg), "Error: Function Index out of allowable range!!! ws_pkt.payload[0] = %u", ws_pkt.payload[0]);
resp_Ws_Error_Message_Sync(req, err_msg, command_error);
return ESP_FAIL;
}
}
else if (ws_pkt.len == 0)
{
ESP_LOGW(TAG, "Frame binário vazio recebido, ignorando processamento de comando.");
return ESP_OK;
}
return ESP_OK;
}
That's how it worked with static variables:
Code: Select all
static uint8_t buf[128] = { 0 };
static httpd_ws_frame_t ws_pkt;
static esp_err_t get_clients_message_handler(httpd_req_t* req)
{
ESP_LOGI(TAG, LOG_USER("FUNCTION: %s"), __func__ );
ESP_LOGI(TAG, LOG_USER("[%s]req->method = %d\n"), __func__, req->method);
if (req->method == HTTP_GET)
{
char message[50];
int sockfd = httpd_req_to_sockfd(req);
ESP_LOGI(TAG, LOG_USER("New Connection Was Opened"));
ESP_LOGI(TAG, LOG_USER("New Connection Socket: %d\n"), sockfd);
bool code = ws_server_users_login(req, message, sizeof(message));
if (code)
{
add_ws_client_to_list(sockfd);
resp_Ws_Error_Message_Sync(req, message, command_error);
return ESP_OK;
}
else
{
ESP_LOGI(TAG, LOG_USER("Message: %s\n"), message);
resp_Ws_Error_Message_Sync(req, message, command_error);
ESP_LOGI(TAG, LOG_USER("SEND CLOSE FRAME"));
esp_err_t ret = send_close_frame( unexpected_condition_code, message, sockfd ); // send_close_frame( normal_closure, NULL, sockfd );
ESP_LOGI(TAG, LOG_USER("Send Close Frame: %s\n"), esp_err_to_name(ret));
return ESP_FAIL;
}
}
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
ws_pkt.payload = buf;
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, sizeof(buf));
if (ret != ESP_OK)
{
#if webSocketDebug
ESP_LOGI(TAG, LOG_USER("httpd_ws_recv_frame failed with: %s\n"), esp_err_to_name(ret));
#endif
return ret;
}
#if webSocketDebug
printFrame(&ws_pkt, "Received Client Frame", req);
#endif
#if enable_handle_ws_control_frames
if (ws_pkt.type == HTTPD_WS_TYPE_PING || ws_pkt.type == HTTPD_WS_TYPE_PONG || ws_pkt.type == HTTPD_WS_TYPE_CLOSE)
return control_frames_handler(req, &ws_pkt); // Control frames = HTTPD_WS_TYPE_PING or HTTPD_WS_TYPE_PONG or HTTPD_WS_TYPE_CLOSE.
#endif
// Other frames types = HTTPD_WS_TYPE_BINARY or HTTPD_WS_TYPE_TEXT or HTTPD_WS_TYPE_CONTINUE.
if (ws_pkt.type != HTTPD_WS_TYPE_BINARY) // if( ws_pkt.type != HTTPD_WS_TYPE_BINARY || ws_pkt.type != HTTPD_WS_TYPE_TEXT )
{
int fd = httpd_req_to_sockfd(req);
ESP_LOGI(TAG, LOG_USER("HTTPD_WS_TYPE != HTTPD_WS_TYPE_BINARY: %d"), ws_pkt.type);
ESP_LOGI(TAG, LOG_USER("SOCKET: %d\n"), fd);
resp_Ws_Error_Message_Sync(req, "WebSocket Type Not Binary!!!", command_error);
return ESP_FAIL;
}
// The first payload byte is a command, the rest of the bytes are data.
if( (ws_pkt.payload[0] >= 0) && (ws_pkt.payload[0] < web_comm_t_array_size_t) ) // func_index = ws_pkt.payload[0].
{
ret = func_pointer[ ws_pkt.payload[0] ]( req, ws_pkt.payload[0] );
#if webSocketDebug
ESP_LOGI(TAG, LOG_USER("ret select_func = %d\n"), ret);
#endif
return ESP_OK; // return ret;
}
else
{
#if webSocketDebug
ESP_LOGE(TAG, "Error: Function Index out of allowable range!!! ws_pkt.payload[0] = %u\n", ws_pkt.payload[0]);
#endif
char err_msg[100];
snprintf(err_msg, sizeof(err_msg), "Error: Function Index out of allowable range!!! ws_pkt.payload[0] = %u", ws_pkt.payload[0]);
resp_Ws_Error_Message_Sync(req, err_msg, command_error);
return ESP_FAIL;
}
}
Note:
.handle_ws_control_frames = true,
ESP-IDF v5.5.1
ESP32-S3