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

Attempting to open a TCP port in use not being blocked #2915

Closed
toryalsip opened this issue Feb 4, 2018 · 13 comments
Closed

Attempting to open a TCP port in use not being blocked #2915

toryalsip opened this issue Feb 4, 2018 · 13 comments

Comments

@toryalsip
Copy link

Windows Version: Microsoft Windows [Version 10.0.16299.192]

While running within the Ubuntu shell, I startup a simple node app like the following:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

Within a second Ubuntu shell I attempt to startup the same app. The expected behavior within the second app is that the console output should throw an error similar to this:

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE 127.0.0.1:3000
    at Object._errnoException (util.js:1022:11)
    at _exceptionWithHostPort (util.js:1044:20)
    at Server.setupListenHandle [as _listen2] (net.js:1351:14)
    at listenInCluster (net.js:1392:12)
    at doListen (net.js:1501:7)
    at _combinedTickCallback (internal/process/next_tick.js:141:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
    at Function.Module.runMain (module.js:686:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3

What actually happens is the second bash shell runs the app without any error. This is completely inconsistent with how I would expect.

Curiously enough, if I run the app within the Ubuntu shell, and then attempt to run the same app within a regular Windows command shell, then I do get the error as I expect.

I only observed this behavior with testing node apps, but I do wonder if it isn't just limited to node or if other programs using TCP exhibit a similar behavior.

@therealkenc
Copy link
Collaborator

therealkenc commented Feb 5, 2018

Confirmed and yeah that's weird. bind(2) should have failed with ADDRINUSE. Nah it isn't a node thing. Weird mostly because it hasn't been reported before AFAICT. Ref #384 (message) just because it is behaving a little like SO_REUSEPORT all the time. Or I'm missing something obvious.

@sunilmut
Copy link
Member

sunilmut commented Feb 6, 2018

@jbalsip - good catch!

It's the SO_REUSEADDR that is causing problems here. If you look at a strace, nodejs calls the SO_REUSEADDR socket option when the socket is created. Now the thing is that that socket option behaves differently on Windows and on Linux. Maybe, the Windows version of node is smart enough to not call this socket option. We have talked to the Windows networking team that supports these options previously to see if we can reconcile the differences, but, given the legacy of these options, that has had been a difficult conversation. We will continue to explore alternatives.

You should not see this behavior with other TCP applications if this socket option doesn't come into play.

@therealkenc
Copy link
Collaborator

We have talked to the Windows networking team that supports these options previously to see if we can reconcile the differences, but, given the legacy of these options, that has had been a difficult conversation.

Looks like Cygwin suffers from the same problem, for the same reasons.

This can be done in a backward compatible way that does not disturb Win32, but you already know that. I feel your pain 😢.

@firewave
Copy link

I ran into this issue using boost::asio::ip::tcp::acceptor and boost::asio::socket_base::reuse_address set to true (which sets SO_REUSEADDR). So it's not just related to node. Also makes writing "portable" code fun...

Start an acceptor on 0.0.0.0 and a port and it works fine.
Start another acceptor on the same host and port and the requests will still go to the previously started ones.
If you don't set SO_REUSEADDR it will fail with address already in use.

@therealkenc
Copy link
Collaborator

therealkenc commented Aug 24, 2018

So it's not just related to node. Also makes writing "portable" code fun...

Indeed. Concrete solution proposed would be to have win32 setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, &(int){1}, sizeof(int)). Which WSL and Cygwin and win32 asio and win32 libuv (nodejs) would in turn use. Under the conservative assumption that there exists Windows code out in the wild that depends on the Winsock bug.

@LAHumphreys
Copy link

I've run into the same issue with SO_REUSEADDR, although admittedly in a toy project which can be worked around locally...

https://github.com/Grauniad/WSL_SO_REUSEADDR

@Conduitry
Copy link

Is this something that's known to be fixed in 1809? I'm now getting the desired 'address in use' error on one machine running 1809, and am still seeing the listen incorrectly succeed on another machine running 1803.

@toryalsip
Copy link
Author

@Conduitry my Surface Pro is running 1809 and is still affected, so that's a negative I would say. But it is running the insider's build so I don't know if that makes a difference or not. The official 1809 has yet to hit my desktop.

@therealkenc
Copy link
Collaborator

Green 'Open' indicator at the top. The issue is not resolved.

@fananchong
Copy link

I also encountered this problem.

@azlan
Copy link

azlan commented Feb 11, 2019

Any update on this? I want to turn off this 'feature' :)

@toryalsip
Copy link
Author

I installed the latest Windows Insider build and the good news is this appears to be fixed in WSL 2.
image

@treysis
Copy link

treysis commented Sep 5, 2021

I installed the latest Windows Insider build and the good news is this appears to be fixed in WSL 2.
image

WSL2 is totally different than WSL. By the design it's no wonder it's "fixed" in WSL2. But this doesn't fix it in WSL, and many people still need to use WSL, because of the problems that come with WSL2 by design, e.g. the missing IPv6 support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants