From 236d74238cf31e3eacbebe9d09c76daa7d8f7e27 Mon Sep 17 00:00:00 2001 From: dive2tech Date: Thu, 22 Jan 2026 07:57:28 -0500 Subject: [PATCH] fix: improve RADIUS client error handling and socket cleanup (#6783) Co-authored-by: GitTensor Miner Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- server/radius-client.js | 42 ++++++++++++++++++++++++++++++----------- server/util-server.js | 14 ++++++++++++-- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/server/radius-client.js b/server/radius-client.js index d7c9a3150..207bc73f7 100644 --- a/server/radius-client.js +++ b/server/radius-client.js @@ -67,23 +67,47 @@ class RadiusClient { let attempts = 0; let responseReceived = false; let timeoutHandle; + let socketClosed = false; + + /** + * Safely close socket and clear timeout + * @returns {void} + */ + const cleanup = () => { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + timeoutHandle = null; + } + if (!socketClosed) { + socketClosed = true; + try { + socket.close(); + } catch (err) { + // Ignore errors during cleanup + } + } + }; /** * Send RADIUS request with retry logic * @returns {void} */ const sendRequest = () => { + if (responseReceived || socketClosed) { + return; + } + attempts++; socket.send(encodedPacket, 0, encodedPacket.length, this.port, this.host, (err) => { if (err) { - socket.close(); + cleanup(); return reject(new Error(`Failed to send RADIUS request: ${err.message}`)); } // Set timeout for this attempt timeoutHandle = setTimeout(() => { - if (responseReceived) { + if (responseReceived || socketClosed) { return; } @@ -92,7 +116,7 @@ class RadiusClient { sendRequest(); } else { // All retries exhausted - socket.close(); + cleanup(); reject(new Error(`RADIUS request timeout after ${attempts} attempts`)); } }, this.timeout); @@ -101,23 +125,20 @@ class RadiusClient { // Handle response socket.on("message", (msg) => { - if (responseReceived) { + if (responseReceived || socketClosed) { return; } responseReceived = true; - clearTimeout(timeoutHandle); + cleanup(); let response; try { response = radius.decode({ packet: msg, secret: secret }); } catch (error) { - socket.close(); return reject(new Error(`RADIUS response decoding failed: ${error.message}`)); } - socket.close(); - // Map response code to match node-radius-client format const responseCode = response.code; @@ -140,10 +161,9 @@ class RadiusClient { // Handle socket errors socket.on("error", (err) => { - if (!responseReceived) { + if (!responseReceived && !socketClosed) { responseReceived = true; - clearTimeout(timeoutHandle); - socket.close(); + cleanup(); reject(new Error(`RADIUS socket error: ${err.message}`)); } }); diff --git a/server/util-server.js b/server/util-server.js index d7316dee3..a22d4d09e 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -356,10 +356,20 @@ exports.radius = function ( ], }) .catch((error) => { + // Preserve error stack trace and provide better context if (error.response?.code) { - throw Error(error.response.code); + const radiusError = new Error(`RADIUS ${error.response.code} from ${hostname}:${port}`); + radiusError.response = error.response; + radiusError.originalError = error; + throw radiusError; } else { - throw Error(error.message); + // Preserve original error message and stack trace + const enhancedError = new Error( + `RADIUS authentication failed for ${hostname}:${port}: ${error.message}` + ); + enhancedError.originalError = error; + enhancedError.stack = error.stack || enhancedError.stack; + throw enhancedError; } }); };