Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ext/node/net): emit error before close when connection is refused #24656

Merged
merged 12 commits into from
Jul 24, 2024

Conversation

kt3k
Copy link
Member

@kt3k kt3k commented Jul 20, 2024

This PR delays the timing of callback called in socket._handle.close(cb) call, and causes error event happens before close event when socket.destroy() is called.

closes #24376
closes #23665
closes #21951
closes #19078

Note: The changes in unit_node/tls_test.ts, unit_node/http_test.ts, and polyfills/dgram.ts were needed for avoiding op leak error in testing. They are not directly related to the fix.

TODO:

  • enable test cases Write test cases (I couldn't find the exact test case which exercise this behavior of net.createConnection in node.js native test cases)

@kt3k kt3k changed the title fix(ext/node): emit error before close when destroying socket fix(ext/node/net): emit error before close when connection is refused Jul 23, 2024
@kt3k
Copy link
Member Author

kt3k commented Jul 23, 2024

@bartlomieju PTAL

@kt3k kt3k requested a review from bartlomieju July 23, 2024 14:06
Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for looking into this one!

@@ -40,7 +38,7 @@ export class HandleWrap extends AsyncWrap {

close(cb: () => void = () => {}) {
this._onClose();
queueMicrotask(cb);
setTimeout(cb, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried using nextTick instead?

Copy link
Member Author

@kt3k kt3k Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nextTick doesn't delay enough because emitErrorNT (which causes error event) callback is called at next tick (and that's registered after _handle.close callback.

deno/ext/node/polyfills/net.ts

Lines 1418 to 1426 in 29934d5

this._handle.close(() => {
this._handle!.onread = _noop;
this._handle = null;
this._sockname = undefined;
debug("emit close");
this.emit("close", isException);
});
cb(exception);

In the above code, the callback for this._handle.close is the one delayed in this PR (that emits close). cb in the above is onDestroy in _stream.mjs, which calls process.nextTick(() => stream.emit("error")).

So we need to delay the close callback at least 2 ticks.

Copy link
Member Author

@kt3k kt3k Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the line to nextTick(nextTick, cb) which also seems working, and also feels more accurate/predictable than setTimeout.

@kt3k kt3k merged commit 199a8ca into denoland:main Jul 24, 2024
17 checks passed
@kt3k kt3k deleted the error-before-close branch July 24, 2024 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment