http_server: websocket server to support async send

This commit is contained in:
David Cermak
2020-03-11 10:03:12 +01:00
committed by bot
parent d7b3a051f0
commit 1b842ce1a8
9 changed files with 111 additions and 29 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ menu "HTTP Server"
config HTTPD_WS_SUPPORT
bool "WebSocket server support"
default y
default n
help
This sets the WebSocket server support.
@@ -1514,6 +1514,23 @@ esp_err_t httpd_ws_recv_frame(httpd_req_t *req, httpd_ws_frame_t *pkt, size_t ma
*/
esp_err_t httpd_ws_send_frame(httpd_req_t *req, httpd_ws_frame_t *pkt);
/**
* @brief Low level send of a WebSocket frame out of the scope of current request
* using internally configured httpd send function
*
* This API should rarely be called directly, with an exception of asynchronous send using httpd_queue_work.
*
* @param[in] hd Server instance data
* @param[in] fd Socket descriptor for sending data
* @param[in] frame WebSocket frame
* @return
* - ESP_OK : On successful
* - ESP_FAIL : When socket errors occurs
* - ESP_ERR_INVALID_STATE : Handshake was already done beforehand
* - ESP_ERR_INVALID_ARG : Argument is invalid (null or non-WebSocket)
*/
esp_err_t httpd_ws_send_frame_async(httpd_handle_t hd, int fd, httpd_ws_frame_t *frame);
#endif /* CONFIG_HTTPD_WS_SUPPORT */
/** End of WebSocket related stuff
* @}
@@ -690,7 +690,9 @@ static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
ra->first_chunk_sent = 0;
ra->req_hdrs_count = 0;
ra->resp_hdrs_count = 0;
#if CONFIG_HTTPD_WS_SUPPORT
ra->ws_handshake_detect = false;
#endif
memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
}
@@ -703,11 +705,13 @@ static void httpd_req_cleanup(httpd_req_t *r)
httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
}
#if CONFIG_HTTPD_WS_SUPPORT
/* Close the socket when a WebSocket Close request is received */
if (ra->sd->ws_close) {
ESP_LOGD(TAG, LOG_FMT("Try closing WS connection at FD: %d"), ra->sd->fd);
httpd_sess_trigger_close(r->handle, ra->sd->fd);
}
#endif
/* Retrieve session info from the request into the socket database. */
ra->sd->ctx = r->sess_ctx;
+1 -1
View File
@@ -279,7 +279,6 @@ esp_err_t httpd_uri(struct httpd_data *hd)
{
httpd_uri_t *uri = NULL;
httpd_req_t *req = &hd->hd_req;
struct httpd_req_aux *aux = req->aux;
struct http_parser_url *res = &hd->hd_req_aux.url_parse_res;
/* For conveying URI not found/method not allowed */
@@ -313,6 +312,7 @@ esp_err_t httpd_uri(struct httpd_data *hd)
/* Final step for a WebSocket handshake verification */
#ifdef CONFIG_HTTPD_WS_SUPPORT
struct httpd_req_aux *aux = req->aux;
if (uri->is_websocket && aux->ws_handshake_detect && uri->method == HTTP_GET) {
ESP_LOGD(TAG, LOG_FMT("Responding WS handshake to sock %d"), aux->sd->fd);
esp_err_t ret = httpd_ws_respond_server_handshake(&hd->hd_req);
+13 -3
View File
@@ -26,7 +26,7 @@
#ifdef CONFIG_HTTPD_WS_SUPPORT
#define TAG "httpd_ws"
static const char *TAG="httpd_ws";
/*
* Bit masks for WebSocket frames.
@@ -266,6 +266,11 @@ esp_err_t httpd_ws_send_frame(httpd_req_t *req, httpd_ws_frame_t *frame)
if (ret != ESP_OK) {
return ret;
}
return httpd_ws_send_frame_async(req->handle, httpd_req_to_sockfd(req), frame);
}
esp_err_t httpd_ws_send_frame_async(httpd_handle_t hd, int fd, httpd_ws_frame_t *frame)
{
if (!frame) {
ESP_LOGW(TAG, LOG_FMT("Argument is invalid"));
return ESP_ERR_INVALID_ARG;
@@ -299,15 +304,20 @@ esp_err_t httpd_ws_send_frame(httpd_req_t *req, httpd_ws_frame_t *frame)
/* WebSocket server does not required to mask response payload, so leave the MASK bit as 0. */
header_buf[1] &= (~HTTPD_WS_MASK_BIT);
struct sock_db *sess = httpd_sess_get(hd, fd);
if (!sess) {
return ESP_ERR_INVALID_ARG;
}
/* Send off header */
if (httpd_send(req, (const char *)header_buf, tx_len) < 0) {
if (sess->send_fn(hd, fd, (const char *)header_buf, tx_len, 0) < 0) {
ESP_LOGW(TAG, LOG_FMT("Failed to send WS header"));
return ESP_FAIL;
}
/* Send off payload */
if(frame->len > 0 && frame->payload != NULL) {
if (httpd_send(req, (const char *)frame->payload, frame->len) < 0) {
if (sess->send_fn(hd, fd, (const char *)frame->payload, frame->len, 0) < 0) {
ESP_LOGW(TAG, LOG_FMT("Failed to send WS payload"));
return ESP_FAIL;
}