Implement connection activity timeouts.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4706 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-12-30 16:52:05 +00:00
parent b6a3923b27
commit 2f6a92168e

View File

@ -16,11 +16,14 @@
#include <alloca.h> #include <alloca.h>
#endif #endif
static const int k_timeout_ms = 60000;
typedef struct _tf_http_connection_t typedef struct _tf_http_connection_t
{ {
tf_http_t* http; tf_http_t* http;
uv_tcp_t tcp; uv_tcp_t tcp;
uv_shutdown_t shutdown; uv_shutdown_t shutdown;
uv_timer_t timeout;
int ref_count; int ref_count;
@ -77,6 +80,7 @@ typedef struct _tf_http_t
static const char* _http_connection_get_header(const tf_http_connection_t* connection, const char* name); static const char* _http_connection_get_header(const tf_http_connection_t* connection, const char* name);
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason); static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason);
static const char* _http_status_text(int status); static const char* _http_status_text(int status);
static void _http_timer_reset(tf_http_connection_t* connection);
tf_http_t* tf_http_create(uv_loop_t* loop) tf_http_t* tf_http_create(uv_loop_t* loop)
{ {
@ -119,6 +123,7 @@ bool _http_find_handler(tf_http_t* http, const char* path, tf_http_callback_t**
static void _http_on_write(uv_write_t* write, int status) static void _http_on_write(uv_write_t* write, int status)
{ {
_http_timer_reset(write->data);
tf_free(write); tf_free(write);
} }
@ -131,11 +136,19 @@ static void _http_connection_on_close(uv_handle_t* handle)
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason) static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason)
{ {
if (connection->tcp.data) if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp))
{ {
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close); uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
} }
else if (connection->ref_count == 0) if (connection->timeout.data && !uv_is_closing((uv_handle_t*)&connection->timeout))
{
uv_close((uv_handle_t*)&connection->timeout, _http_connection_on_close);
}
if (connection->ref_count == 0 &&
!connection->tcp.data &&
!connection->shutdown.data &&
!connection->timeout.data)
{ {
tf_http_t* http = connection->http; tf_http_t* http = connection->http;
for (int i = 0; i < http->connections_count; i++) for (int i = 0; i < http->connections_count; i++)
@ -298,6 +311,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer) static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer)
{ {
tf_http_connection_t* connection = stream->data; tf_http_connection_t* connection = stream->data;
_http_timer_reset(connection);
if (read_size > 0) if (read_size > 0)
{ {
if (!connection->headers_done) if (!connection->headers_done)
@ -389,6 +403,29 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
} }
} }
static void _http_timer_callback(uv_timer_t* timer)
{
tf_printf("_http_timer_callback\n");
_http_connection_destroy(timer->data, "_http_timer_callback");
}
static void _http_timer_reset(tf_http_connection_t* connection)
{
if (connection->timeout.data)
{
int r = uv_timer_stop(&connection->timeout);
if (r)
{
tf_printf("uv_timer_stop: %s\n", uv_strerror(r));
}
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
if (r)
{
tf_printf("uv_timer_start: %s\n", uv_strerror(r));
}
}
}
static void _http_on_connection(uv_stream_t* stream, int status) static void _http_on_connection(uv_stream_t* stream, int status)
{ {
tf_http_t* http = stream->data; tf_http_t* http = stream->data;
@ -398,7 +435,23 @@ static void _http_on_connection(uv_stream_t* stream, int status)
if (r) if (r)
{ {
tf_printf("uv_tcp_init: %s\n", uv_strerror(r)); tf_printf("uv_tcp_init: %s\n", uv_strerror(r));
tf_free(connection); _http_connection_destroy(connection, "uv_tcp_init");
return;
}
r = uv_timer_init(connection->http->loop, &connection->timeout);
connection->timeout.data = connection;
if (r)
{
tf_printf("uv_timer_init: %s\n", uv_strerror(r));
_http_connection_destroy(connection, "uv_timer_init");
return;
}
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
if (r)
{
tf_printf("uv_timer_start: %s\n", uv_strerror(r));
_http_connection_destroy(connection, "uv_timer_start");
return; return;
} }
@ -406,17 +459,15 @@ static void _http_on_connection(uv_stream_t* stream, int status)
if (r) if (r)
{ {
tf_printf("uv_accept: %s\n", uv_strerror(r)); tf_printf("uv_accept: %s\n", uv_strerror(r));
uv_close((uv_handle_t*)&connection->tcp, NULL); _http_connection_destroy(connection, "uv_accept");
tf_free(connection);
return; return;
} }
r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read); r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read);
if (r) if (r)
{ {
tf_printf("uv_read-start: %s\n", uv_strerror(r)); tf_printf("uv_read_start: %s\n", uv_strerror(r));
uv_close((uv_handle_t*)&connection->tcp, NULL); _http_connection_destroy(connection, "uv_read_start");
tf_free(connection);
return; return;
} }
@ -533,6 +584,7 @@ static void _http_on_shutdown(uv_shutdown_t* request, int status)
static void _http_write(tf_http_connection_t* connection, const void* data, size_t size) static void _http_write(tf_http_connection_t* connection, const void* data, size_t size)
{ {
_http_timer_reset(connection);
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size); uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size);
*write = (uv_write_t) { .data = connection }; *write = (uv_write_t) { .data = connection };
memcpy(write + 1, data, size); memcpy(write + 1, data, size);
@ -599,6 +651,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
{ {
memcpy(buffer + offset, body, content_length); memcpy(buffer + offset, body, content_length);
} }
_http_timer_reset(request->connection);
int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write); int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write);
if (r) if (r)
{ {