mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-08 12:10:59 +00:00
tcp_transport/ws_client: websockets now correctly handle messages longer than buffer
transport_ws can now be read multiple times in a row to read frames larger than the buffer. Added reporting of total payload length and offset to the user in websocket_client. Added local example test for long messages. Closes IDF-1083
This commit is contained in:
@@ -91,9 +91,11 @@ struct esp_websocket_client {
|
||||
char *tx_buffer;
|
||||
int buffer_size;
|
||||
ws_transport_opcodes_t last_opcode;
|
||||
int payload_len;
|
||||
int payload_offset;
|
||||
};
|
||||
|
||||
static uint64_t _tick_get_ms()
|
||||
static uint64_t _tick_get_ms(void)
|
||||
{
|
||||
return esp_timer_get_time()/1000;
|
||||
}
|
||||
@@ -112,6 +114,8 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
|
||||
event_data.data_ptr = data;
|
||||
event_data.data_len = data_len;
|
||||
event_data.op_code = client->last_opcode;
|
||||
event_data.payload_len = client->payload_len;
|
||||
event_data.payload_offset = client->payload_offset;
|
||||
|
||||
if ((err = esp_event_post_to(client->event_handle,
|
||||
WEBSOCKET_EVENTS, event,
|
||||
@@ -426,10 +430,38 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
{
|
||||
int rlen;
|
||||
client->payload_offset = 0;
|
||||
do {
|
||||
rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
|
||||
if (rlen < 0) {
|
||||
ESP_LOGE(TAG, "Error read data");
|
||||
esp_websocket_client_abort_connection(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
client->payload_len = esp_transport_ws_get_read_payload_len(client->transport);
|
||||
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
|
||||
|
||||
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen);
|
||||
|
||||
client->payload_offset += rlen;
|
||||
} while (client->payload_offset < client->payload_len);
|
||||
|
||||
// if a PING message received -> send out the PONG, this will not work for PING messages with payload longer than buffer len
|
||||
if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
|
||||
const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer;
|
||||
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, client->payload_len,
|
||||
client->config->network_timeout_ms);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void esp_websocket_client_task(void *pv)
|
||||
{
|
||||
const int lock_timeout = portMAX_DELAY;
|
||||
int rlen;
|
||||
esp_websocket_client_handle_t client = (esp_websocket_client_handle_t) pv;
|
||||
client->run = true;
|
||||
|
||||
@@ -480,31 +512,20 @@ static void esp_websocket_client_task(void *pv)
|
||||
ESP_LOGD(TAG, "Sending PING...");
|
||||
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms);
|
||||
}
|
||||
|
||||
if (read_select == 0) {
|
||||
ESP_LOGV(TAG, "Read poll timeout: skipping esp_transport_read()...");
|
||||
break;
|
||||
}
|
||||
client->ping_tick_ms = _tick_get_ms();
|
||||
|
||||
rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
|
||||
if (rlen < 0) {
|
||||
ESP_LOGE(TAG, "Error read data");
|
||||
if (esp_websocket_client_recv(client) == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Error receive data");
|
||||
esp_websocket_client_abort_connection(client);
|
||||
break;
|
||||
}
|
||||
if (rlen >= 0) {
|
||||
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
|
||||
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen);
|
||||
// if a PING message received -> send out the PONG
|
||||
if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
|
||||
const char *data = (rlen == 0) ? NULL : client->rx_buffer;
|
||||
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, rlen,
|
||||
client->config->network_timeout_ms);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WEBSOCKET_STATE_WAIT_TIMEOUT:
|
||||
|
||||
if (!client->config->auto_reconnect) {
|
||||
client->run = false;
|
||||
break;
|
||||
@@ -617,7 +638,8 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
|
||||
}
|
||||
memcpy(client->tx_buffer, data + widx, need_write);
|
||||
// send with ws specific way and specific opcode
|
||||
wlen = esp_transport_ws_send_raw(client->transport, opcode, (char *)client->tx_buffer, need_write, timeout);
|
||||
wlen = esp_transport_ws_send_raw(client->transport, opcode, (char *)client->tx_buffer, need_write,
|
||||
(timeout==portMAX_DELAY)? -1 : timeout * portTICK_PERIOD_MS);
|
||||
if (wlen <= 0) {
|
||||
ret = wlen;
|
||||
ESP_LOGE(TAG, "Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
|
||||
@@ -643,7 +665,8 @@ bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client)
|
||||
esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
esp_event_handler_t event_handler,
|
||||
void* event_handler_arg) {
|
||||
void *event_handler_arg)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
Reference in New Issue
Block a user