From e463fe83565352ea20c464ab462700cc4e5dd494 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 9 Mar 2023 14:21:25 -0500 Subject: [PATCH] MT#55283 single-threaded lws_write() Avoid calling lws_write() from threads other than the service thread, as this might not be thread-safe. Instead store the values used for the HTTP response headers in the websocket_output, then trigger a "writable" callback, and finally do all the lws_write() calls from the service thread. Reported in #1624 Change-Id: Ifcb050193044e5543f750a12fb44f5e16d4c0a08 (cherry picked from commit b207d0c58678b9f06755e170585f8dd1574c9935) --- daemon/websocket.c | 78 ++++++++++++++++++++++++++------------------- include/websocket.h | 2 +- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/daemon/websocket.c b/daemon/websocket.c index 58018ff2a..a3b6ba8af 100644 --- a/daemon/websocket.c +++ b/daemon/websocket.c @@ -18,6 +18,9 @@ struct websocket_output { GString *str; size_t str_done; enum lws_write_protocol protocol; + int http_status; + const char *content_type; + ssize_t content_length; }; struct websocket_conn { @@ -217,6 +220,31 @@ static void websocket_process(void *p, void *up) { } +static const char *__websocket_write_http_response(struct websocket_conn *wc, int status, + const char *content_type, ssize_t content_length) +{ + uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, + *end = &buf[sizeof(buf) - LWS_PRE - 1]; + + if (lws_add_http_header_status(wc->wsi, status, &p, end)) + return "Failed to add HTTP status"; + if (content_type) + if (lws_add_http_header_by_token(wc->wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, + (const unsigned char *) content_type, + strlen(content_type), &p, end)) + return "Failed to add content-type"; + if (content_length >= 0) + if (lws_add_http_header_content_length(wc->wsi, content_length, &p, end)) + return "Failed to add HTTP headers to response"; + if (lws_finalize_http_header(wc->wsi, &p, end)) + return "Failed to write HTTP headers"; + + size_t len = p - start; + if (lws_write(wc->wsi, start, len, LWS_WRITE_HTTP_HEADERS) != len) + return "Failed to write HTTP headers"; + + return NULL; +} static int websocket_dequeue(struct websocket_conn *wc) { if (!wc) return 0; @@ -231,6 +259,15 @@ static int websocket_dequeue(struct websocket_conn *wc) { if (!wo->str) goto next; + if (wo->http_status) { + const char *err = __websocket_write_http_response(wc, wo->http_status, + wo->content_type, wo->content_length); + if (err) { + ilogs(http, LOG_ERR, "Failed to write HTTP response headers: %s", err); + goto next; + } + } + // allocate post-buffer g_string_set_size(wo->str, wo->str->len + LWS_SEND_BUFFER_POST_PADDING); size_t to_send = wo->str->len - wo->str_done - LWS_SEND_BUFFER_POST_PADDING; @@ -267,45 +304,23 @@ next: return ret; } -static const char *websocket_do_http_response(struct websocket_conn *wc, int status, const char *content_type, +void websocket_http_response(struct websocket_conn *wc, int status, const char *content_type, ssize_t content_length) { - uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + mutex_lock(&wc->lock); - if (lws_add_http_header_status(wc->wsi, status, &p, end)) - return "Failed to add HTTP status"; - if (content_type) - if (lws_add_http_header_by_token(wc->wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, - (const unsigned char *) content_type, - strlen(content_type), &p, end)) - return "Failed to add content-type"; - if (content_length >= 0) - if (lws_add_http_header_content_length(wc->wsi, content_length, &p, end)) - return "Failed to add HTTP headers to response"; - if (lws_finalize_http_header(wc->wsi, &p, end)) - return "Failed to write HTTP headers"; + struct websocket_output *wo = g_queue_peek_tail(&wc->output_q); - size_t len = p - start; - if (lws_write(wc->wsi, start, len, LWS_WRITE_HTTP_HEADERS) != len) - return "Failed to write HTTP headers"; + wo->http_status = status; + wo->content_type = content_type; + wo->content_length = content_length; - return NULL; -} -int websocket_http_response(struct websocket_conn *wc, int status, const char *content_type, - ssize_t content_length) -{ - const char *err = websocket_do_http_response(wc, status, content_type, content_length); - if (!err) - return 0; - ilogs(http, LOG_ERR, "Failed to write HTTP response headers: %s", err); - return -1; + mutex_unlock(&wc->lock); } const char *websocket_http_complete(struct websocket_conn *wc, int status, const char *content_type, ssize_t content_length, const char *content) { - if (websocket_http_response(wc, status, content_type, content_length)) - return "Failed to write response HTTP headers"; + websocket_http_response(wc, status, content_type, content_length); if (websocket_write_http(wc, content, 1)) return "Failed to write pong response"; return NULL; @@ -413,8 +428,7 @@ static void websocket_ng_send_ws(str *cookie, str *body, const endpoint_t *sin, } static void websocket_ng_send_http(str *cookie, str *body, const endpoint_t *sin, void *p1) { struct websocket_conn *wc = p1; - if (websocket_http_response(wc, 200, "application/x-rtpengine-ng", cookie->len + 1 + body->len)) - ilogs(http, LOG_WARN, "Failed to write HTTP headers"); + websocket_http_response(wc, 200, "application/x-rtpengine-ng", cookie->len + 1 + body->len); websocket_queue_raw(wc, cookie->s, cookie->len); websocket_queue_raw(wc, " ", 1); websocket_queue_raw(wc, body->s, body->len); diff --git a/include/websocket.h b/include/websocket.h index 03d5c66ea..d627dc9d1 100644 --- a/include/websocket.h +++ b/include/websocket.h @@ -48,7 +48,7 @@ int websocket_write_binary(struct websocket_conn *wc, const char *msg, size_t le size_t websocket_queue_len(struct websocket_conn *wc); // write HTTP response headers -int websocket_http_response(struct websocket_conn *wc, int status, const char *content_type, +void websocket_http_response(struct websocket_conn *wc, int status, const char *content_type, ssize_t content_length); #endif