From 1d9905ff87ad231cb9add839cb458e3189eec82b Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 12 Feb 2025 18:07:00 +1100 Subject: [PATCH 1/2] fix: fixed corner case where zombie streams are created after destruction --- Cargo.lock | 7 ++--- package-lock.json | 61 +++++++++++++++++++++++++++++++++++++ src/QUICConnection.ts | 65 +++++++++++++++++++++++++--------------- src/errors.ts | 5 ++++ src/utils.ts | 5 ++++ tests/QUICStream.test.ts | 2 +- 6 files changed, 115 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a64fa4d..688b895a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,12 +252,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "log" -version = "0.4.17" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" diff --git a/package-lock.json b/package-lock.json index 2858e26a..337166f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1469,6 +1469,67 @@ "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-3.1.2.tgz", "integrity": "sha512-nNliLCnbg6hGS2+gGtQfeeyVNJzOmvqz90AbrQsHPNiE08l3YsENL2JQt9d454SorD1Ud51ymZdDCkeMLWY93A==" }, + "node_modules/@matrixai/quic-darwin-arm64": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-arm64/-/quic-darwin-arm64-1.3.9.tgz", + "integrity": "sha512-KCbRYujKWVFsNP2fZPFytpkYbkZWmaqR9uMLOUSC1HWuFhZnnCCdRubKJ4MjuCPssJilNF2BJbpIFv9vhOGjOw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@matrixai/quic-darwin-universal": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-universal/-/quic-darwin-universal-1.3.9.tgz", + "integrity": "sha512-LjeElD9+Z8P8mNuJQyHFMNDOkYAAGudbBulgy6Pz3xcemSZ01WJHRZ7G/iDhBU/cbzI34QRhY/dj0JKOF+fnkw==", + "cpu": [ + "x64", + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@matrixai/quic-darwin-x64": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-x64/-/quic-darwin-x64-1.3.9.tgz", + "integrity": "sha512-hRJyWMJthcts0k1qgVoDl9EdX1ycwtGxNoJzEINbITTKQ+YdgBxVNW+LE0tMgdGhkPp6FSUuCNtAWJFiYAYz8A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@matrixai/quic-linux-x64": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@matrixai/quic-linux-x64/-/quic-linux-x64-1.3.9.tgz", + "integrity": "sha512-KC5sNKKCvIDvskn/xsN5vDqB4JVHrr5qPqcIrgxfBEg/y9u0Syluobq/Hp3khFgkJrPPNHs5IQQBReyHYkljIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@matrixai/quic-win32-x64": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@matrixai/quic-win32-x64/-/quic-win32-x64-1.3.9.tgz", + "integrity": "sha512-YkWwmGsaN+sQAAXdL9MlEK4CsDXGwwrLAYEfYckn9JfL9j0KTAkJnhrzPu84x+gjBiVacD4tiJSQDLlncd6liA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@matrixai/resources": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.1.5.tgz", diff --git a/src/QUICConnection.ts b/src/QUICConnection.ts index 0b2c5a7a..7e1008fe 100644 --- a/src/QUICConnection.ts +++ b/src/QUICConnection.ts @@ -1029,30 +1029,47 @@ class QUICConnection { ); continue; } - - quicStream = QUICStream.createQUICStream({ - initiated: 'peer', - streamId, - config: this.config, - connection: this, - codeToReason: this.codeToReason, - reasonToCode: this.reasonToCode, - logger: this.logger.getChild(`${QUICStream.name} ${streamId}`), - }); - this.streamMap.set(quicStream.streamId, quicStream); - quicStream.addEventListener( - events.EventQUICStreamSend.name, - this.handleEventQUICStreamSend, - ); - quicStream.addEventListener( - events.EventQUICStreamDestroyed.name, - this.handleEventQUICStreamDestroyed, - { once: true }, - ); - quicStream.addEventListener(EventAll.name, this.handleEventQUICStream); - this.dispatchEvent( - new events.EventQUICConnectionStream({ detail: quicStream }), - ); + try { + this.conn.streamSend(streamId, Buffer.alloc(0), false); + utils.never( + 'We never expect the stream to be writable if it was created during the writable iterator', + ); + } catch (e) { + // If we got `FinalSize` during the writable iterator then we cleaned up an errant stream + if (e.message === 'FinalSize') continue; + if (utils.isStreamStopped(e) !== false) { + // In this case it was a stream that was created but errored out. We want to create a new stream for this one case. + quicStream = QUICStream.createQUICStream({ + initiated: 'peer', + streamId, + config: this.config, + connection: this, + codeToReason: this.codeToReason, + reasonToCode: this.reasonToCode, + logger: this.logger.getChild(`${QUICStream.name} ${streamId}`), + }); + this.streamMap.set(quicStream.streamId, quicStream); + quicStream.addEventListener( + events.EventQUICStreamSend.name, + this.handleEventQUICStreamSend, + ); + quicStream.addEventListener( + events.EventQUICStreamDestroyed.name, + this.handleEventQUICStreamDestroyed, + { once: true }, + ); + quicStream.addEventListener( + EventAll.name, + this.handleEventQUICStream, + ); + this.dispatchEvent( + new events.EventQUICConnectionStream({ detail: quicStream }), + ); + quicStream.write(); + continue; + } + utils.never(`Expected to throw "FinalSize", got ${e.message}`); + } } quicStream.write(); } diff --git a/src/errors.ts b/src/errors.ts index 6f839fc6..838e1506 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -6,6 +6,10 @@ class ErrorQUIC extends AbstractError { static description = 'QUIC error'; } +class ErrorQUICUndefinedBehaviour extends AbstractError { + static description = 'You should never see this error'; +} + class ErrorQUICHostInvalid extends AbstractError { static description = 'Host provided was not valid'; } @@ -293,6 +297,7 @@ class ErrorQUICStreamLimit extends ErrorQUICStream { export { ErrorQUIC, + ErrorQUICUndefinedBehaviour, ErrorQUICHostInvalid, ErrorQUICPortInvalid, ErrorQUICConfig, diff --git a/src/utils.ts b/src/utils.ts index 34404379..5b492a1a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,6 +18,10 @@ import * as errors from './errors'; const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder('utf-8'); +function never(message: string): never { + throw new errors.ErrorQUICUndefinedBehaviour(message); +} + /** * Used to yield to the event loop to allow other micro tasks to process */ @@ -572,6 +576,7 @@ function setMaxListeners( export { textEncoder, textDecoder, + never, yieldMicro, promisify, promise, diff --git a/tests/QUICStream.test.ts b/tests/QUICStream.test.ts index 1c3f151e..313a8bbf 100644 --- a/tests/QUICStream.test.ts +++ b/tests/QUICStream.test.ts @@ -11,7 +11,7 @@ import * as testsUtils from './utils'; import { generateTLSConfig, sleep } from './utils'; describe(QUICStream.name, () => { - const logger = new Logger(`${QUICStream.name} Test`, LogLevel.WARN, [ + const logger = new Logger(`${QUICStream.name} Test`, LogLevel.INFO, [ new StreamHandler( formatting.format`${formatting.level}:${formatting.keys}:${formatting.msg}`, ), From 117f32f343916e5cb218251e7a3acc20d2ee5b7e Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Wed, 12 Feb 2025 18:13:47 +1100 Subject: [PATCH 2/2] 1.3.10 --- Cargo.lock | 2 +- Cargo.toml | 2 +- package-lock.json | 75 +++++------------------------------------------ package.json | 12 ++++---- 4 files changed, 15 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 688b895a..35679f1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ [[package]] name = "quic" -version = "1.3.9" +version = "1.3.10" dependencies = [ "boring", "napi", diff --git a/Cargo.toml b/Cargo.toml index 499e61b7..f288d5f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quic" -version = "1.3.9" +version = "1.3.10" authors = ["Roger Qiu "] license-file = "LICENSE" edition = "2021" diff --git a/package-lock.json b/package-lock.json index 337166f5..052ba4bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@matrixai/quic", - "version": "1.3.9", + "version": "1.3.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@matrixai/quic", - "version": "1.3.9", + "version": "1.3.10", "license": "Apache-2.0", "dependencies": { "@matrixai/async-cancellable": "^1.1.1", @@ -57,11 +57,11 @@ "typescript": "^5.1.6" }, "optionalDependencies": { - "@matrixai/quic-darwin-arm64": "1.3.9", - "@matrixai/quic-darwin-universal": "1.3.9", - "@matrixai/quic-darwin-x64": "1.3.9", - "@matrixai/quic-linux-x64": "1.3.9", - "@matrixai/quic-win32-x64": "1.3.9" + "@matrixai/quic-darwin-arm64": "1.3.10", + "@matrixai/quic-darwin-universal": "1.3.10", + "@matrixai/quic-darwin-x64": "1.3.10", + "@matrixai/quic-linux-x64": "1.3.10", + "@matrixai/quic-win32-x64": "1.3.10" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1469,67 +1469,6 @@ "resolved": "https://registry.npmjs.org/@matrixai/logger/-/logger-3.1.2.tgz", "integrity": "sha512-nNliLCnbg6hGS2+gGtQfeeyVNJzOmvqz90AbrQsHPNiE08l3YsENL2JQt9d454SorD1Ud51ymZdDCkeMLWY93A==" }, - "node_modules/@matrixai/quic-darwin-arm64": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-arm64/-/quic-darwin-arm64-1.3.9.tgz", - "integrity": "sha512-KCbRYujKWVFsNP2fZPFytpkYbkZWmaqR9uMLOUSC1HWuFhZnnCCdRubKJ4MjuCPssJilNF2BJbpIFv9vhOGjOw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@matrixai/quic-darwin-universal": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-universal/-/quic-darwin-universal-1.3.9.tgz", - "integrity": "sha512-LjeElD9+Z8P8mNuJQyHFMNDOkYAAGudbBulgy6Pz3xcemSZ01WJHRZ7G/iDhBU/cbzI34QRhY/dj0JKOF+fnkw==", - "cpu": [ - "x64", - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@matrixai/quic-darwin-x64": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@matrixai/quic-darwin-x64/-/quic-darwin-x64-1.3.9.tgz", - "integrity": "sha512-hRJyWMJthcts0k1qgVoDl9EdX1ycwtGxNoJzEINbITTKQ+YdgBxVNW+LE0tMgdGhkPp6FSUuCNtAWJFiYAYz8A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@matrixai/quic-linux-x64": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@matrixai/quic-linux-x64/-/quic-linux-x64-1.3.9.tgz", - "integrity": "sha512-KC5sNKKCvIDvskn/xsN5vDqB4JVHrr5qPqcIrgxfBEg/y9u0Syluobq/Hp3khFgkJrPPNHs5IQQBReyHYkljIg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@matrixai/quic-win32-x64": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@matrixai/quic-win32-x64/-/quic-win32-x64-1.3.9.tgz", - "integrity": "sha512-YkWwmGsaN+sQAAXdL9MlEK4CsDXGwwrLAYEfYckn9JfL9j0KTAkJnhrzPu84x+gjBiVacD4tiJSQDLlncd6liA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@matrixai/resources": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@matrixai/resources/-/resources-1.1.5.tgz", diff --git a/package.json b/package.json index 82009cd4..17273598 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@matrixai/quic", - "version": "1.3.9", + "version": "1.3.10", "author": "Matrix AI", "contributors": [ { @@ -48,11 +48,11 @@ "ip-num": "^1.5.0" }, "optionalDependencies": { - "@matrixai/quic-darwin-arm64": "1.3.9", - "@matrixai/quic-darwin-universal": "1.3.9", - "@matrixai/quic-darwin-x64": "1.3.9", - "@matrixai/quic-linux-x64": "1.3.9", - "@matrixai/quic-win32-x64": "1.3.9" + "@matrixai/quic-darwin-arm64": "1.3.10", + "@matrixai/quic-darwin-universal": "1.3.10", + "@matrixai/quic-darwin-x64": "1.3.10", + "@matrixai/quic-linux-x64": "1.3.10", + "@matrixai/quic-win32-x64": "1.3.10" }, "devDependencies": { "@fast-check/jest": "^1.1.0",