Преглед изворни кода

esp_http_server: Add Websocket API to return list of active clients

Closes https://github.com/espressif/esp-idf/issues/5406
David Cermak пре 5 година
родитељ
комит
fbf2680427

+ 34 - 4
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

+ 19 - 0
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;

+ 4 - 4
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);
         }
 

+ 3 - 3
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 */