From 55dd3c8b77877b49dd11c0545076b97f1358c96f Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 25 Mar 2020 21:22:25 +0100 Subject: [PATCH] ws_client: fix fragmented send setting proper opcodes Previous implementation violated the RFC by having both the actual opcode and WS_FIN flag set for all fragments of a message. Fixed by setting the opcode only for the first fragment and WS_FIN for the last one Closes IDFGH-2938 Closes https://github.com/espressif/esp-idf/issues/4974 --- .../esp_websocket_client/esp_websocket_client.c | 13 ++++++++----- components/tcp_transport/include/esp_transport_ws.h | 1 + components/tcp_transport/transport_ws.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 10efde008c..ab9271e990 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -452,7 +452,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client) // 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, + esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG | WS_TRANSPORT_OPCODES_FIN, data, client->payload_len, client->config->network_timeout_ms); } @@ -510,7 +510,7 @@ static void esp_websocket_client_task(void *pv) if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) { client->ping_tick_ms = _tick_get_ms(); ESP_LOGD(TAG, "Sending PING..."); - esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms); + esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms); } if (read_select == 0) { @@ -630,23 +630,26 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c ESP_LOGE(TAG, "Invalid transport"); goto unlock_and_return; } - - + uint32_t current_opcode = opcode; while (widx < len) { if (need_write > client->buffer_size) { need_write = client->buffer_size; + } else { + current_opcode |= WS_TRANSPORT_OPCODES_FIN; } 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, + wlen = esp_transport_ws_send_raw(client->transport, current_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); goto unlock_and_return; } + current_opcode = 0; widx += wlen; need_write = len - widx; + } ret = widx; unlock_and_return: diff --git a/components/tcp_transport/include/esp_transport_ws.h b/components/tcp_transport/include/esp_transport_ws.h index 3e4a46febb..ab82fd9c22 100644 --- a/components/tcp_transport/include/esp_transport_ws.h +++ b/components/tcp_transport/include/esp_transport_ws.h @@ -20,6 +20,7 @@ typedef enum ws_transport_opcodes { WS_TRANSPORT_OPCODES_CLOSE = 0x08, WS_TRANSPORT_OPCODES_PING = 0x09, WS_TRANSPORT_OPCODES_PONG = 0x0a, + WS_TRANSPORT_OPCODES_FIN = 0x80, } ws_transport_opcodes_t; /** diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index 0f5fa82fbf..ea5ee29bc1 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -259,7 +259,7 @@ int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t o return ESP_ERR_INVALID_ARG; } ESP_LOGD(TAG, "Sending raw ws message with opcode %d", op_code); - return _ws_write(t, op_code | WS_FIN, WS_MASK, b, len, timeout_ms); + return _ws_write(t, op_code, WS_MASK, b, len, timeout_ms); } static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms)