0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-28 14:42:31 +00:00
netdata_netdata/web/server/web_client_cache.c
thiagoftsm b6088e08a7 SSL implementation for Netdata ()
* SSL implementation for Netdata

* Upload of fixes asked by @paulkatsoulakis and @cakrit

* Fix local computer

* Adding openssl to webserver

* fixing..

* HTTPS almost there

* Codacity

* HTTPS day 3

* HTTPS without Bio step 1

* HTTPS without Bio step 2

* HTTPS without Bio step 3

* HTTPS without Bio step 4

* HTTPS without Bio step 5

* HTTPS without Bio step 6

* HTTPS without Bio step 7

* HTTPS without Bio step 8

* HTTPS without Bio step 9

* HTTPS without Bio step 10

* SSL on streaming 1

* Daily pull

* HTTPS without Bio step 11

* HTTPS without Bio step 12

* HTTPS without Bio step 13

* HTTPS without Bio step 14

* SSL_Interception change documentation

* HTTPS without Bio step 15

* HTTPS without Bio step 16

* SSL_Interception fix codacity

* SSL_Interception fix doc

* SSL_Interception comments

* SSL_Interception fixing problems!

* SSL_Interception killing bugs

* SSL_Interception changing parameter

* SSL_Implementation documentation and script

* SSL_Implementation multiple fixes

* SSL_Implementation installer and cipher

* SSL_Implementation Redirect 301

* SSL_Implementation webserver doc and install-or-update.sh

* SSL_Implementation error 00000001:lib(0):func(0):reason(1)

* SSL_Implementation web server doc

* SSL_Implementation SEGFAULT on Fedora

* SSL_Implementation fix ^SSL=force|optional

* SSL_Implementation Redirect and Ciphers

* SSL_Implementation race condition 1

* SSL_Implementation Fix Location

* SSL_Implementation Fix Location 2

* SSL_Implementation Fix stream

* SSL_Implementation Fix stream 2

* SSL_Implementation Fix stream 3

* SSL_Implementation last problems!

* SSL_Implementation adjusts to commit!

* SSL_Implementation documentation permission!

* SSL_Implementation documentation permission 2!

* SSL_Implementation documentation permission 3!
2019-05-31 16:27:35 +02:00

269 lines
8.2 KiB
C

// SPDX-License-Identifier: GPL-3.0-or-later
#define WEB_SERVER_INTERNALS 1
#include "web_client_cache.h"
// ----------------------------------------------------------------------------
// allocate and free web_clients
#ifdef ENABLE_HTTPS
static void web_client_reuse_ssl(struct web_client *w) {
if (netdata_srv_ctx) {
if (w->ssl.conn) {
SSL_clear(w->ssl.conn);
}
}
}
#endif
static void web_client_zero(struct web_client *w) {
// zero everything about it - but keep the buffers
// remember the pointers to the buffers
BUFFER *b1 = w->response.data;
BUFFER *b2 = w->response.header;
BUFFER *b3 = w->response.header_output;
// empty the buffers
buffer_flush(b1);
buffer_flush(b2);
buffer_flush(b3);
freez(w->user_agent);
// zero everything
memset(w, 0, sizeof(struct web_client));
// restore the pointers of the buffers
w->response.data = b1;
w->response.header = b2;
w->response.header_output = b3;
}
static void web_client_free(struct web_client *w) {
buffer_free(w->response.header_output);
buffer_free(w->response.header);
buffer_free(w->response.data);
freez(w->user_agent);
#ifdef ENABLE_HTTPS
if ((!web_client_check_unix(w)) && ( netdata_srv_ctx )) {
if (w->ssl.conn) {
SSL_free(w->ssl.conn);
w->ssl.conn = NULL;
}
}
#endif
freez(w);
}
static struct web_client *web_client_alloc(void) {
struct web_client *w = callocz(1, sizeof(struct web_client));
w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE);
return w;
}
// ----------------------------------------------------------------------------
// web clients caching
// When clients connect and disconnect, avoid allocating and releasing memory.
// Instead, when new clients get connected, reuse any memory previously allocated
// for serving web clients that are now disconnected.
// The size of the cache is adaptive. It caches the structures of 2x
// the number of currently connected clients.
// Comments per server:
// SINGLE-THREADED : 1 cache is maintained
// MULTI-THREADED : 1 cache is maintained
// STATIC-THREADED : 1 cache for each thred of the web server
__thread struct clients_cache web_clients_cache = {
.pid = 0,
.used = NULL,
.used_count = 0,
.avail = NULL,
.avail_count = 0,
.allocated = 0,
.reused = 0
};
inline void web_client_cache_verify(int force) {
#ifdef NETDATA_INTERNAL_CHECKS
static __thread size_t count = 0;
count++;
if(unlikely(force || count > 1000)) {
count = 0;
struct web_client *w;
size_t used = 0, avail = 0;
for(w = web_clients_cache.used; w ; w = w->next) used++;
for(w = web_clients_cache.avail; w ; w = w->next) avail++;
info("web_client_cache has %zu (%zu) used and %zu (%zu) available clients, allocated %zu, reused %zu (hit %zu%%)."
, used, web_clients_cache.used_count
, avail, web_clients_cache.avail_count
, web_clients_cache.allocated
, web_clients_cache.reused
, (web_clients_cache.allocated + web_clients_cache.reused)?(web_clients_cache.reused * 100 / (web_clients_cache.allocated + web_clients_cache.reused)):0
);
}
#else
if(unlikely(force)) {
info("web_client_cache has %zu used and %zu available clients, allocated %zu, reused %zu (hit %zu%%)."
, web_clients_cache.used_count
, web_clients_cache.avail_count
, web_clients_cache.allocated
, web_clients_cache.reused
, (web_clients_cache.allocated + web_clients_cache.reused)?(web_clients_cache.reused * 100 / (web_clients_cache.allocated + web_clients_cache.reused)):0
);
}
#endif
}
// destroy the cache and free all the memory it uses
void web_client_cache_destroy(void) {
#ifdef NETDATA_INTERNAL_CHECKS
if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid()))
error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid());
web_client_cache_verify(1);
#endif
netdata_thread_disable_cancelability();
struct web_client *w, *t;
w = web_clients_cache.used;
while(w) {
t = w;
w = w->next;
web_client_free(t);
}
web_clients_cache.used = NULL;
web_clients_cache.used_count = 0;
w = web_clients_cache.avail;
while(w) {
t = w;
w = w->next;
web_client_free(t);
}
web_clients_cache.avail = NULL;
web_clients_cache.avail_count = 0;
netdata_thread_enable_cancelability();
}
struct web_client *web_client_get_from_cache_or_allocate() {
#ifdef NETDATA_INTERNAL_CHECKS
if(unlikely(web_clients_cache.pid == 0))
web_clients_cache.pid = gettid();
if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid()))
error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid());
#endif
netdata_thread_disable_cancelability();
struct web_client *w = web_clients_cache.avail;
if(w) {
// get it from avail
if (w == web_clients_cache.avail) web_clients_cache.avail = w->next;
if(w->prev) w->prev->next = w->next;
if(w->next) w->next->prev = w->prev;
web_clients_cache.avail_count--;
#ifdef ENABLE_HTTPS
web_client_reuse_ssl(w);
SSL *ssl = w->ssl.conn;
#endif
web_client_zero(w);
web_clients_cache.reused++;
#ifdef ENABLE_HTTPS
w->ssl.conn = ssl;
w->ssl.flags = NETDATA_SSL_START;
debug(D_WEB_CLIENT_ACCESS,"Reusing SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
#endif
}
else {
// allocate it
w = web_client_alloc();
#ifdef ENABLE_HTTPS
w->ssl.flags = NETDATA_SSL_START;
debug(D_WEB_CLIENT_ACCESS,"Starting SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
#endif
web_clients_cache.allocated++;
}
// link it to used web clients
if (web_clients_cache.used) web_clients_cache.used->prev = w;
w->next = web_clients_cache.used;
w->prev = NULL;
web_clients_cache.used = w;
web_clients_cache.used_count++;
// initialize it
w->id = web_client_connected();
w->mode = WEB_CLIENT_MODE_NORMAL;
netdata_thread_enable_cancelability();
return w;
}
void web_client_release(struct web_client *w) {
#ifdef NETDATA_INTERNAL_CHECKS
if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid()))
error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid());
if(unlikely(w->running))
error("%llu: releasing web client from %s port %s, but it still running.", w->id, w->client_ip, w->client_port);
#endif
debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
web_server_log_connection(w, "DISCONNECTED");
web_client_request_done(w);
web_client_disconnected();
netdata_thread_disable_cancelability();
if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
if (w->ifd != -1) close(w->ifd);
if (w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
w->ifd = w->ofd = -1;
#ifdef ENABLE_HTTPS
web_client_reuse_ssl(w);
w->ssl.flags = NETDATA_SSL_START;
#endif
}
// unlink it from the used
if (w == web_clients_cache.used) web_clients_cache.used = w->next;
if(w->prev) w->prev->next = w->next;
if(w->next) w->next->prev = w->prev;
web_clients_cache.used_count--;
if(web_clients_cache.avail_count >= 2 * web_clients_cache.used_count) {
// we have too many of them - free it
web_client_free(w);
}
else {
// link it to the avail
if (web_clients_cache.avail) web_clients_cache.avail->prev = w;
w->next = web_clients_cache.avail;
w->prev = NULL;
web_clients_cache.avail = w;
web_clients_cache.avail_count++;
}
netdata_thread_enable_cancelability();
}