From 1611386431324ea6d18840b6b7d7961d130f6a76 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 22 Aug 2019 17:39:20 +0200 Subject: [PATCH 1/4] ws_client: fix ping-pong mechanism to use mask, support reception of zero-payload PONG and sending non-zero-payload PING Closes https://github.com/espressif/esp-idf/issues/3890 Closes https://github.com/espressif/esp-idf/issues/4138 --- components/tcp_transport/transport_ws.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index ad6364daf5..febab05697 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -207,18 +207,17 @@ static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const ws_header[header_len++] = (uint8_t)((len >> 8) & 0xFF); ws_header[header_len++] = (uint8_t)((len >> 0) & 0xFF); } - if (len) { - if (mask_flag) { - mask = &ws_header[header_len]; - getrandom(ws_header + header_len, 4, 0); - header_len += 4; - for (i = 0; i < len; ++i) { - buffer[i] = (buffer[i] ^ mask[i % 4]); - } + if (mask_flag) { + mask = &ws_header[header_len]; + getrandom(ws_header + header_len, 4, 0); + header_len += 4; + + for (i = 0; i < len; ++i) { + buffer[i] = (buffer[i] ^ mask[i % 4]); } - } + if (esp_transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) { ESP_LOGE(TAG, "Error write header"); return -1; @@ -257,7 +256,7 @@ static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeou // This behaviour could however be altered in IDF 5.0, since a separate API for sending // messages with user defined opcodes has been introduced. ESP_LOGD(TAG, "Write PING message"); - return _ws_write(t, WS_OPCODE_PING | WS_FIN, 0, NULL, 0, timeout_ms); + return _ws_write(t, WS_OPCODE_PING | WS_FIN, WS_MASK, NULL, 0, timeout_ms); } return _ws_write(t, WS_OPCODE_BINARY | WS_FIN, WS_MASK, b, len, timeout_ms); } @@ -315,7 +314,7 @@ static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ } // Then receive and process payload - if ((rlen = esp_transport_read(ws->parent, buffer, payload_len, timeout_ms)) <= 0) { + if (payload_len != 0 && (rlen = esp_transport_read(ws->parent, buffer, payload_len, timeout_ms)) <= 0) { ESP_LOGE(TAG, "Error read data"); return rlen; } From 7a0587902416edb2815418284cd566f079e8ab0a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 22 Aug 2019 21:01:08 +0200 Subject: [PATCH 2/4] ws_client: fixed transport config option when server address configured as host, port, transport rather then uri closes https://github.com/espressif/esp-idf/issues/3891 --- components/esp_websocket_client/esp_websocket_client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 9ebef334bf..4a68265316 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -225,6 +225,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie client->lock = xSemaphoreCreateMutex(); ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail); + client->config = calloc(1, sizeof(websocket_config_storage_t)); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); + client->transport_list = esp_transport_list_init(); ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail); @@ -260,14 +263,11 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT); esp_transport_list_add(client->transport_list, wss, "wss"); - if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { + if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) { asprintf(&client->config->scheme, "wss"); ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } - client->config = calloc(1, sizeof(websocket_config_storage_t)); - ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); - if (config->uri) { if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) { ESP_LOGE(TAG, "Invalid uri"); From b529c6f282e870e74d1e47b5415359d1aa1323db Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 22 Aug 2019 21:25:20 +0200 Subject: [PATCH 3/4] ws_client: fixed path config issue when ws server configured using host and path instead of uri closes https://github.com/espressif/esp-idf/issues/3892 --- .../esp_websocket_client.c | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 4a68265316..ba29851eba 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -206,6 +206,18 @@ static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle return ESP_OK; } +static void set_websocket_client_path(esp_websocket_client_handle_t client) +{ + esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } + trans = esp_transport_list_get_transport(client->transport_list, "wss"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } +} + esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config) { esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client)); @@ -285,6 +297,10 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } + if (client->config->path) { + set_websocket_client_path(client); + } + client->keepalive_tick_ms = _tick_get_ms(); client->reconnect_tick_ms = _tick_get_ms(); client->ping_tick_ms = _tick_get_ms(); @@ -374,15 +390,7 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); } ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); - - esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); - if (trans) { - esp_transport_ws_set_path(trans, client->config->path); - } - trans = esp_transport_list_get_transport(client->transport_list, "wss"); - if (trans) { - esp_transport_ws_set_path(trans, client->config->path); - } + set_websocket_client_path(client); } if (puri.field_data[UF_PORT].off) { client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10); From 1a8e5a40d654171aeb8a3014cd61e89b887eca01 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 22 Aug 2019 22:00:41 +0200 Subject: [PATCH 4/4] ws_client: added subprotocol configuration option to websocket client closes https://github.com/espressif/esp-idf/issues/3893 --- .../esp_websocket_client.c | 23 +++++++++++-------- .../include/esp_websocket_client.h | 1 + 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index ba29851eba..c774a4e8f8 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -62,6 +62,7 @@ typedef struct { bool auto_reconnect; void *user_context; int network_timeout_ms; + char *subprotocol; } websocket_config_storage_t; typedef enum { @@ -173,6 +174,11 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c cfg->path = strdup(config->path); ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, return ESP_ERR_NO_MEM); } + if (config->subprotocol) { + free(cfg->subprotocol); + cfg->subprotocol = strdup(config->subprotocol); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->subprotocol, return ESP_ERR_NO_MEM); + } cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS; cfg->user_context = config->user_context; @@ -200,21 +206,20 @@ static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle free(cfg->scheme); free(cfg->username); free(cfg->password); + free(cfg->subprotocol); memset(cfg, 0, sizeof(websocket_config_storage_t)); free(client->config); client->config = NULL; return ESP_OK; } -static void set_websocket_client_path(esp_websocket_client_handle_t client) +static void set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, esp_transport_handle_t trans) { - esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); - if (trans) { + if (trans && client->config->path) { esp_transport_ws_set_path(trans, client->config->path); } - trans = esp_transport_list_get_transport(client->transport_list, "wss"); - if (trans) { - esp_transport_ws_set_path(trans, client->config->path); + if (trans && client->config->subprotocol) { + esp_transport_ws_set_subprotocol(trans, client->config->subprotocol); } } @@ -297,9 +302,8 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } - if (client->config->path) { - set_websocket_client_path(client); - } + set_websocket_transport_optional_settings(client, esp_transport_list_get_transport(client->transport_list, "ws")); + set_websocket_transport_optional_settings(client, esp_transport_list_get_transport(client->transport_list, "wss")); client->keepalive_tick_ms = _tick_get_ms(); client->reconnect_tick_ms = _tick_get_ms(); @@ -390,7 +394,6 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); } ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); - set_websocket_client_path(client); } if (puri.field_data[UF_PORT].off) { client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10); diff --git a/components/esp_websocket_client/include/esp_websocket_client.h b/components/esp_websocket_client/include/esp_websocket_client.h index 0439828382..631fb53bda 100644 --- a/components/esp_websocket_client/include/esp_websocket_client.h +++ b/components/esp_websocket_client/include/esp_websocket_client.h @@ -92,6 +92,7 @@ typedef struct { int buffer_size; /*!< Websocket buffer size */ const char *cert_pem; /*!< SSL Certification, PEM format as string, if the client requires to verify server */ esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */ + char *subprotocol; /*!< Websocket subprotocol */ } esp_websocket_client_config_t; /**