From 927e2b7060603dcebe8f66abbbdaf5ffe3cac13d Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Thu, 9 Jun 2022 02:45:34 +0000 Subject: [PATCH] Expose some information about active sockets to try to track down leaks. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3898 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- core/core.js | 1 + src/socket.js.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/core.js b/core/core.js index 93b62b78..b52e40b1 100644 --- a/core/core.js +++ b/core/core.js @@ -172,6 +172,7 @@ async function getProcessBlob(blobId, key, options) { }, 'user': getUser(process, process), 'apps': user => getApps(user, process), + 'getSockets': getSockets, } }; if (options.api) { diff --git a/src/socket.js.c b/src/socket.js.c index a89ad43e..fad83c7c 100644 --- a/src/socket.js.c +++ b/src/socket.js.c @@ -13,12 +13,16 @@ #include "quickjs-libc.h" typedef int promiseid_t; +typedef struct _socket_t socket_t; static JSClassID _classId; static int _count; static int _open_count; static tf_tls_context_t* _defaultTlsContext; +static socket_t** _sockets; +static int _sockets_count; + typedef enum _socket_direction_t { kUndetermined, kAccept, @@ -41,6 +45,7 @@ typedef struct _socket_t { JSValue _onConnect; JSValue _onRead; JSValue _onError; + uint64_t created_ms; } socket_t; static JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); @@ -62,6 +67,7 @@ static JSValue _socket_getPeerName(JSContext* context, JSValueConst this_val, in static JSValue _socket_getPeerCertificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _socket_getNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); +static JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static void _socket_onClose(uv_handle_t* handle); static void _socket_onShutdown(uv_shutdown_t* request, int status); @@ -131,6 +137,10 @@ JSValue tf_socket_register(JSContext* context) { fprintf(stderr, "Failed to register Socket.\n"); } + + JSValue global = JS_GetGlobalObject(context); + JS_SetPropertyStr(context, global, "getSockets", JS_NewCFunction(context, _sockets_get, "getSockets", 0)); + JS_FreeValue(context, global); return JS_NewCFunction2(context, _socket_create, "Socket", 0, JS_CFUNC_constructor, 0); } @@ -154,6 +164,8 @@ socket_t* _socket_create_internal(JSContext* context) { socket_t* socket = tf_malloc(sizeof(socket_t)); memset(socket, 0, sizeof(*socket)); + _sockets = realloc(_sockets, sizeof(socket_t*) * (_sockets_count + 1)); + _sockets[_sockets_count++] = socket; socket->_closePromise = -1; socket->_startTlsPromise = -1; @@ -164,6 +176,8 @@ socket_t* _socket_create_internal(JSContext* context) socket->_object = object; JS_SetOpaque(object, socket); + socket->created_ms = uv_now(tf_task_get_loop(socket->_task)); + socket->_onRead = JS_UNDEFINED; socket->_onError = JS_UNDEFINED; socket->_onConnect = JS_UNDEFINED; @@ -230,6 +244,15 @@ void _socket_close_internal(socket_t* socket) JS_IsUndefined(socket->_object)) { --_count; + for (int i = 0; i < _sockets_count; i++) + { + if (_sockets[i] == socket) + { + _sockets[i] = _sockets[_sockets_count - 1]; + --_sockets_count; + break; + } + } tf_free(socket); } } @@ -439,7 +462,7 @@ JSValue _socket_connect(JSContext* context, JSValueConst this_val, int argc, JSV const char* node = JS_ToCString(context, argv[0]); const char* port = JS_ToCString(context, argv[1]); - strncpy(socket->_peerName, node, sizeof(socket->_peerName) - 1); + snprintf(socket->_peerName, sizeof(socket->_peerName), "%s", node); socket_resolve_data_t* data = tf_malloc(sizeof(socket_resolve_data_t)); memset(data, 0, sizeof(*data)); @@ -561,6 +584,12 @@ JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSVa int status = uv_accept((uv_stream_t*)&socket->_socket, (uv_stream_t*)&client->_socket); if (status == 0) { + struct sockaddr_in name = { 0 }; + int namelen = (int)sizeof(name); + if (uv_tcp_getpeername(&client->_socket, (struct sockaddr*)&name, &namelen) == 0) + { + uv_ip_name((const struct sockaddr*)&name, client->_peerName, sizeof(client->_peerName)); + } client->_connected = true; tf_task_resolve_promise(socket->_task, promise, client->_object); } @@ -1035,3 +1064,20 @@ JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc, uv_tcp_nodelay(&socket->_socket, result > 0 ? 1 : 0); return JS_UNDEFINED; } + +JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) +{ + JSValue array = JS_NewArray(context); + for (int i = 0; i < _sockets_count; i++) + { + socket_t* s = _sockets[i]; + JSValue entry = JS_NewObject(context); + JS_SetPropertyStr(context, entry, "peer", JS_NewString(context, s->_peerName)); + JS_SetPropertyStr(context, entry, "listening", JS_NewBool(context, s->_listening)); + JS_SetPropertyStr(context, entry, "connected", JS_NewBool(context, s->_connected)); + JS_SetPropertyStr(context, entry, "tls", JS_NewBool(context, s->_tls != NULL)); + JS_SetPropertyStr(context, entry, "age_seconds", JS_NewFloat64(context, (uv_now(tf_task_get_loop(s->_task)) - s->created_ms) / 1000.f)); + JS_SetPropertyUint32(context, array, i, entry); + } + return array; +}