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

View File

@ -31,6 +31,8 @@ typedef struct _socket_t {
promiseid_t _closePromise; promiseid_t _closePromise;
bool _connected; bool _connected;
bool _noDelay; bool _noDelay;
bool _reading;
bool _listening;
char _peerName[256]; char _peerName[256];
socket_direction_t _direction; socket_direction_t _direction;
JSValue _object; JSValue _object;
@ -80,6 +82,30 @@ static void _socket_processOutgoingTls(socket_t* socket);
static void _socket_reportTlsErrors(socket_t* socket); static void _socket_reportTlsErrors(socket_t* socket);
static void _socket_reportError(socket_t* socket, const char* error); 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) static void _socket_gc_mark(JSRuntime* runtime, JSValueConst value, JS_MarkFunc mark_func)
{ {
socket_t* socket = JS_GetOpaque(value, _classId); 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)); socket_t* socket = malloc(sizeof(socket_t));
memset(socket, 0, sizeof(*socket)); memset(socket, 0, sizeof(*socket));
socket->_onRead = JS_UNDEFINED;
socket->_onError = JS_UNDEFINED;
socket->_onConnect = JS_UNDEFINED;
socket->_closePromise = -1; socket->_closePromise = -1;
socket->_startTlsPromise = -1; socket->_startTlsPromise = -1;
@ -139,6 +162,10 @@ socket_t* _socket_create_internal(JSContext* context)
socket->_object = object; socket->_object = object;
JS_SetOpaque(object, socket); 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, "bind", JS_NewCFunction(context, _socket_bind, "bind", 2));
JS_SetPropertyStr(context, object, "connect", JS_NewCFunction(context, _socket_connect, "connect", 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)); 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) void _socket_close_internal(socket_t* socket)
{ {
if (!JS_IsUndefined(socket->_onRead)) _socket_set_handler(socket, &socket->_onRead, JS_UNDEFINED);
{ _socket_set_handler(socket, &socket->_onError, JS_UNDEFINED);
JSValue value = socket->_onRead; _socket_set_handler(socket, &socket->_onConnect, JS_UNDEFINED);
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);
}
if (socket->_tls) if (socket->_tls)
{ {
tf_tls_session_destroy(socket->_tls); tf_tls_session_destroy(socket->_tls);
socket->_tls = NULL; 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); 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) void _socket_finalizer(JSRuntime *runtime, JSValue value)
{ {
socket_t* socket = JS_GetOpaque(value, _classId); socket_t* socket = JS_GetOpaque(value, _classId);
if (socket->_listening)
{
printf("FINALIZING A LISTENING SOCKET!\n");
abort();
}
socket->_object = JS_UNDEFINED; socket->_object = JS_UNDEFINED;
_socket_close_internal(socket); _socket_close_internal(socket);
} }
void _socket_reportError(socket_t* socket, const char* error) 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 exception = JS_ThrowInternalError(context, "%s", error);
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onError, socket->_object, 1, &exception); JSValue result = JS_Call(context, socket->_onError, socket->_object, 1, &exception);
if (JS_IsException(result)) tf_util_report_error(context, result);
{ JS_FreeValue(context, exception);
printf("Socket error.\n"); JS_FreeValue(context, result);
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);
} }
else else
{ {
fprintf(stderr, "Socket::reportError: %s\n", error); fprintf(stderr, "Socket::reportError: %s\n", error);
} }
JS_FreeValue(context, ref);
} }
void _socket_reportTlsErrors(socket_t* socket) 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) JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
socket_t* socket = JS_GetOpaque(this_val, _classId); socket_t* socket = JS_GetOpaque(this_val, _classId);
socket->_listening = true;
int backlog = 1; int backlog = 1;
JS_ToInt32(context, &backlog, argv[0]); JS_ToInt32(context, &backlog, argv[0]);
if (JS_IsUndefined(socket->_onConnect)) 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); int result = uv_listen((uv_stream_t*)&socket->_socket, backlog, _socket_onNewConnection);
if (result != 0) 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) void _socket_onNewConnection(uv_stream_t* server, int status)
{ {
socket_t* socket = server->data; 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)) if (!JS_IsUndefined(socket->_onConnect))
{ {
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onConnect, socket->_object, 0, NULL); JSValue result = JS_Call(context, socket->_onConnect, socket->_object, 0, NULL);
if (JS_IsException(result)) tf_util_report_error(context, result);
{ JS_FreeValue(context, result);
printf("Socket error on connection.\n");
js_std_dump_error(tf_task_get_context(socket->_task));
}
} }
JS_FreeValue(context, ref);
} }
JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) 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) JSValue _socket_onError(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
socket_t* socket = JS_GetOpaque(this_val, _classId); socket_t* socket = JS_GetOpaque(this_val, _classId);
if (!JS_IsUndefined(socket->_onError)) _socket_set_handler(socket, &socket->_onError, argv[0]);
{
JS_FreeValue(context, socket->_onError);
socket->_onError = JS_UNDEFINED;
}
socket->_onError = JS_DupValue(context, argv[0]);
return JS_NULL; return JS_NULL;
} }
JSValue _socket_read(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) JSValue _socket_read(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
socket_t* socket = JS_GetOpaque(this_val, _classId); socket_t* socket = JS_GetOpaque(this_val, _classId);
socket->_onRead = JS_DupValue(context, argv[0]); JSValue ref = JS_DupValue(context, socket->_object);
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead); _socket_set_handler(socket, &socket->_onRead, argv[0]);
promiseid_t promise = -1; promiseid_t promise = -1;
JSValue read_result = tf_task_allocate_promise(socket->_task, &promise); JSValue read_result = tf_task_allocate_promise(socket->_task, &promise);
if (result != 0) if (!socket->_reading)
{ {
char error[256]; int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result)); if (result != 0)
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error)); {
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 else
{ {
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED); tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
} }
JS_FreeValue(context, ref);
return read_result; 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) void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffer)
{ {
socket_t* socket = stream->data; socket_t* socket = stream->data;
JSContext* context = tf_task_get_context(socket->_task);
JSValue ref = JS_DupValue(context, socket->_object);
if (readSize <= 0) if (readSize <= 0)
{ {
socket->_connected = false; socket->_connected = false;
if (!JS_IsUndefined(socket->_onRead)) if (!JS_IsUndefined(socket->_onRead))
{ {
JSValue args[] = { JS_UNDEFINED }; JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result)) tf_util_report_error(context, result);
{ JS_FreeValue(context, 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);
} }
_socket_close_internal(socket); _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]; char buffer[8192];
if (tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer))) 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 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]; char plain[8192];
int result = tf_tls_session_read_plain(socket->_tls, plain, sizeof(plain)); 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)) if (!JS_IsUndefined(socket->_onRead))
{ {
JSValue args[] = { JS_UNDEFINED }; JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result)) tf_util_report_error(context, result);
{ JS_FreeValue(context, 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);
} }
break; break;
} }
@ -747,6 +765,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
break; break;
} }
} }
if (socket->_tls) if (socket->_tls)
{ {
_socket_processOutgoingTls(socket); _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); free(buffer->base);
JS_FreeValue(context, ref);
} }
static JSValue _newUint8Array(JSContext* context, const void* data, size_t length) 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) 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 result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
JSValue args[] = { typedArray }; tf_util_report_error(context, result);
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JS_FreeValue(context, result);
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);
} }
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, "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) if (task->_ssb)
{ {