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

net: multiple listen() events fail silently #13149

Closed
wants to merge 1 commit into from

Conversation

eduardbme
Copy link
Contributor

  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows [commit guidelines]

Affected core subsystem(s)

net

Description of change

Problem: It's possible to run listen() on a net.Server that's already listening to a port.
The result is silent failure, with the side effect of changing the _connectionKey and or _pipeName.

Solution: emit error if listen method called more than once.
close() method should be called between listen() method calls.

Refs: #8294
Fixes: #6190
Fixes: #11685

Previous PR #8419

@nodejs-github-bot nodejs-github-bot added the net Issues and PRs related to the net subsystem. label May 22, 2017
@eduardbme
Copy link
Contributor Author

hi there @jasnell @rvagg @addaleax @cjihrig @joyeecheung @evanlucas

@gibfahn have updated pr, please run CI
updated docs and moved away from accessors @bnoordhuis

@gibfahn
Copy link
Member

gibfahn commented May 22, 2017

doc/api/http.md Outdated
*Note*: The `server.listen()` method may be called multiple times. Each
subsequent call will *re-open* the server using the provided options.
*Note*:
The `server.listen()` method can be called again if and only if there was an error
Copy link
Member

Choose a reason for hiding this comment

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

There's no reason for the line break after *Note*: ...

*Note*: The `server.listen()` method...

doc/api/http.md Outdated
subsequent call will *re-open* the server using the provided options.
*Note*:
The `server.listen()` method can be called again if and only if there was an error
during the first *listen* call or you explicitly called `server.close()`.
Copy link
Member

Choose a reason for hiding this comment

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

during the first `listen()` call ...

Copy link
Member

Choose a reason for hiding this comment

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

Please avoid the use of you in docs :-)

lib/net.js Outdated
return this.emit('error', er);
}

this._serverListenHasBeenCalled = true;
Copy link
Member

Choose a reason for hiding this comment

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

Rather than introducing a new state variable for tracking, just look for the existence of the _handle. If it is not undefined or null, the server is listening, otherwise it is not.

Copy link
Member

Choose a reason for hiding this comment

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

What if the server._handle has been manually set to a non-listening wrap though?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. But I think that the _ sign clearly says "okay, you know what you doing by accessing , sort of, private field. You are on your own way now".

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

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

Good idea but the implementation and docs need a bit of work. Added a few comments. Thank you for working on this.

@eduardbme eduardbme force-pushed the listenhasbeencalled branch 4 times, most recently from b07d6f5 to fbe11dc Compare May 28, 2017 12:15
@eduardbme
Copy link
Contributor Author

@jasnell updated pr

lib/net.js Outdated
@@ -1404,6 +1404,12 @@ Server.prototype.listen = function() {
var options = normalized[0];
var cb = normalized[1];

if (this._handle) {
var er = new Error('listen method has been called more than once.');
Copy link
Member

Choose a reason for hiding this comment

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

The other thing I would recommend here is using the new internal/errors when introducing a new error.

@jasnell jasnell added the semver-major PRs that contain breaking changes and should be released in the next major version. label May 29, 2017
@eduardbme eduardbme force-pushed the listenhasbeencalled branch 2 times, most recently from 068bcbf to c566e77 Compare June 22, 2017 11:07
@eduardbme
Copy link
Contributor Author

@jasnell moved away from EINVAL error, added new one inside errors called ERR_SERVER_ALREADY_LISTEN and updated tests.

@cjihrig
Copy link
Contributor

cjihrig commented Jun 22, 2017

This is an interesting edge case. Would calling listen() twice be considered a programmer error? If so, we should throw, not emit an error. If we do stick with an emit(), should the PR return this for consistency with other returns in listen()?

@BridgeAR
Copy link
Member

@cjihrig I'd say it's a programmer error.

@joyeecheung
Copy link
Member

@cjihrig I think the theory is, if listen has already been called, whoever calls it is likely to have a error handler setup already and they should be notified. Although I think the second listen call should throw as well so the second caller can be notified ASAP

Copy link

@justsml justsml left a comment

Choose a reason for hiding this comment

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

Excellent work, very clean PR! 👍

@BridgeAR
Copy link
Member

@eduardbcom this needs a rebase and as far as I see it the emit should be changed to throwing right away.

Copy link
Member

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

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

One comment, otherwise LGTM

@eduardbme
Copy link
Contributor Author

@BridgeAR done

}));
}

// Thrid test.
Copy link
Member

Choose a reason for hiding this comment

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

Nit: typo (can be fixed while landing though)

@BridgeAR
Copy link
Member

@BridgeAR
Copy link
Member

@gibfahn @cjihrig @joyeecheung @jasnell you might want to have another look as the emit now changed to a throw instead.

code: 'ERR_SERVER_ALREADY_LISTEN',
type: Error,
}));
}
Copy link
Member

Choose a reason for hiding this comment

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

nit... this can be changed to:

common.expectsError(() => server.listen(),
                    {
                      code: 'ERR_SERVER_ALREADY_LISTEN',
                      type: Error
                    });

@jasnell
Copy link
Member

jasnell commented Aug 30, 2017

Still LGTM but I'd like to get more @nodejs/ctc reviews

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

LGTM

doc/api/http.md Outdated
*Note*: The `server.listen()` method may be called multiple times. Each
subsequent call will *re-open* the server using the provided options.
*Note*: The `server.listen()` method can be called again if and only if there was an error
during the first `server.listen()` call or `server.close()` method has been called.
Copy link
Contributor

Choose a reason for hiding this comment

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

Drop the word "method" after server.close() in this sentence.

doc/api/http.md Outdated
subsequent call will *re-open* the server using the provided options.
*Note*: The `server.listen()` method can be called again if and only if there was an error
during the first `server.listen()` call or `server.close()` method has been called.
Otherwise, an `ERR_SERVER_ALREADY_LISTEN` error would be thrown.
Copy link
Contributor

Choose a reason for hiding this comment

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

would be -> will be

doc/api/http.md Outdated
*Note*: The `server.listen()` method may be called multiple times. Each
subsequent call will *re-open* the server using the provided options.
*Note*: The `server.listen()` method can be called again if and only if there was an error
during the first `server.listen()` call or `server.close()` method has been called.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comments apply to this paragraph and the one below.

const server = net.Server();

server.listen(common.mustCall(
() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Style nit, but could you move this to the previous line. It saves a level of indentation.

Problem:
It's possible to run listen()
  on a net.Server that's already listening to a port.
The result is silent failure,
  with the side effect of changing the connectionKey and or pipeName.

Solution:
  throw an error if listen method called more than once.
  close() method should be called between listen() method calls.

Refs: nodejs#8294
Fixes: nodejs#6190
Fixes: nodejs#11685
@eduardbme
Copy link
Contributor Author

Thank you folks for your comments. Updated

@joyeecheung
Copy link
Member

Copy link
Member

@joyeecheung joyeecheung left a comment

Choose a reason for hiding this comment

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

LGTM if CI is happy

@mcollina
Copy link
Member

mcollina commented Sep 4, 2017

CI failures are unrelated, this can land.

@mcollina
Copy link
Member

mcollina commented Sep 4, 2017

Landed as b24e269.

@mcollina mcollina closed this Sep 4, 2017
@mcollina
Copy link
Member

mcollina commented Sep 4, 2017

Thanks @eduardbcom for your contribution!

mcollina pushed a commit that referenced this pull request Sep 4, 2017
Problem:
It's possible to run listen()
  on a net.Server that's already listening to a port.
The result is silent failure,
  with the side effect of changing the connectionKey and or pipeName.

Solution:
  throw an error if listen method called more than once.
  close() method should be called between listen() method calls.

Refs: #8294
Fixes: #6190
Fixes: #11685
PR-URL: #13149
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
addaleax pushed a commit to addaleax/ayo that referenced this pull request Sep 5, 2017
Problem:
It's possible to run listen()
  on a net.Server that's already listening to a port.
The result is silent failure,
  with the side effect of changing the connectionKey and or pipeName.

Solution:
  throw an error if listen method called more than once.
  close() method should be called between listen() method calls.

Refs: nodejs/node#8294
Fixes: nodejs/node#6190
Fixes: nodejs/node#11685
PR-URL: nodejs/node#13149
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
net Issues and PRs related to the net subsystem. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Document that you can only listen on an already closed socket net: multiple listen() events fail silently
9 participants