From eae77c87679bcd63f5aacc2d45fb6061e41a9714 Mon Sep 17 00:00:00 2001 From: "hrushikesh.bhosale" Date: Mon, 15 Sep 2025 11:37:30 +0530 Subject: [PATCH] fix(esp_http_server): Fix async requests on same socket blocking issue 1. In async requests, if the two or more requests are made on same socket then it used to block the second request. 2. The main thread is used to block on select call. And there done no FD_SET for particular fd. Closes https://github.com/espressif/esp-idf/issues/16998 --- .../esp_http_server/src/esp_httpd_priv.h | 13 +++++++++++++ components/esp_http_server/src/httpd_main.c | 9 --------- components/esp_http_server/src/httpd_txrx.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/components/esp_http_server/src/esp_httpd_priv.h b/components/esp_http_server/src/esp_httpd_priv.h index 33af33c152..7262052fb8 100644 --- a/components/esp_http_server/src/esp_httpd_priv.h +++ b/components/esp_http_server/src/esp_httpd_priv.h @@ -41,6 +41,19 @@ extern "C" { /* Formats a log string to prepend context function name */ #define LOG_FMT(x) "%s: " x, __func__ +/** + * @brief Control message data structure for internal use. Sent to control socket. + */ +struct httpd_ctrl_data { + enum httpd_ctrl_msg { + HTTPD_CTRL_SHUTDOWN, + HTTPD_CTRL_WORK, + HTTPD_CTRL_MAX, + } hc_msg; + httpd_work_fn_t hc_work; + void *hc_work_arg; +}; + /** * @brief Thread related data for internal use */ diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index fd434e87ae..943075317f 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -133,15 +133,6 @@ exit: return ESP_FAIL; } -struct httpd_ctrl_data { - enum httpd_ctrl_msg { - HTTPD_CTRL_SHUTDOWN, - HTTPD_CTRL_WORK, - } hc_msg; - httpd_work_fn_t hc_work; - void *hc_work_arg; -}; - esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *arg) { if (handle == NULL || work == NULL) { diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index 1ca2165d71..04c74bbc81 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -12,6 +12,7 @@ #include #include "esp_httpd_priv.h" #include +#include "ctrl_sock.h" static const char *TAG = "httpd_txrx"; @@ -655,6 +656,11 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r) return ESP_ERR_INVALID_ARG; } + // Get server handle and control socket info before freeing the request + struct httpd_data *hd = (struct httpd_data *) r->handle; + int msg_fd = hd->msg_fd; + int port = hd->config.ctrl_port; + struct httpd_req_aux *ra = r->aux; ra->sd->for_async_req = false; @@ -662,6 +668,18 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r) free(r->aux); free(r); + // Send a dummy control message(httpd_ctrl_data) to unblock the main HTTP server task from the select() call. + // Since the current connection FD was marked as inactive for async requests, the main task + // 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}; + 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")); + return ESP_FAIL; + } + + ESP_LOGD(TAG, LOG_FMT("socket notification sent")); return ESP_OK; }