From e5d963e24d03aa6e03235ed9064fd465c1edbd6b Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 14:07:58 -0700 Subject: [PATCH] quic: fixup kEndpointClose Ensure that the QuicSocket is properly destroyed if the QuicEndpoint is destroyed directly rather than through QuicSocket destroy PR-URL: https://github.com/nodejs/node/pull/34283 Reviewed-By: Anna Henningsen --- lib/internal/quic/core.js | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index d76478ff52b31e..1af67c031c81fa 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -1052,7 +1052,6 @@ class QuicSocket extends EventEmitter { }); } - // Called when a QuicEndpoint closes [kEndpointClose](endpoint, error) { const state = this[kInternalState]; state.endpoints.delete(endpoint); @@ -1064,26 +1063,15 @@ class QuicSocket extends EventEmitter { } }); - // If there are no more QuicEndpoints, the QuicSocket is no - // longer usable. + // If there aren't any more endpoints, the QuicSession + // is no longer usable and needs to be destroyed. if (state.endpoints.size === 0) { - for (const session of state.sessions) - session.destroy(error); - - if (error) process.nextTick(emit.bind(this, 'error', error)); - process.nextTick(emit.bind(this, 'close')); + if (!this.destroyed) + return this.destroy(error); + this[kDestroy](error); } } - // kDestroy is called to actually free the QuicSocket resources and - // cause the error and close events to be emitted. - [kDestroy](error) { - // The QuicSocket will be destroyed once all QuicEndpoints - // are destroyed. See [kEndpointClose]. - for (const endpoint of this[kInternalState].endpoints) - endpoint.destroy(error); - } - // kMaybeDestroy is called one or more times after the close() method // is called. The QuicSocket will be destroyed if there are no remaining // open sessions. @@ -1463,7 +1451,20 @@ class QuicSocket extends EventEmitter { for (const session of state.sessions) session.destroy(error); - this[kDestroy](error); + // If there aren't any QuicEndpoints to clean up, skip + // directly to the end to emit the error and close events. + if (state.endpoints.size === 0) + return this[kDestroy](error); + + // Otherwise, the QuicSocket will be destroyed once all + // QuicEndpoints are destroyed. See [kEndpointClose]. + for (const endpoint of state.endpoints) + endpoint.destroy(error); + } + + [kDestroy](error) { + if (error) process.nextTick(emit.bind(this, 'error', error)); + process.nextTick(emit.bind(this, 'close')); } ref() {