From d6eb00e18e0e8750ee880cbb52049b4b97610cdf Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Mon, 29 Dec 2025 02:02:28 +0300 Subject: [PATCH] Do not re-initialize TLS context every connection --- src/client/etcd_state_client.cpp | 28 +++++------------ src/client/http_client.cpp | 52 ++++++++++++++++++-------------- src/client/http_client.h | 3 +- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/client/etcd_state_client.cpp b/src/client/etcd_state_client.cpp index 1353d938..123c36e8 100644 --- a/src/client/etcd_state_client.cpp +++ b/src/client/etcd_state_client.cpp @@ -22,12 +22,12 @@ etcd_state_client_t::~etcd_state_client_t() stop_ws_keepalive(); if (etcd_watch_ws) { - http_close(etcd_watch_ws); + http_destroy(etcd_watch_ws); etcd_watch_ws = NULL; } if (keepalive_client) { - http_close(keepalive_client); + http_destroy(keepalive_client); keepalive_client = NULL; } #endif @@ -98,7 +98,7 @@ void etcd_state_client_t::etcd_call_oneshot(std::string etcd_address, std::strin json11::Json data; response->parse_json_response(err, data); callback(err, data); - http_close(http_cli); + http_destroy(http_cli); }; http_request(http_cli, etcd_address, req, { .timeout = timeout, .ssl = ssl, .ssl_ca = etcd_ca }, cb); } @@ -348,17 +348,16 @@ void etcd_state_client_t::start_etcd_watcher() } etcd_watches_initialised = 0; ws_alive = 1; - if (etcd_watch_ws) - { - http_close(etcd_watch_ws); - etcd_watch_ws = NULL; - } if (this->log_level > 1) { fprintf(stderr, "Trying to connect to etcd websocket at %s, watch from revision %ju/%ju/%ju\n", etcd_address.c_str(), etcd_watch_revision_config, etcd_watch_revision_osd, etcd_watch_revision_pg); } - etcd_watch_ws = open_websocket(tfd, etcd_address, etcd_api_path+"/watch", { .timeout = etcd_slow_timeout, .ssl = ssl, .ssl_ca = etcd_ca }, + if (!etcd_watch_ws) + etcd_watch_ws = http_init(tfd); + else + http_close(etcd_watch_ws); + open_websocket(etcd_watch_ws, etcd_address, etcd_api_path+"/watch", { .timeout = etcd_slow_timeout, .ssl = ssl, .ssl_ca = etcd_ca }, [this, cur_addr = selected_etcd_address](const http_response_t *msg) { if (msg->body.length()) @@ -402,7 +401,6 @@ void etcd_state_client_t::start_etcd_watcher() fprintf(stderr, "Revisions before %ju were compacted by etcd, reloading state\n", data["result"]["compact_revision"].uint64_value()); http_close(etcd_watch_ws); - etcd_watch_ws = NULL; etcd_watch_revision_config = etcd_watch_revision_osd = etcd_watch_revision_pg = 0; on_reload_hook(); } @@ -479,11 +477,6 @@ void etcd_state_client_t::start_etcd_watcher() fprintf(stderr, "Disconnected from etcd %s\n", cur_addr.c_str()); if (cur_addr == selected_etcd_address) selected_etcd_address = ""; - if (etcd_watch_ws) - { - http_close(etcd_watch_ws); - etcd_watch_ws = NULL; - } if (etcd_watches_initialised == 0) { // Connection not established, retry in @@ -560,11 +553,6 @@ void etcd_state_client_t::start_ws_keepalive() { fprintf(stderr, "Websocket ping failed, disconnecting from etcd %s\n", selected_etcd_address.c_str()); } - if (etcd_watch_ws) - { - http_close(etcd_watch_ws); - etcd_watch_ws = NULL; - } start_etcd_watcher(); } else diff --git a/src/client/http_client.cpp b/src/client/http_client.cpp index 6dd683c0..1ce97fe9 100644 --- a/src/client/http_client.cpp +++ b/src/client/http_client.cpp @@ -114,9 +114,13 @@ http_co_t *http_init(timerfd_manager_t *tfd) return handler; } -http_co_t* open_websocket(timerfd_manager_t *tfd, const std::string & host, const std::string & path, +void open_websocket(http_co_t *handler, const std::string & host, const std::string & path, const http_options_t & options, std::function response_callback) { + if (handler->state == HTTP_CO_KEEPALIVE && (handler->connected_host != host || handler->ssl != options.ssl)) + handler->close_connection(); + if (handler->state != HTTP_CO_KEEPALIVE && handler->state != HTTP_CO_CLOSED) + throw std::runtime_error("Attempt to open websocket on a keepalive stream"); std::string request = "GET "+path+" HTTP/1.1\r\n" "Host: "+host+"\r\n" "Upgrade: websocket\r\n" @@ -124,9 +128,6 @@ http_co_t* open_websocket(timerfd_manager_t *tfd, const std::string & host, cons "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" "Sec-WebSocket-Version: 13\r\n" "\r\n"; - http_co_t *handler = new http_co_t(); - handler->tfd = tfd; - handler->state = HTTP_CO_CLOSED; handler->host = host; handler->request_timeout = options.timeout < 0 ? -1 : (options.timeout == 0 ? DEFAULT_TIMEOUT : options.timeout); handler->want_streaming = false; @@ -135,8 +136,11 @@ http_co_t* open_websocket(timerfd_manager_t *tfd, const std::string & host, cons handler->ssl_ca = options.ssl_ca; handler->request = request; handler->response_callback = response_callback; + handler->ws_outbox = ""; + handler->response = ""; + handler->sent = 0; + handler->parsed = {}; handler->start_ws_connection(); - return handler; } void http_request(http_co_t *handler, const std::string & host, const std::string & request, @@ -249,11 +253,16 @@ void http_co_t::post_message(uint8_t type, const std::string & msg) stackout(); } -void http_close(http_co_t *handler) +void http_destroy(http_co_t *handler) { handler->end(); } +void http_close(http_co_t *handler) +{ + handler->close_connection(); +} + void http_response_t::parse_json_response(std::string & error, json11::Json & r) const { if (this->error != "") @@ -285,20 +294,14 @@ void http_response_t::parse_json_response(std::string & error, json11::Json & r) http_co_t::~http_co_t() { + close_connection(); #ifdef WITH_OPENSSL - ssl_bio = NULL; - if (ssl_cli) - { - SSL_free(ssl_cli); - ssl_cli = NULL; - } if (ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } #endif - close_connection(); } void http_co_t::close_connection() @@ -319,9 +322,9 @@ void http_co_t::close_connection() { // Frees client and bios at once SSL_free(ssl_cli); - ssl_bio = NULL; ssl_cli = NULL; } + ssl_bio = NULL; #endif state = HTTP_CO_CLOSED; connected_host = ""; @@ -377,16 +380,19 @@ void http_co_t::start_connection() // https://wiki.openssl.org/index.php/Hostname_validation if (ssl) { - ssl_ctx = SSL_CTX_new(TLS_method()); if (!ssl_ctx) - goto init_err; - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if (!SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION)) - goto init_err; - if ((ssl_ca != "") - ? !SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca.c_str(), NULL) - : !SSL_CTX_set_default_verify_paths(ssl_ctx)) - goto init_err; + { + ssl_ctx = SSL_CTX_new(TLS_method()); + if (!ssl_ctx) + goto init_err; + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + if (!SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION)) + goto init_err; + if ((ssl_ca != "") + ? !SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca.c_str(), NULL) + : !SSL_CTX_set_default_verify_paths(ssl_ctx)) + goto init_err; + } ssl_bio = BIO_new(BIO_s_socket()); if (!ssl_bio) goto init_err; diff --git a/src/client/http_client.h b/src/client/http_client.h index 1dfbe3ed..ae2fe80f 100644 --- a/src/client/http_client.h +++ b/src/client/http_client.h @@ -44,9 +44,10 @@ struct http_response_t struct http_co_t; http_co_t* http_init(timerfd_manager_t *tfd); -http_co_t* open_websocket(timerfd_manager_t *tfd, const std::string & host, const std::string & path, +void open_websocket(http_co_t *handler, const std::string & host, const std::string & path, const http_options_t & options, std::function on_message); void http_request(http_co_t *handler, const std::string & host, const std::string & request, const http_options_t & options, std::function response_callback); void http_post_message(http_co_t *handler, uint8_t type, const std::string & msg); void http_close(http_co_t *co); +void http_destroy(http_co_t *co);