mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
fix(esp_http_server): merge release/v6.0 to resolve backport conflict
Merge branch 'release/v6.0' into backport-48352-resolve to resolve a conflict in esp_httpd_priv.h between this backport's sdkconfig.h include and the ctrl-socket semaphore's freertos/semphr.h include.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include "osal.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -130,9 +131,7 @@ struct httpd_data {
|
||||
httpd_config_t config; /*!< HTTPD server configuration */
|
||||
int listen_fd; /*!< Server listener FD */
|
||||
int ctrl_fd; /*!< Ctrl message receiver FD */
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
SemaphoreHandle_t ctrl_sock_semaphore; /*!< Ctrl socket semaphore */
|
||||
#endif
|
||||
SemaphoreHandle_t ctrl_sock_semaphore; /*!< Ctrl mbox slot reservation (sized to LWIP_UDP_RECVMBOX_SIZE) */
|
||||
int msg_fd; /*!< Ctrl message sender FD */
|
||||
struct thread_data hd_td; /*!< Information for the HTTPD thread */
|
||||
struct sock_db *hd_sd; /*!< The socket database */
|
||||
|
||||
@@ -50,7 +50,7 @@ void esp_http_server_dispatch_event(int32_t event_id, const void* event_data, si
|
||||
}
|
||||
#endif // CONFIG_HTTPD_ENABLE_EVENTS
|
||||
|
||||
static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
||||
static esp_err_t httpd_accept_conn(struct httpd_data *hd)
|
||||
{
|
||||
/* If no space is available for new session, close the least recently used one */
|
||||
if (hd->config.lru_purge_enable == true) {
|
||||
@@ -73,11 +73,13 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
||||
|
||||
struct sockaddr_storage addr_from;
|
||||
socklen_t addr_from_len = sizeof(addr_from);
|
||||
int new_fd = accept(listen_fd, (struct sockaddr *)&addr_from, &addr_from_len);
|
||||
|
||||
int new_fd = accept(hd->listen_fd, (struct sockaddr *)&addr_from, &addr_from_len);
|
||||
if (new_fd < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in accept (%d)"), errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("newfd = %d"), new_fd);
|
||||
|
||||
struct timeval tv;
|
||||
@@ -153,24 +155,27 @@ esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *ar
|
||||
.hc_work = work,
|
||||
.hc_work_arg = arg,
|
||||
};
|
||||
|
||||
/* Reserve a slot in the control mbox before sending. In blocking mode
|
||||
* the caller waits for a slot; in the default non-blocking mode we
|
||||
* fail fast so the caller knows the work was not queued. */
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
// Semaphore is acquired here and released after work function is executed.
|
||||
if (xSemaphoreTake(hd->ctrl_sock_semaphore, portMAX_DELAY) == pdTRUE) {
|
||||
const TickType_t wait = portMAX_DELAY;
|
||||
#else
|
||||
const TickType_t wait = 0;
|
||||
#endif
|
||||
int ret = cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg));
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("failed to queue work"));
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
#endif
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
if (xSemaphoreTake(hd->ctrl_sock_semaphore, wait) != pdTRUE) {
|
||||
ESP_LOGW(TAG, LOG_FMT("ctrl socket queue full, work not queued"));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGE(TAG, "Unable to acquire semaphore");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
|
||||
int ret = cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg));
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("failed to queue work"));
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t httpd_get_client_list(httpd_handle_t handle, size_t *fds, int *client_fds)
|
||||
@@ -210,16 +215,16 @@ static void httpd_process_ctrl_msg(struct httpd_data *hd)
|
||||
int ret = recv(hd->ctrl_fd, &msg, sizeof(msg), 0);
|
||||
if (ret <= 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("error in recv (%d)"), errno);
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
/* No packet was actually consumed from the mbox here, so this give
|
||||
* is unbalanced. It's tolerated because the counting semaphore is
|
||||
* capped at its max — excess gives become no-ops. Spurious recv
|
||||
* errors after select() are rare in practice. */
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (ret != sizeof(msg)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("incomplete msg"));
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,9 +242,7 @@ static void httpd_process_ctrl_msg(struct httpd_data *hd)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called for each session from httpd_server
|
||||
@@ -319,7 +322,7 @@ static esp_err_t httpd_server(struct httpd_data *hd)
|
||||
* process? */
|
||||
if (FD_ISSET(hd->listen_fd, &read_set)) {
|
||||
ESP_LOGD(TAG, LOG_FMT("processing listen socket %d"), hd->listen_fd);
|
||||
if (httpd_accept_conn(hd, hd->listen_fd) != ESP_OK) {
|
||||
if (httpd_accept_conn(hd) != ESP_OK) {
|
||||
ESP_LOGW(TAG, LOG_FMT("error accepting new connection"));
|
||||
}
|
||||
}
|
||||
@@ -472,6 +475,10 @@ static void httpd_delete(struct httpd_data *hd)
|
||||
free(hd->err_handler_fns);
|
||||
free(ra->resp_hdrs);
|
||||
free(hd->hd_sd);
|
||||
if (hd->ctrl_sock_semaphore) {
|
||||
vSemaphoreDelete(hd->ctrl_sock_semaphore);
|
||||
hd->ctrl_sock_semaphore = NULL;
|
||||
}
|
||||
|
||||
/* Free registered URI handlers */
|
||||
httpd_unregister_all_uri_handlers(hd);
|
||||
@@ -507,18 +514,18 @@ esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
|
||||
/* Failed to allocate memory */
|
||||
return ESP_ERR_HTTPD_ALLOC_MEM;
|
||||
}
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
/* Using a Counting Semaphore with count equals CONFIG_LWIP_UDP_RECVMBOX_SIZE
|
||||
* as the number of UDP messages which can be stored is equal to UDP mailbox size.
|
||||
* Using this, we can make sure that the work function is always received by the ctrl socket.
|
||||
*/
|
||||
/* Counting semaphore sized to the UDP control-socket recv mbox. Each
|
||||
* httpd_queue_work() take reserves one mbox slot; httpd_process_ctrl_msg()
|
||||
* gives one back per drain. This bounds the producer to the mbox capacity
|
||||
* and prevents silent lwIP-mbox overflow drops that would otherwise leak
|
||||
* the caller's async-send context. Always created so the default
|
||||
* (non-blocking) httpd_queue_work() path can also rely on it. */
|
||||
hd->ctrl_sock_semaphore = xSemaphoreCreateCounting(CONFIG_LWIP_UDP_RECVMBOX_SIZE, CONFIG_LWIP_UDP_RECVMBOX_SIZE);
|
||||
if (hd->ctrl_sock_semaphore == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create Semaphore");
|
||||
httpd_delete(hd);
|
||||
return ESP_ERR_HTTPD_ALLOC_MEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (httpd_server_init(hd) != ESP_OK) {
|
||||
httpd_delete(hd);
|
||||
@@ -532,6 +539,12 @@ esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
|
||||
httpd_thread, hd,
|
||||
hd->config.core_id,
|
||||
hd->config.task_caps) != ESP_OK) {
|
||||
/* Close the open socket */
|
||||
close(hd->listen_fd);
|
||||
/* Close the control socket */
|
||||
cs_free_ctrl_sock(hd->ctrl_fd);
|
||||
/* Close the message socket */
|
||||
close(hd->msg_fd);
|
||||
/* Failed to launch task */
|
||||
httpd_delete(hd);
|
||||
return ESP_ERR_HTTPD_TASK;
|
||||
@@ -554,9 +567,19 @@ esp_err_t httpd_stop(httpd_handle_t handle)
|
||||
struct httpd_ctrl_data msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.hc_msg = HTTPD_CTRL_SHUTDOWN;
|
||||
int ret = 0;
|
||||
if ((ret = cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg))) < 0) {
|
||||
|
||||
/* Reserve a slot in the ctrl mbox before sending so we never push past
|
||||
* its capacity. Blocking is safe: the httpd task is the consumer and
|
||||
* keeps draining the mbox until it observes HTTPD_CTRL_SHUTDOWN. */
|
||||
if (xSemaphoreTake(hd->ctrl_sock_semaphore, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to acquire ctrl socket semaphore");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int ret = cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg));
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to send shutdown signal err=%d", ret);
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -586,9 +609,6 @@ esp_err_t httpd_stop(httpd_handle_t handle)
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("server stopped"));
|
||||
#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING
|
||||
vSemaphoreDelete(hd->ctrl_sock_semaphore);
|
||||
#endif
|
||||
httpd_delete(hd);
|
||||
esp_http_server_dispatch_event(HTTP_SERVER_EVENT_STOP, NULL, 0);
|
||||
return ESP_OK;
|
||||
|
||||
@@ -738,9 +738,19 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r)
|
||||
// will now re-add this FD to its select() descriptor list. This ensures that subsequent requests
|
||||
// on the same FD are processed correctly
|
||||
struct httpd_ctrl_data msg = {.hc_msg = HTTPD_CTRL_MAX};
|
||||
|
||||
/* Reserve an mbox slot so we don't overrun ctrl_sock_semaphore's
|
||||
* accounting and starve concurrent httpd_queue_work() producers. The
|
||||
* httpd main task is the consumer and will drain the mbox shortly. */
|
||||
if (xSemaphoreTake(hd->ctrl_sock_semaphore, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGW(TAG, LOG_FMT("failed to acquire ctrl socket semaphore"));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int ret = cs_send_to_ctrl_sock(msg_fd, port, &msg, sizeof(msg));
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("failed to send socket notification"));
|
||||
xSemaphoreGive(hd->ctrl_sock_semaphore);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user