Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add memory_type Support for Flexible Memory Allocation in WebSocket Client to permit other memory type caps to be used (IDFGH-13127) #586

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
51 changes: 36 additions & 15 deletions components/esp_websocket_client/esp_websocket_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ static const char *TAG = "websocket_client";
#define WEBSOCKET_KEEP_ALIVE_INTERVAL (5)
#define WEBSOCKET_KEEP_ALIVE_COUNT (3)

#define VALID_MEMORY_FLAGS (MALLOC_CAP_EXEC | MALLOC_CAP_32BIT | MALLOC_CAP_8BIT | MALLOC_CAP_DMA | \
MALLOC_CAP_PID2 | MALLOC_CAP_PID3 | MALLOC_CAP_PID4 | MALLOC_CAP_PID5 | \
MALLOC_CAP_PID6 | MALLOC_CAP_PID7 | MALLOC_CAP_SPIRAM | MALLOC_CAP_INTERNAL | \
MALLOC_CAP_DEFAULT | MALLOC_CAP_IRAM_8BIT | MALLOC_CAP_RETENTION | \
MALLOC_CAP_RTCRAM | MALLOC_CAP_TCM | MALLOC_CAP_INVALID)

#define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \
action; \
Expand Down Expand Up @@ -137,6 +143,7 @@ struct esp_websocket_client {
int payload_offset;
esp_transport_keep_alive_t keep_alive_cfg;
struct ifreq *if_name;
int memory_type;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not against making the selection in runtime but, in other components, we make this choice in compile time through Kconfig.
Do you have a use case to have it set in runtime?

};

static uint64_t _tick_get_ms(void)
Expand All @@ -152,14 +159,14 @@ static esp_err_t esp_websocket_new_buf(esp_websocket_client_handle_t client, boo
free(client->tx_buffer);
}

client->tx_buffer = calloc(1, client->buffer_size);
client->tx_buffer = heap_caps_calloc(1, client->buffer_size,client->memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, return ESP_ERR_NO_MEM);
} else {
if (client->rx_buffer) {
free(client->rx_buffer);
}

client->rx_buffer = calloc(1, client->buffer_size);
client->rx_buffer = heap_caps_calloc(1, client->buffer_size,client->memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, return ESP_ERR_NO_MEM);
}
#endif
Expand Down Expand Up @@ -249,7 +256,7 @@ static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client
if (client->errormsg_buffer) {
free(client->errormsg_buffer);
}
client->errormsg_buffer = malloc(needed_size);
client->errormsg_buffer = heap_caps_malloc(needed_size,client->memory_type);
if (client->errormsg_buffer == NULL) {
client->errormsg_size = 0;
ESP_LOGE(TAG, "Failed to allocate...");
Expand All @@ -268,7 +275,7 @@ static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client
return ESP_OK;
}

static char *http_auth_basic(const char *username, const char *password)
static char *http_auth_basic(const char *username, const char *password, int memory_type)
{
int out;
char *user_info = NULL;
Expand All @@ -285,7 +292,7 @@ static char *http_auth_basic(const char *username, const char *password)
}

esp_crypto_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
digest = calloc(1, strlen(WS_HTTP_BASIC_AUTH) + n + 1);
digest = heap_caps_calloc(1, strlen(WS_HTTP_BASIC_AUTH) + n + 1,memory_type);
if (digest) {
strcpy(digest, WS_HTTP_BASIC_AUTH);
esp_crypto_base64_encode((unsigned char *)digest + 6, n, (size_t *)&out, (const unsigned char *)user_info, strlen(user_info));
Expand Down Expand Up @@ -332,7 +339,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c

if (cfg->username && cfg->password) {
free(cfg->auth);
cfg->auth = http_auth_basic(cfg->username, cfg->password);
cfg->auth = http_auth_basic(cfg->username, cfg->password, client->memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->auth, return ESP_ERR_NO_MEM);
}

Expand Down Expand Up @@ -619,7 +626,19 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand

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));
int memory_type = 0;
if ((config->memory_type & ~VALID_MEMORY_FLAGS) != 0) {
ESP_LOGW("TAG", "Invalid memory_type flags set, using default internal memory.\n");
euripedesrocha marked this conversation as resolved.
Show resolved Hide resolved
memory_type = MALLOC_CAP_DEFAULT;
} else if (config->memory_type == 0) {
memory_type = MALLOC_CAP_DEFAULT; //MALLOC_CAP_DEFAULT
ESP_LOGI("TAG","memory_type is not set, using MALLOC_CAP_DEFAULT memory [%d] versus external [%d].\n",memory_type,MALLOC_CAP_SPIRAM);
euripedesrocha marked this conversation as resolved.
Show resolved Hide resolved
} else {
memory_type = config->memory_type;
ESP_LOGI("TAG","memory_type is set to %d \n", config->memory_type);
}

esp_websocket_client_handle_t client = heap_caps_calloc(1, sizeof(struct esp_websocket_client),memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client, return NULL);

esp_event_loop_args_t event_args = {
Expand All @@ -633,6 +652,8 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
return NULL;
}

client->memory_type = memory_type;

if (config->keep_alive_enable == true) {
client->keep_alive_cfg.keep_alive_enable = true;
client->keep_alive_cfg.keep_alive_idle = (config->keep_alive_idle == 0) ? WEBSOCKET_KEEP_ALIVE_IDLE : config->keep_alive_idle;
Expand All @@ -641,15 +662,15 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
}

if (config->if_name) {
client->if_name = calloc(1, sizeof(struct ifreq) + 1);
client->if_name = heap_caps_calloc(1, sizeof(struct ifreq) + 1,memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->if_name, goto _websocket_init_fail);
memcpy(client->if_name, config->if_name, sizeof(struct ifreq));
}

client->lock = xSemaphoreCreateRecursiveMutex();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail);

client->config = calloc(1, sizeof(websocket_config_storage_t));
client->config = heap_caps_calloc(1, sizeof(websocket_config_storage_t),memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);

if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
Expand All @@ -661,7 +682,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
}

if (!config->disable_auto_reconnect && config->reconnect_timeout_ms <= 0) {
client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
ESP_LOGW(TAG, "`reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out %d (milliseconds)", WEBSOCKET_RECONNECT_TIMEOUT_MS);
} else {
client->wait_timeout_ms = config->reconnect_timeout_ms;
Expand Down Expand Up @@ -708,11 +729,11 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->errormsg_buffer = NULL;
client->errormsg_size = 0;
#ifndef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
client->rx_buffer = malloc(buffer_size);
client->rx_buffer = heap_caps_malloc(buffer_size,client->memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, {
goto _websocket_init_fail;
});
client->tx_buffer = malloc(buffer_size);
client->tx_buffer = heap_caps_malloc(buffer_size,client->memory_type);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, {
goto _websocket_init_fail;
});
Expand Down Expand Up @@ -842,7 +863,7 @@ esp_err_t esp_websocket_client_append_header(esp_websocket_client_handle_t clien

// If no previous headers exist
if (cfg->headers == NULL) {
cfg->headers = (char *)malloc(len);
cfg->headers = (char *)heap_caps_malloc(len,client->memory_type);
if (cfg->headers == NULL) {
ESP_LOGE(TAG, "Failed to allocate...");
return ESP_ERR_NO_MEM;
Expand All @@ -856,7 +877,7 @@ esp_err_t esp_websocket_client_append_header(esp_websocket_client_handle_t clien
size_t new_len = current_len + len;

// Allocate memory for new headers
char *new_headers = (char *)malloc(new_len);
char *new_headers = (char *)heap_caps_malloc(new_len,client->memory_type);
if (new_headers == NULL) {
ESP_LOGE(TAG, "Failed to allocate...");
return ESP_ERR_NO_MEM;
Expand Down Expand Up @@ -1143,7 +1164,7 @@ static int esp_websocket_client_send_close(esp_websocket_client_handle_t client,
uint8_t *close_status_data = NULL;
// RFC6455#section-5.5.1: The Close frame MAY contain a body (indicated by total_len >= 2)
if (total_len >= 2) {
close_status_data = calloc(1, total_len);
close_status_data = heap_caps_calloc(1, total_len,client->memory_type);;
ESP_WS_CLIENT_MEM_CHECK(TAG, close_status_data, return -1);
// RFC6455#section-5.5.1: The first two bytes of the body MUST be a 2-byte representing a status
uint16_t *code_network_order = (uint16_t *) close_status_data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ typedef struct {
int network_timeout_ms; /*!< Abort network operation if it is not completed after this value, in milliseconds (defaults to 10s) */
size_t ping_interval_sec; /*!< Websocket ping interval, defaults to 10 seconds if not set */
struct ifreq *if_name; /*!< The name of interface for data to go through. Use the default interface without setting */
int memory_type; /*!< The name of memory region type to be used in the heap_caps_malloc / heap_caps_calloc */
} esp_websocket_client_config_t;

/**
Expand Down
15 changes: 15 additions & 0 deletions docs/esp_websocket_client/en/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Features
* Supports WebSocket over TCP, TLS with mbedtls
* Easy to setup with URI
* Multiple instances (Multiple clients in one application)
* Use any Internal, External or any other CAPS memory allowed.

Configuration
-------------
Expand Down Expand Up @@ -51,6 +52,20 @@ overridden. Sample:
};
//WebSocket client will connect to websocket.org using port 4567

Memory Usage configurations:

.. code:: c

const esp_websocket_client_config_t ws_cfg = {
.uri = "ws://echo.websocket.org:123",
.port = 4567,
.memory_type = MALLOC_CAP_SPIRAM;
};
//WebSocket client will connect to websocket.org using port 4567
//Will use the external SPIRAM memory to allocate memory
//if .memory_type is not defined it will use default caps MALLOC_CAP_DEFAULT


TLS
^^^

Expand Down
Loading