Trying to fix socket lifetime issues.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3886 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-06-02 10:58:22 +00:00
parent 58f459fb3b
commit 5622db92a7
3 changed files with 105 additions and 80 deletions

View File

@ -175,10 +175,12 @@ function handleRequest(request, response) {
if (promise) {
promise.catch(function(error) {
response.reportError(error);
request.client.close();
});
}
} catch (error) {
response.reportError(error);
request.client.close();
}
} else {
response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"});
@ -412,6 +414,7 @@ function handleConnection(client) {
}
} catch (error) {
response.reportError(error);
client.close();
}
}
@ -561,8 +564,9 @@ if (tildefriends.https_port) {
tls.keyStat = stat[1];
}
let result = client.startTls(tls.context);
handleConnection(client);
return client.startTls(tls.context);
return result;
} catch (error) {
logError("[" + new Date() + "] [" + client.peerName + "] " + error);
}

View File

@ -31,6 +31,8 @@ typedef struct _socket_t {
promiseid_t _closePromise;
bool _connected;
bool _noDelay;
bool _reading;
bool _listening;
char _peerName[256];
socket_direction_t _direction;
JSValue _object;
@ -80,6 +82,30 @@ static void _socket_processOutgoingTls(socket_t* socket);
static void _socket_reportTlsErrors(socket_t* socket);
static void _socket_reportError(socket_t* socket, const char* error);
static void _socket_set_handler(socket_t* socket, JSValue* handler, JSValue new_value)
{
JSContext* context = tf_task_get_context(socket->_task);
bool had_handler = !JS_IsUndefined(*handler);
if (!had_handler && !JS_IsUndefined(new_value))
{
JS_DupValue(context, socket->_object);
}
if (had_handler)
{
JSValue value = *handler;
*handler = JS_UNDEFINED;
JS_FreeValue(context, value);
}
if (!JS_IsUndefined(new_value))
{
*handler = JS_DupValue(context, new_value);
}
if (had_handler && JS_IsUndefined(new_value))
{
JS_FreeValue(context, socket->_object);
}
}
static void _socket_gc_mark(JSRuntime* runtime, JSValueConst value, JS_MarkFunc mark_func)
{
socket_t* socket = JS_GetOpaque(value, _classId);
@ -127,9 +153,6 @@ socket_t* _socket_create_internal(JSContext* context)
socket_t* socket = malloc(sizeof(socket_t));
memset(socket, 0, sizeof(*socket));
socket->_onRead = JS_UNDEFINED;
socket->_onError = JS_UNDEFINED;
socket->_onConnect = JS_UNDEFINED;
socket->_closePromise = -1;
socket->_startTlsPromise = -1;
@ -139,6 +162,10 @@ socket_t* _socket_create_internal(JSContext* context)
socket->_object = object;
JS_SetOpaque(object, socket);
socket->_onRead = JS_UNDEFINED;
socket->_onError = JS_UNDEFINED;
socket->_onConnect = JS_UNDEFINED;
JS_SetPropertyStr(context, object, "bind", JS_NewCFunction(context, _socket_bind, "bind", 2));
JS_SetPropertyStr(context, object, "connect", JS_NewCFunction(context, _socket_connect, "connect", 2));
JS_SetPropertyStr(context, object, "listen", JS_NewCFunction(context, _socket_listen, "listen", 2));
@ -183,30 +210,16 @@ JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSVa
void _socket_close_internal(socket_t* socket)
{
if (!JS_IsUndefined(socket->_onRead))
{
JSValue value = socket->_onRead;
socket->_onRead = JS_UNDEFINED;
JS_FreeValue(tf_task_get_context(socket->_task), value);
}
if (!JS_IsUndefined(socket->_onError))
{
JSValue value = socket->_onError;
socket->_onError = JS_UNDEFINED;
JS_FreeValue(tf_task_get_context(socket->_task), value);
}
if (!JS_IsUndefined(socket->_onConnect))
{
JSValue value = socket->_onConnect;
socket->_onConnect = JS_UNDEFINED;
JS_FreeValue(tf_task_get_context(socket->_task), value);
}
_socket_set_handler(socket, &socket->_onRead, JS_UNDEFINED);
_socket_set_handler(socket, &socket->_onError, JS_UNDEFINED);
_socket_set_handler(socket, &socket->_onConnect, JS_UNDEFINED);
if (socket->_tls)
{
tf_tls_session_destroy(socket->_tls);
socket->_tls = NULL;
}
if (!uv_is_closing((uv_handle_t*)&socket->_socket))
if (socket->_socket.data &&
!uv_is_closing((uv_handle_t*)&socket->_socket))
{
uv_close((uv_handle_t*)&socket->_socket, _socket_onClose);
}
@ -222,28 +235,32 @@ void _socket_close_internal(socket_t* socket)
void _socket_finalizer(JSRuntime *runtime, JSValue value)
{
socket_t* socket = JS_GetOpaque(value, _classId);
if (socket->_listening)
{
printf("FINALIZING A LISTENING SOCKET!\n");
abort();
}
socket->_object = JS_UNDEFINED;
_socket_close_internal(socket);
}
void _socket_reportError(socket_t* socket, const char* error)
{
if (JS_IsFunction(tf_task_get_context(socket->_task),socket-> _onError))
JSContext* context = tf_task_get_context(socket->_task);
JSValue ref = JS_DupValue(context, socket->_object);
if (JS_IsFunction(context, socket-> _onError))
{
JSValue exception = JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error);
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onError, socket->_object, 1, &exception);
if (JS_IsException(result))
{
printf("Socket error.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
JS_FreeValue(tf_task_get_context(socket->_task), exception);
JS_FreeValue(tf_task_get_context(socket->_task), result);
JSValue exception = JS_ThrowInternalError(context, "%s", error);
JSValue result = JS_Call(context, socket->_onError, socket->_object, 1, &exception);
tf_util_report_error(context, result);
JS_FreeValue(context, exception);
JS_FreeValue(context, result);
}
else
{
fprintf(stderr, "Socket::reportError: %s\n", error);
}
JS_FreeValue(context, ref);
}
void _socket_reportTlsErrors(socket_t* socket)
@ -501,11 +518,12 @@ void _socket_onConnect(uv_connect_t* request, int status)
JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
socket_t* socket = JS_GetOpaque(this_val, _classId);
socket->_listening = true;
int backlog = 1;
JS_ToInt32(context, &backlog, argv[0]);
if (JS_IsUndefined(socket->_onConnect))
{
socket->_onConnect = JS_DupValue(context, argv[1]);
_socket_set_handler(socket, &socket->_onConnect, argv[1]);
int result = uv_listen((uv_stream_t*)&socket->_socket, backlog, _socket_onNewConnection);
if (result != 0)
{
@ -524,15 +542,15 @@ JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSVa
void _socket_onNewConnection(uv_stream_t* server, int status)
{
socket_t* socket = server->data;
JSContext* context = tf_task_get_context(socket->_task);
JSValue ref = JS_DupValue(context, socket->_object);
if (!JS_IsUndefined(socket->_onConnect))
{
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onConnect, socket->_object, 0, NULL);
if (JS_IsException(result))
{
printf("Socket error on connection.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
JSValue result = JS_Call(context, socket->_onConnect, socket->_object, 0, NULL);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
}
JS_FreeValue(context, ref);
}
JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
@ -629,32 +647,38 @@ void _socket_onTlsShutdown(uv_write_t* request, int status)
JSValue _socket_onError(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
socket_t* socket = JS_GetOpaque(this_val, _classId);
if (!JS_IsUndefined(socket->_onError))
{
JS_FreeValue(context, socket->_onError);
socket->_onError = JS_UNDEFINED;
}
socket->_onError = JS_DupValue(context, argv[0]);
_socket_set_handler(socket, &socket->_onError, argv[0]);
return JS_NULL;
}
JSValue _socket_read(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
socket_t* socket = JS_GetOpaque(this_val, _classId);
socket->_onRead = JS_DupValue(context, argv[0]);
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
JSValue ref = JS_DupValue(context, socket->_object);
_socket_set_handler(socket, &socket->_onRead, argv[0]);
promiseid_t promise = -1;
JSValue read_result = tf_task_allocate_promise(socket->_task, &promise);
if (result != 0)
if (!socket->_reading)
{
char error[256];
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
if (result != 0)
{
char error[256];
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
}
else
{
socket->_reading = true;
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
}
}
else
{
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
}
JS_FreeValue(context, ref);
return read_result;
}
@ -666,19 +690,17 @@ void _socket_allocateBuffer(uv_handle_t* handle, size_t suggestedSize, uv_buf_t*
void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffer)
{
socket_t* socket = stream->data;
JSContext* context = tf_task_get_context(socket->_task);
JSValue ref = JS_DupValue(context, socket->_object);
if (readSize <= 0)
{
socket->_connected = false;
if (!JS_IsUndefined(socket->_onRead))
{
JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result))
{
printf("Socket error on read.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
JS_FreeValue(tf_task_get_context(socket->_task), result);
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
}
_socket_close_internal(socket);
}
@ -704,7 +726,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
char buffer[8192];
if (tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer)))
{
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), buffer));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, buffer));
}
else
{
@ -713,7 +735,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
}
}
while (true)
while (socket->_tls)
{
char plain[8192];
int result = tf_tls_session_read_plain(socket->_tls, plain, sizeof(plain));
@ -732,13 +754,9 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
if (!JS_IsUndefined(socket->_onRead))
{
JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result))
{
printf("Socket error on read plain.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
JS_FreeValue(tf_task_get_context(socket->_task), result);
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
}
break;
}
@ -747,6 +765,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
break;
}
}
if (socket->_tls)
{
_socket_processOutgoingTls(socket);
@ -758,6 +777,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
}
}
free(buffer->base);
JS_FreeValue(context, ref);
}
static JSValue _newUint8Array(JSContext* context, const void* data, size_t length)
@ -774,21 +794,20 @@ static JSValue _newUint8Array(JSContext* context, const void* data, size_t lengt
void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length)
{
if (!JS_IsUndefined(socket->_onRead))
if (data && length > 0)
{
if (data && length > 0)
JSContext* context = tf_task_get_context(socket->_task);
JSValue ref = JS_DupValue(context, socket->_object);
JSValue typedArray = _newUint8Array(context, data, length);
JSValue args[] = { typedArray };
if (!JS_IsUndefined(socket->_onRead))
{
JSValue typedArray = _newUint8Array(tf_task_get_context(socket->_task), data, length);
JSValue args[] = { typedArray };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result))
{
printf("Socket error on data read.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
JS_FreeValue(tf_task_get_context(socket->_task), typedArray);
JS_FreeValue(tf_task_get_context(socket->_task), result);
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
}
JS_FreeValue(context, typedArray);
JS_FreeValue(context, ref);
}
}

View File

@ -732,6 +732,8 @@ static JSValue _tf_task_getStats(JSContext* context, JSValueConst this_val, int
}
JS_SetPropertyStr(context, result, "sqlite3_memory_percent", JS_NewFloat64(context, 100.0f * sqlite3_memory_used() / total_memory));
JS_SetPropertyStr(context, result, "socket_count", JS_NewInt32(context, tf_socket_get_count()));
JS_SetPropertyStr(context, result, "socket_open_count", JS_NewInt32(context, tf_socket_get_open_count()));
if (task->_ssb)
{