diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h index 2eafca1839..6765e7d19d 100644 --- a/components/esp_http_server/include/esp_http_server.h +++ b/components/esp_http_server/include/esp_http_server.h @@ -409,6 +409,14 @@ typedef struct httpd_uri { #endif } httpd_uri_t; +/** + * @brief Structure for holding list of clients + */ +typedef struct httpd_client_list { + size_t active_clients; /*!< number of active clients in this struct */ + int client_fds[]; /*!< array of file descriptors of all active clients */ +} httpd_client_list_t; + /** * @brief Registers a URI handler * @@ -1466,6 +1474,19 @@ esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd); */ esp_err_t httpd_sess_update_lru_counter(httpd_handle_t handle, int sockfd); +/** + * @brief Returns list of current socket descriptors of active sessions + * + * @param[in] handle Handle to server returned by httpd_start + * @param[in] max_fds Maximum number of socket fds the supplied list could hold + * @param[out] fd_list Structure holding socket descriptors + * + * @return + * - ESP_OK : Successfully retrieved session list + * - ESP_ERR_INVALID_ARG : Wrong arguments or list is longer than maximum + */ +esp_err_t httpd_get_client_list(httpd_handle_t handle, size_t max_fds, httpd_client_list_t *fd_list); + /** End of Session * @} */ @@ -1526,6 +1547,15 @@ typedef enum { HTTPD_WS_TYPE_PONG = 0xA } httpd_ws_type_t; +/** + * @brief Enum for client info description + */ +typedef enum { + HTTPD_WS_CLIENT_INVALID = 0x0, + HTTPD_WS_CLIENT_HTTP = 0x1, + HTTPD_WS_CLIENT_WEBSOCKET = 0x2, +} httpd_ws_client_info_t; + /** * @brief WebSocket frame format */ @@ -1593,11 +1623,11 @@ esp_err_t httpd_ws_send_frame_async(httpd_handle_t hd, int fd, httpd_ws_frame_t * @param[in] hd Server instance data * @param[in] fd Socket descriptor * @return - * - -1 : This fd is not a client of this httpd - * - 0 : This fd is an active client, protocol is not WS - * - 1 : This fd is an active client, protocol is WS + * - HTTPD_WS_CLIENT_INVALID : This fd is not a client of this httpd + * - HTTPD_WS_CLIENT_HTTP : This fd is an active client, protocol is not WS + * - HTTPD_WS_CLIENT_WEBSOCKET : This fd is an active client, protocol is WS */ -int httpd_ws_get_fd_info(httpd_handle_t hd, int fd) +httpd_ws_client_info_t httpd_ws_get_fd_info(httpd_handle_t hd, int fd); #endif /* CONFIG_HTTPD_WS_SUPPORT */ /** End of WebSocket related stuff diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index daa52c3122..af536a9d87 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -104,6 +104,25 @@ esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *ar return ESP_OK; } +esp_err_t httpd_get_client_list(httpd_handle_t handle, size_t max_fds, httpd_client_list_t *fd_list) +{ + struct httpd_data *hd = (struct httpd_data *) handle; + if (hd == NULL || max_fds == 0 || fd_list == NULL || max_fds < hd->config.max_open_sockets) { + return ESP_ERR_INVALID_ARG; + } + fd_list->active_clients = 0; + for (int i = 0; i < hd->config.max_open_sockets; ++i) { + if (hd->hd_sd[i].fd != -1) { + if (fd_list->active_clients < max_fds) { + fd_list->client_fds[fd_list->active_clients++] = hd->hd_sd[i].fd; + } else { + return ESP_ERR_INVALID_ARG; + } + } + } + return ESP_OK; +} + void *httpd_get_global_user_ctx(httpd_handle_t handle) { return ((struct httpd_data *)handle)->config.global_user_ctx; diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index 30ce87d468..e6aaa3c4c6 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -758,8 +758,8 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd) sd->ws_handler != NULL ? "Yes" : "No", sd->ws_close ? "Yes" : "No"); if (sd->ws_handshake_done && sd->ws_handler != NULL) { - ESP_LOGD(TAG, LOG_FMT("New WS request from existing socket")); ret = httpd_ws_get_frame_type(r); + ESP_LOGD(TAG, LOG_FMT("New WS request from existing socket, ws_type=%d"), ra->ws_type); /* Stop and return here immediately if it's a CLOSE frame */ if (ra->ws_type == HTTPD_WS_TYPE_CLOSE) { @@ -767,13 +767,13 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd) return ret; } - /* Ignore PONG frame, as this is a server */ if (ra->ws_type == HTTPD_WS_TYPE_PONG) { - return ret; + /* Pass the PONG frames to the handler as well, as user app might send PINGs */ + ESP_LOGD(TAG, LOG_FMT("Received PONG frame")); } /* Call handler if it's a non-control frame */ - if (ret == ESP_OK && ra->ws_type < HTTPD_WS_TYPE_CLOSE) { + if (ret == ESP_OK && ra->ws_type <= HTTPD_WS_TYPE_PONG) { ret = sd->ws_handler(r); } diff --git a/components/esp_http_server/src/httpd_ws.c b/components/esp_http_server/src/httpd_ws.c index 07b9824a26..7675f263c3 100644 --- a/components/esp_http_server/src/httpd_ws.c +++ b/components/esp_http_server/src/httpd_ws.c @@ -383,15 +383,15 @@ esp_err_t httpd_ws_get_frame_type(httpd_req_t *req) return ESP_OK; } -int httpd_ws_get_fd_info(httpd_handle_t hd, int fd) +httpd_ws_client_info_t httpd_ws_get_fd_info(httpd_handle_t hd, int fd) { struct sock_db *sess = httpd_sess_get(hd, fd); if (sess == NULL) { - return -1; + return HTTPD_WS_CLIENT_INVALID; } bool is_active_ws = sess->ws_handshake_done && (!sess->ws_close); - return is_active_ws ? 1 : 0; + return is_active_ws ? HTTPD_WS_CLIENT_WEBSOCKET : HTTPD_WS_CLIENT_HTTP; } #endif /* CONFIG_HTTPD_WS_SUPPORT */