From 381310043852a9213f1abb62f5f0a7046d806286 Mon Sep 17 00:00:00 2001 From: Cayman Date: Wed, 3 Feb 2021 07:03:09 -0500 Subject: [PATCH] fix: hanging close promise (#140) --- src/socket-to-conn.js | 5 ++++- test/connection.spec.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/socket-to-conn.js b/src/socket-to-conn.js index fd5b574..2986749 100644 --- a/src/socket-to-conn.js +++ b/src/socket-to-conn.js @@ -78,7 +78,10 @@ module.exports = (socket, options) => { resolve() }, CLOSE_TIMEOUT) - socket.once('close', () => clearTimeout(timeout)) + socket.once('close', () => { + clearTimeout(timeout) + resolve() + }) socket.end(err => { maConn.timeline.close = Date.now() if (err) return reject(err) diff --git a/test/connection.spec.js b/test/connection.spec.js index 3a750b4..445beb5 100644 --- a/test/connection.spec.js +++ b/test/connection.spec.js @@ -50,4 +50,36 @@ describe('valid localAddr and remoteAddr', () => { expect(dialerConn.remoteAddr.toString()) .to.equal(listenerConn.localAddr.toString()) }) + + it('should handle multiple simultaneous closes', async () => { + // Create a Promise that resolves when a connection is handled + let handled + const handlerPromise = new Promise(resolve => { handled = resolve }) + + const handler = conn => handled(conn) + + // Create a listener with the handler + const listener = tcp.createListener(handler) + + // Listen on the multi-address + await listener.listen(ma) + + const localAddrs = listener.getAddrs() + expect(localAddrs.length).to.equal(1) + + // Dial to that address + const dialerConn = await tcp.dial(localAddrs[0]) + + // Wait for the incoming dial to be handled + await handlerPromise + + // Close the listener with two simultaneous calls to `close` + await Promise.race([ + new Promise((resolve, reject) => setTimeout(() => reject(new Error('Timed out waiting for connection close')), 500)), + await Promise.all([ + dialerConn.close(), + dialerConn.close() + ]) + ]) + }) })