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

Port is being re-bound under windows 10 (native shell) preventing portfinder logic from working #39

Closed
dharmax opened this issue Sep 5, 2016 · 28 comments · Fixed by #42

Comments

@dharmax
Copy link

dharmax commented Sep 5, 2016

However, this simple code does work:
export function findFreePort() { return new Promise((resolve, reject) => { var server = createServer() , port = 0 server.on("listening", function () { port = server.address().port server.close() }) server.on("close", function () { resolve(port) }) server.on('error', function (err) { reject(err) }) server.listen(0, '127.0.0.1') }) }

@eriktrom
Copy link
Member

eriktrom commented Sep 5, 2016

howdy @dharmax - can you provide more info?

What do you mean by

it always gives me 800

do you mean 8000? The base port starts at 8000 here: https://github.com/indexzero/node-portfinder/blob/39e39603ec1f5dd27d5fafa9ea1dc7d2e5a558fd/lib/portfinder.js#L73

If you give me some more detail I'm more than glad to help work through this with you.

Thanks!

@dharmax
Copy link
Author

dharmax commented Sep 5, 2016

Sorry, 8000, yeah.
Even if it already in use, of course.

@eriktrom
Copy link
Member

eriktrom commented Sep 5, 2016

Thanks @dharmax for confirming - which version of portfinder are you running?

If your running the latest version, do mind setting this env var before you start your process:

DEBUG=portfinder*

e.g.,:

DEBUG=portfinder* node index.js

If you have a chance, paste that into a gist and drop me the link - I'll figure it out from there.

Thanks again

@noahzark
Copy link

@eriktrom @indexzero
Hi,

I also have the same probelm on Windows 10 (Version 10.0.10586) development machine, but works well on Linux machines. Seems windows 10 is allowing http.createServer(express()) and net.createServer listening on the same port with the same host (though the net server isn't working).

The screenshots are here:
http://imgur.com/a/libNy

Here are the steps to reproduce:

  1. I have an express http server listening on 10004
    http://imgur.com/laHP9rP
  2. When I set basePort to 10004 and call portfinder.getPort(), it doesn't throw an error. Instead, it fires a listening event and calls the onListen callback
    http://imgur.com/HbXst7C
  3. When breaking on line 43 of portfinder, I tried the "netstat -an | grep 10004", and it shows two programs are listening on 0.0.0.0:10004
    http://imgur.com/b8RGdDU

TCP 0.0.0.0:10004 0.0.0.0:0 LISTENING
TCP 0.0.0.0:10004 0.0.0.0:0 LISTENING
TCP [::]:10004 [::]:0 LISTENING

Here are my packages:

"dependencies": {
        "express": "3.4.x",
        "socket.io": "0.9.x",
        "portfinder": "1.0.7",
        "config": "1.21.x"
    },
    "engines": {
        "node": "0.10.x",
        "npm": "1.2.x"
    }

Since many people are using Node express http server, and net server is failing, so maybe we need to use http server to test a port's availability?

@eriktrom
Copy link
Member

eriktrom commented Sep 24, 2016

howdy @noahzark - thanks for the detailed report

Couple of quick questions will help me a bunch:

  1. What version of node (engines prop says 0.10.x, is that correct?)
  2. Did this occur on windows 8 (if u dont know, no worries)
  3. Can you open a node shell via node on ur command line, then type os.networkInterfaces() and paste the output here (or in a linked gist if its long)
  4. Can u try this in node >= 12 if u are using node 10 -- thanks a bunch for time here

perhaps very important note - node 6 is about to become LTS so @noahzark verifying u can't bind to 0.0.0.0 with the same port on a normal node server in windows 10 is rather important for users long term - check that out... (aka, run this same experiment in node 6, it should not reproduce, if it does, we file bug upstream in node quickly)

EDIT: Does this bind twice as well? (if no python, no worries):

python -m SimpleHTTPServer 10004
python -m SimpleHTTPServer 10004

Background/Diagnosis: The output that u pasted says there are 3 servers running on port 10004, 2 of them on host 0.0.0.0 and one on [::] - which currently (to me) seems like a bug in node or windows 10. The interesting thing about 0.0.0.0 is that it might (especially in this case) bind to any real interface that is external, meaning it could really be bound twice - to say (as an example) 10.0.1.2 and 10.0.1.3 under the hood. In Linux it will simply choose en0 and default to ipv4 limiting that range to only one interface (I presume in most/all cases) - but in windows 10 - looks like this assumption does not hold...

Thanks again for finding this and the great detail in ur bug report - ur awesome :)

(fyi @stefanpenner - ping me if u see this in ember-cli/angular-cli 👍)

@noahzark
Copy link

noahzark commented Sep 24, 2016

@eriktrom Thank you so much for your response, it really helps a lot.

  1. Actually I'm using Node 6.5
  2. All my Window$ 8 machines were upgraded to 10, so I'm unable to confirm (LOL
  3. These are my network interfaces:
D:\Workspace\porttest>node -v
v6.5.0

D:\Workspace\porttest>node
> os.networkInterfaces()
{ Ethernet:
   [ { address: 'fe80::3de6:795c:d6c8:8ad2',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: 'd8:cb:8a:5d:3a:e4',
       scopeid: 17,
       internal: false },
     { address: '192.168.199.10',
       netmask: '255.255.255.0',
       family: 'IPv4',
       mac: 'd8:cb:8a:5d:3a:e4',
       internal: false } ],
  'VMware Network Adapter VMnet1':
   [ { address: 'fe80::3960:b8bf:faa5:4e03',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:50:56:c0:00:01',
       scopeid: 13,
       internal: false },
     { address: '192.168.160.1',
       netmask: '255.255.255.0',
       family: 'IPv4',
       mac: '00:50:56:c0:00:01',
       internal: false } ],
  'VMware Network Adapter VMnet8':
   [ { address: 'fe80::ed8d:6ebe:b2c6:6d19',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:50:56:c0:00:08',
       scopeid: 2,
       internal: false },
     { address: '192.168.137.1',
       netmask: '255.255.255.0',
       family: 'IPv4',
       mac: '00:50:56:c0:00:08',
       internal: false } ],
  'Loopback Pseudo-Interface 1':
   [ { address: '::1',
       netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
       family: 'IPv6',
       mac: '00:00:00:00:00:00',
       scopeid: 0,
       internal: true },
     { address: '127.0.0.1',
       netmask: '255.0.0.0',
       family: 'IPv4',
       mac: '00:00:00:00:00:00',
       internal: true } ] }

  1. Since I was using an old version of express server, I wrote a small test script. Unfortunately it still doesn't work.
    Here is the screen shot:
    http://imgur.com/eA3lFEj
    You can try it if you have a PC:
    https://codepad.remoteinterview.io/XTDLDMLIJT
  2. Yes you are right, as far as I know, in Windows environment(not sure but at least in 7,8,10), bind to "0.0.0.0" will bind to all available interfaces (tried in C, Java, Python and so on). It's not node/Windows' bug, maybe just a characteristic
  3. Yes, python simple http server will bind twice too (LOL
    Screenshot:
    http://imgur.com/4ud45Ym

So, in my previous projects I used socket to find available ports, it used to be working on Windows 7, but seems broken on Windows 10 I used DGRAM to listen on UDP, after changed to TCP(SOCK_STREAM), it's working

image

image

@eriktrom eriktrom changed the title It simply doesn't work for me. it always give me 800. Port is being bound when already in use b/c of 0.0.0.0 auto-binding Sep 27, 2016
eriktrom added a commit that referenced this issue Sep 27, 2016
- Binding to 0.0.0.0 was used in an earlier iteration of the port finding
  logic. That logic has since been replaced by explicitly testing the
  OS's network interfaces and is thus no longer of use.

fixes #39
@eriktrom
Copy link
Member

@noahzark - hey I really appreciate the info u provided. I pushed what I believe should fix the issue to 6ee0553 - do u mind merging or installing that sha directly into ur setup to test it out

tl;dr - we no need longer look at 0.0.0.0 - that logic was old, incorrect and no longer needed as of 1.0.7 - (wahoo!)

@noahzark
Copy link

noahzark commented Oct 2, 2016

@eriktrom Hmm... Seems this fix still doesn't work due to the Windows allows to bind several times using the same port & host options.server.listen(options.port, options.host); (Seems it's not a node bug but the system's bug)

When I tried to remove the options.host argument and changed that line to options.server.listen(options.port); The error event is normally triggered. So the conclusion is that Windows doesn't allow one program binds to one port (and all interfaces), but allows one program binds to one port (on one specific interface)

So I'm wondering if we can ignore the interfaces and just bind to the port on Windows ( Just like the elder portfinder version works well on the M$ platform

@artch
Copy link

artch commented Oct 6, 2016

I can confirm that portfinder doesn't work on Windows 10 as expected, always indicating a busy port as free. The entire module purpose is compromised. I think this is a breaking bug which must be fixed ASAP.

@eriktrom
Copy link
Member

eriktrom commented Oct 6, 2016

@noahzark - just to clarify this sentence in context of the way the old portfinder worked

So I'm wondering if we can ignore the interfaces and just bind to the port on Windows ( Just like the elder portfinder version works well on the M$ platform

In older versions, if you started a python server on port X and then ask portfinder to find an open port, starting with X, it would happily say 'yes port X is open' when the truth is 'Yes port X is open, but on a different interface (and therefore w/ a different ip address) than you may have expected'.

Sorry @noahzark - I don't follow this sentence:

The error event is normally triggered. So the conclusion is that Windows doesn't allow one program binds to one port (and all interfaces), but allows one program binds to one port (on one specific interface)

Can you re-phrase if u get a chance?

@artch - yes I agree - the problem is that I'm not exactly sure how to handle this issue yet. Last week I read through net, http and dns modules inside the node source code, including some of the libuv code - and scanned through the issue list as well - the issue you mention specifically

always indicating a busy port as free

is certainly a problem

If there is a way we can think of to hack around the fact that windows will NOT bind (as @noahzark mentioned in any language) to busy ports as though they are free, I'm all ears. I honestly thought the removing the 0.0.0.0 line would fix it.

I suppose one hack that would work, while a bit crazy, but would work - would be to start the server that checks each port, make a request, and if the handler gets hit, pipe OK to the body of the http response, shutdown the server and keep the port if the response matches, throw it away if it doesn't. In reality this won't take much longer than the current logic, and could be windows specific

I'll write that code but I'd love to hear any feedback for suggestions for another implementation thats not so hacky if someone has any thoughts.

To be clear the old way that port finder worked did not take into account this binding to multiple interfaces(or hosts within a single interface) and thus any port it found was literally dumb luck. #13 has the details on that.

Thanks for your help all and @artch - we'll get this fixed up - sorry I didn't respond earlier this week - I am just not yet sure of the best answer. I do realize the urgency.

@artch
Copy link

artch commented Oct 6, 2016

I suppose one hack that would work, while a bit crazy, but would work - would be to start the server that checks each port, make a request, and if the handler gets hit, pipe OK to the body of the http response, shutdown the server and keep the port if the response matches, throw it away if it doesn't. In reality this won't take much longer than the current logic, and could be windows specific

This sounds like pretty reliable approach to me.

@eriktrom
Copy link
Member

eriktrom commented Oct 6, 2016

@artch - thanks for the feedback 👍

One question I have is:

When windows 10 allows re-binding to a host+port, like in the python simple http server example, does the second 'bind' take precedence over the first?

Regardless - on friday night I'll have access to a few machines that can run my Parallels install of Windows 10 and I'll make these changes and test out this monkey business thats going on. My own macbook pro 13 inch w/ 8gb of ram and limited ssd drive space hardly runs it. Boo.)

Till then, worth noting you can pass a host and port explicitly - although not sure that'll give you 'the truth' ATM on windows 10 - unless your sure host+port are open, just fyi.

@eriktrom eriktrom changed the title Port is being bound when already in use b/c of 0.0.0.0 auto-binding Port is being re-bound under windows 10 (native shell) preventing portfinder logic from working Oct 10, 2016
eriktrom added a commit that referenced this issue Oct 17, 2016
- Windows 10 native shell(#39) was rebinding to already bound ports. We
  now send a message from a socket client -> server -> client to ensure
  a host + port are actually open
- Windows 10 bash shell falls back to using 0.0.0.0 as the only host we
  check in order to prevent throwing a syscall error as being tracked here:
  microsoft/WSL#468

fixes: #39
closes: #41
fixes: ember-cli/ember-cli#6338
@eriktrom eriktrom reopened this Oct 19, 2016
@eriktrom
Copy link
Member

@artch @noahzark - fwiw - I shipped the proposed fix for windows native shell and it broke on computers with bluetooth enabled.

I currently don't have another way to hack around the way windows 10 is allowing u to bind to a port more than once. If u guys come across such knowledge, drop me a note here.

@khrome83
Copy link

khrome83 commented Nov 6, 2016

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/index.global.css 4:14-125 13:2-17:4 14:20-131

Get this issue after using the windows 10 branch. I fixed the issue with It calling the var interfaces = os.networkInterfaces(), but started causing the above problem.

@eriktrom
Copy link
Member

eriktrom commented Nov 8, 2016

@khrome83 - yeah sorry about that - so to clarify - there are 2 windows 10 issues - one with the native shell and one with the bash shell - if you hit uv_interface_addresses that means u must have been using the bash shell, which does not have a networking stack ATM - u can follow that issue here: microsoft/WSL#468

I had a hack in place for the windows 10 bash shell that did work - which I may add back in although I'd rather wait for windows bash shell to add networking to their stack - but let me know ur opinion and if u think we should add back in that hack

@khrome83
Copy link

khrome83 commented Nov 8, 2016

@eriktrom In the short term, the hack would be ideal. Even if it's just on a separate branch. I am on the Insiders ring, and it will still take months to make it too me on the Slow Ring given the release path before, and the users not on Insiders ring won't receive the update until the Windows 10 Creative update launch I assume.

Are there any downsides on leaving the hack in?

@eriktrom
Copy link
Member

eriktrom commented Nov 8, 2016

@khrome83 - actually its on master ATM - do u mind working off that - let me know if u hit any issues too - if not I'll cut a release with master as is

I merged this in a couple weeks back - haven't released to npm though (b/c I haven't fully had the time to battle test it) - #46

downsides to leaving the hack are minimal - there are a number of repos that have this hack

@eriktrom
Copy link
Member

eriktrom commented Nov 8, 2016

@khrome83 - hows master working out - I don't launch windows much - let me know if u do use it - thanks a bunch

@khrome83
Copy link

Going to give this a shot and see if it resolves the issue. Sorry @eriktrom I have not had a chance to look into it. Was working on my MacBook. Reinstalling the repo on the SurfaceBook to see if master resolves the issue.

@eriktrom
Copy link
Member

ur awesome thanks again

if things are not working - u can set the env var DEBUG=portfinder* and you'll get some overly verbose debug logging, which u might throw into a gist, just fyi

it works in parallels, never tried a real windows machine, so really, thanks

@khrome83
Copy link

It got me past my pervious error. Now I am getting a different issue.


✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/index.global.css 4:14-125 13:2-17:4 14:20-131

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/highlight.global.css 4:14-129 13:2-17:4 14:20-135

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/layouts/Page/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/layouts/PageError/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Footer/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Header/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Navigation/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Container/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Content/index.css 4:14-192 13:2-17:4 14:20-198

✖ Error in EINVAL: invalid argument, uv_interface_addresses
 @ ./src/components/Loading/index.css 4:14-192 13:2-17:4 14:20-198

Guessing this is a webpack problem though. Posting here just in case you think otherwise.

@eriktrom
Copy link
Member

eriktrom commented Nov 10, 2016

Yeah - looks like webpack - maybe fix it for them - here is how yarn package manager fixed their issue https://github.com/yarnpkg/yarn/pull/772/files - the code for portfinder (bottom of portfinder js, from #46 is very similar, easy pickins i'd say :)

@eriktrom
Copy link
Member

also - thanks - i'll make the move in the morning to cut a release now that I have double verification that it works - if something changes and u find a bug, drop me a HALP comment so I dont release a bad version :)

@NemoStein
Copy link

I'm having this problem (portfinder not working as expected on Win10) and found this issue, but, after reading the entire discussion I'm not sure if it was fixed or not.
So, I must ask: Do we have a solution/workaround?

@eriktrom
Copy link
Member

Sorry it's not fixed yet. Look for it soon though

Work around in the meantime is pass a port that u know is open for sure.

@Leftium
Copy link

Leftium commented Jan 11, 2018

This package works in Windows 10: https://www.npmjs.com/package/get-port

The API is very similar.

@eriktrom
Copy link
Member

@Leftium - thanks for the link

I don't believe this is an issue any longer. IIRC (more than a year ago) this issue only happened when using the developer build of windows 10 and checking the box that said something like 'allow port rebinding' within the developer experiments settings (same settings panel where you turn on bash for windows)

closing, thanks again for the alternate package, perhaps I can find some answers for things I never fully understood in this package (os level stuff in node -> libuv intricacies)

@Leftium
Copy link

Leftium commented Jan 11, 2018

Oh, I think I misinterpreted this issue. If my problem is a different issue, I can open a new issue.

If another instance of my app was already using port 80, portfinder used to give the 2nd instance of my app port 81. Now it just throws this error (which defeats the purpose of using portfinder):

Error: listen EADDRINUSE :::80
    at Object._errnoException (util.js:1024:11)
    at _exceptionWithHostPort (util.js:1046:20)
    at Server.setupListenHandle [as _listen2] (net.js:1351:14)
    at listenInCluster (net.js:1392:12)
    at Server.listen (net.js:1476:7)
    at Function.listen (C:\Dropbox\p\adhoc\node_modules\connect\index.js:217:24)
    at listen (C:\Dropbox\p\adhoc\bin\adhoc:71:12)
    at C:\Dropbox\p\adhoc\bin\adhoc:62:13
    at C:\Dropbox\p\adhoc\node_modules\portfinder\lib\portfinder.js:160:14
    at C:\Dropbox\p\adhoc\node_modules\async\lib\async.js:52:16

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