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: Windows 7 allows AF_INET, AF_INET6+IPV6_V6ONLY=1 and AF_INET6+IPV6_V6ONLY=0 listeners to coexist #7598

Closed
gopherbot opened this issue Mar 20, 2014 · 23 comments

Comments

@gopherbot
Copy link

by gregory.tseng@moovweb.com:

Attached example program: regression.go

Environment: Windows 7 x64

Go versions: 1.0.3 and 1.2 (i386)

Assumptions:
Port 80 is occupied by another process.. Skype, Apache, etc.

Observations:
With go1.0.3, the example program will error out.

With go1.2, the example program (successfully?) binds to the port

Edge case:
If the first process that binds port 80 is a go program, the go1.0.3 example program
will not error out either.

If an additional instance of the compiled example program (in either go version) is run,
it will correctly error out.

Additional notes:
I tested the program on Ubuntu 12.04 x64 and in both go versions, it errors out
correctly.

I tried testing on Mac OSX (Mountain Lion and Mavericks), but did not end up with
conclusive results, so please check this out as well.

Attachments:

  1. regression.go (178 bytes)
@gopherbot
Copy link
Author

Comment 1 by gregory.tseng@moovweb.com:

It appears that on Mac OSX Mountain Lion and Mavericks, the program does not error out
in either go versions tested.

@mikioh
Copy link
Contributor

mikioh commented Mar 21, 2014

Comment 2:

Not sure about Windows but I can't see anything described in #1 on OS X Mavericks.
dtruss says as follows:
bind(0x4, 0xC20803401C, 0x1C)        = -1 Err#48
select(0x0, 0x0, 0x0, 0x0, 0xB0080E28)       = 0 0
close(0x4)       = 0 0
// See /usr/include/sys/errno.h
#define EADDRINUSE      48              /* Address already in use */

@mikioh
Copy link
Contributor

mikioh commented Mar 21, 2014

Comment 3:

FWIW TestDualStackTCPListener in net/unicast_posix_test.go tests such behavior.
Unfortunately someone disabled it in short-mode test at tip.

@alexbrainman
Copy link
Member

Comment 4:

Tested this on both windows/32 (windows xp) and windows/amd64 (windows 7) here. Works as
expected:
c:\>go run regression.go
listen tcp :80: bind: Only one usage of each socket address (protocol/network
address/port) is normally permitted.
I'm using 740f2c9af41e tip here.
gregory.tseng, how can I reproduce your problem? Perhaps you are mistaken?
Alex

Status changed to WaitingForReply.

@gopherbot
Copy link
Author

Comment 5 by gregory.tseng@moovweb.com:

Mac OSX Mavericks:
1) Try running this python server to occupy port 80, then try running the test program
with the two versions of go I tested.
sudo python -m SimpleHTTPServer 80
2) Both go programs will listen and bind.
sudo lsof -i -P | grep LISTEN | grep :80
Python    84239           root    3u  IPv4 0xa65145c3d4ad2ac3      0t0    TCP *:80
(LISTEN)
regressio 84374           root    4u  IPv6 0xa65145c3cdf51723      0t0    TCP *:80
(LISTEN)
Windows:
The error I found was on the released version of go1.2.
The error does not occur on the released version of go1.0.3
To reproduce, 
1) please run a program that binds to port 80 that is not a compiled go program.
2) Then try running the program with the two versions of go I tested.
If this is fixed in tip, then great. I'll try tip if I get a chance.

@mikioh
Copy link
Contributor

mikioh commented Mar 21, 2014

Comment 6:

gregory.tseng,
That's the reason why I mentioned TestDualStackTCPListener. It's obvious that your 1st
tcp endpoint holder uses address family IPv4, and 2nd one uses IPv6. How should we
behave on the dual IP stack node that implements either BIA (bump-in-API) or BIS
(bump-in-stack) feature? I think this is equivalent to tcp4+"", then tcp6+"" case in
http://golang.org/src/pkg/net/unicast_posix_test.go#L112.
I'm guessing that the difference btw go1.0.3 and go1.2 comes from the fix for issue
2581. So I'd like to say that current behavior is expected, and sorry for the confusion.
That issue #2581 was one of my blunders submitted in just before Go 1 release.
net: OS X allows duplicate listen in single process?
http://golang.org/issue/2581

@mikioh
Copy link
Contributor

mikioh commented Mar 22, 2014

Comment 7:

Status changed to WorkingAsIntended.

@mikioh
Copy link
Contributor

mikioh commented Mar 22, 2014

Comment 8:

Ah, I missed Windows part. For the record, looks like gregory.tseng had two questions:
Q1) Why the behavior of tcp listeners on the dual IP stack node is different btw
Unix-like systems?
Q2) Why go1.0.3 on Windows 7 rejects the dual IP stack node behavior?
Here are answers:
A1) Basically It's depends on the protocol stack inside the kernel, but net package
struggles to abstract a bit
A2) Windows port for go1.0.x doesn't implement support for IPv6

@gopherbot
Copy link
Author

Comment 9 by gregory.tseng@moovweb.com:

Ahhhhh thanks for clarifying the dual stack behavior. I did not understand your first
comment about the short-mode tests.
I've attached a new program that tests each of the Listen protocols individually...
I understand now that if I specify "tcp", it will auto detect and bind to available.
However... I'm still observing that, on Windows 7, if I already have a process that
binds to both tcp4 and tcp6
and I run go1.2 program, the Listen method with "tcp" specified still seems to work.
Random program bound to 80 in both tcp4 and tcp6
netstat -ano | findstr LISTEN | findstr :80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       10328
  TCP    [::]:80                [::]:0                 LISTENING       10328
Running go program with net.Listen("tcp", ":http")
netstat -ano | findstr LISTEN | findstr :80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       7604
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       10328
  TCP    [::]:80                [::]:0                 LISTENING       10328
  TCP    [::]:80                [::]:0                 LISTENING       7604
Is this still the expected behavior? Forgive my ignorance if I'm still missing something.

Attachments:

  1. dualstack.go (491 bytes)

@mikioh
Copy link
Contributor

mikioh commented Mar 22, 2014

Comment 10:

Awesome Windows networking stack. I've never imagined that it would be possible, but
BIS-style implementation might be, but for what purposes? hm, interesting.
I can't say it's a expected behavior, but it's pretty Windows-specific, so leave to Alex
or other Windows expert.
gregory.tseng: I have no clue how to fix (fix?) this because at the moment we do almost
nothing to control Windows  networking stack. Perhaps a workaround would be "please
don't do that" for years.
See http://golang.org/src/pkg/net/sockopt_windows.go

Labels changed: added repo-main, os-windows.

Status changed to New.

@mikioh
Copy link
Contributor

mikioh commented Mar 24, 2014

Comment 11:

gregory.tseng,
Looks like attached program in #9 just just does close Listener when Listen succeeds in
listenOn function. Is this correct one? (I think not because Listener.Close will cancel
its address:port book inside the kernel)

Status changed to WaitingForReply.

@gopherbot
Copy link
Author

Comment 12 by gregorygtseng:

The only purpose of the attached program from #9 was to distinguish the differences when
net.Listen specifies "tcp", "tcp4", or "tcp6" on different OSes, and on go versions
1.0.3 and 1.2
Before running this program, I run a separate program to occupy the port/protocol, and
test.

@mikioh
Copy link
Contributor

mikioh commented Mar 24, 2014

Comment 13:

Then, for our sakes:
1) can you show us the output of "go test net -v -run=TestDualStackTCPListener" with
go1.2 on Windows 7?
2) Also can you provide a concrete procedure to reproduce what you got in #9 with go1.2
on Windows 7?
Thanks for your cooperation.

@gopherbot
Copy link
Author

Comment 14 by gregorygtseng:

1) The test is passing:
D:\Desktop>go version
go version go1.2 windows/amd64
D:\Desktop>go test net -v -run=TestDualStackTCPListener
=== RUN TestDualStackTCPListener
--- PASS: TestDualStackTCPListener (0.14 seconds)
PASS
ok      net     0.779s
2) I've attached a very crude test program where it listens on a certain protocol, and
spawns a second listener on each of the protocols...
While running this, I have another command prompt open that is monitoring the ports with
this simple batch script.
Is any of the behavior because of SO_REUSEADDR? I read about that briefly, but it's
currently beyond my understanding, and I'm not sure if I can set that in my Go programs.

Attachments:

  1. monitorport.bat (99 bytes)
  2. dualstack2.go (1323 bytes)

@mikioh
Copy link
Contributor

mikioh commented Mar 24, 2014

Comment 15:

Thanks, it would be great help for us.
> Is any of the behavior because of SO_REUSEADDR?
I guess not. For now we never set SO_REUSEADDR to 1 for stream listener sockets on
Windows. Perhaps, it's related to IPV6_V6ONLY. When you have three listeners on 80/tcp,
not sure the reason, but probably they are:
1) AF_INET, 80/tcp4, single endpoint,
2) AF_INET6, 80/tcp6, IPV6_V6ONLY=1, single endpoint,
3) AF_INET6, 80/tcp4 and 80/tcp6, IPV6_V6ONLY=0, dual endpoints,
Hmm...

@mikioh
Copy link
Contributor

mikioh commented Mar 24, 2014

Comment 16:

Status changed to New.

@mikioh
Copy link
Contributor

mikioh commented Apr 11, 2014

Comment 17:

Note that it looks like the host functionality of Windows network stack prefers
AF_INET/IPV6_V6ONLY=1 listeners rather than IPV6_V6ONLY=1 listeners; not sure in the
case of router functionality.

Status changed to HelpWanted.

@alexbrainman
Copy link
Member

Comment 18:

mikioh,
I don't use ipv6 (don't have it here, don't know how to use it), and unfortunately don't
have time to learn now. Sorry.
Alex

@mikioh
Copy link
Contributor

mikioh commented Apr 11, 2014

Comment 19:

typo in #17: s/rather than IPV6_V6ONLY=1/rather than IPV6_V6ONLY=0/

@rsc
Copy link
Contributor

rsc commented May 21, 2014

Comment 20:

Labels changed: added release-none.

@mattn
Copy link
Member

mattn commented Jan 16, 2015

I tried this. When listening another port like :8888 by nc.exe, regression.exe could bind same port.
But it couldn't with :http. So I guess, this is depend on Windows ACL. IIS or special application are allowed to listen with port 80. I think this is closable.

@mikioh mikioh changed the title net: Windows 7 allows AF_INET/AF_INET6 and AF_INET6/IPV6_V6ONLY=0 listeners to coexist net: Windows 7 allows AF_INET, AF_INET6+IPV6_V6ONLY=1 and AF_INET6+IPV6_V6ONLY=0 listeners to coexist Jan 16, 2015
@mikioh
Copy link
Contributor

mikioh commented Jan 17, 2015

@mattn,

The issue here is that we are able to have three TCP listeners on the same port when we use configurations as follows:

No. Network arg. Address arg. Socket address family IPV6_V6ONLY option
1 "tcp" [::]:port AF_INET6 0
2 "tcp4" 0.0.0.0:port AF_INET N/A
3 "tcp6" [::]:port AF_INET6 1

Can you please confirm that;

  • It doesn't appear to be happening when we choose a TCP service port other than 80
  • When we have three listeners, Windows always prefers the No. 1 listener than the No. 3

Thanks.

@mikioh
Copy link
Contributor

mikioh commented Nov 27, 2016

I will close this issue as "working as intended" because looks like this is Windows-specific IP dual stack behavior and there's no helpful information. Also the IP dual stack implementation on Windows may be different between versions.

@mikioh mikioh closed this as completed Nov 27, 2016
@golang golang locked and limited conversation to collaborators Nov 27, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants