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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

TcpStream::peer_addr and local_addr fail on Windows #397

Closed
housleyjk opened this issue May 30, 2016 · 7 comments
Closed

TcpStream::peer_addr and local_addr fail on Windows #397

housleyjk opened this issue May 30, 2016 · 7 comments
Labels

Comments

@housleyjk
Copy link
Contributor

I'm running into an issue where the same code behaves differently on Windows and Linux (big surprise 馃槃). It's led one user to request changes to the API of WS-RS (see housleyjk/ws-rs#49), but I believe the underlying issue has to do with peer_addr and local_addr on Windows. This gist, derived from the simple TCP example in the docs and using only Mio, shows that the same code runs perfectly on Linux but fails on Windows: https://gist.github.com/housleyjk/fa0ab22ef2264818c43d25ab2ed76ffb. If possible, I would like to avoid needing to provide a Windows-specific API for obtaining the peer_addr in WS-RS, and I don't know how I can get the local_addr to work on Windows.

Thank you for your consideration!

@rrichardson
Copy link
Contributor

Huh. Interestingly, peer_addr and local_addr use std::net::TcpStream which is part of the Rust standard library. There must be some disconnect where that object isn't being fully realized (fuzzy wording there) in the Mio iocp implementation.

@housleyjk
Copy link
Contributor Author

Yeah, it's as if it's not connected, but what's really strange is that you can send/receive on the stream without encountering these io errors.

@rrichardson
Copy link
Contributor

I added these lines to the accept event:

let (sock, addr) = server.accept().unwrap().unwrap();
println!("accept reported addr {:?}", addr);
println!("Accepted peer {:?}", sock.peer_addr());

And it correctly reports the address it gets from accept, but peer_addr() on the TcpStream fails in the same way. This definitely seems like a bug in the TcpStream implementation, since Mio isn't involved.

@rrichardson
Copy link
Contributor

version info:
paperspace@vm_u2861_m1516 MINGW64 ~/Projects/test_mio (master)
$ rustc --version
rustc 1.8.0 (db2939409 2016-04-11)

@rrichardson
Copy link
Contributor

NM. I was wrong: https://gist.github.com/rrichardson/4d1320cb96c59a84685505e19898e523

That works as expected when using std::net::TcpStream and TcpListener.

This means that the inner socket object in the mio TcpStream for the windows implementation isn't being properly initialized when calling accept and connect. I'm not actually sure if there is a way.

The construction logic is here:
https://github.com/carllerche/mio/blob/master/src/sys/windows/tcp.rs#L86

It might be that the accept and connect are still pending, therefore the TcpStream objects arent constructed.

ustulation added a commit to ustulation/crust that referenced this issue Jun 9, 2016
Current mio is buggy in the sense we are unable to obtain remote addr from a connected socket: tokio-rs/mio#397
The workaround is to have socket address contained as state into the closure result
ustulation added a commit to ustulation/crust that referenced this issue Jun 10, 2016
Ignore test as the bug in MIO will cause it to fail: tokio-rs/mio#397
@canndrew
Copy link
Contributor

canndrew commented Jun 14, 2016

If you call getpeername on the socket as soon as it's created with WSASocketW you get the same error: "A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.".

So is that just window's way of saying "Socket not connected"? If so, why does it still give the same error once the socket is definitely connected?

Edit: Seems it is just window's way of saying "Socket not connected". If I call getpeername directly on the accepted socket here it returns -1 but io::Error::last_os_error() returns "The operation completed successfully."

Edit: Calling getsockopt with SO_BSP_STATE instead of getpeername does the same thing, if that helps.

@alexcrichton
Copy link
Contributor

It appears that the protocol for accepting and connecting sockets is a little more involved on Windows than we originally thought! After an AcceptEx you have to call setsockopt with SO_UPDATE_ACCEPT_CONTEXT to finish the accept apparently, enabling functions like getpeername/getsockname to work. Similarly with ConnectEx it needs to be called with SO_UPDATE_CONNECT_CONTEXT.

Who knew! I've got a PR for this and I'll send it in shortly.

alexcrichton added a commit to alexcrichton/mio that referenced this issue Jul 19, 2016
Apparently there are extra steps that need to be taken after a socket finishes
being accepted and/or connected on Windows to prepare state like calling
getsockaddr and getpeeraddr. This updates the `miow` binding to where it has
these functions, then calls those functions in these situations.

Closes tokio-rs#397
alexcrichton added a commit to alexcrichton/mio that referenced this issue Jul 19, 2016
Apparently there are extra steps that need to be taken after a socket finishes
being accepted and/or connected on Windows to prepare state like calling
getsockaddr and getpeeraddr. This updates the `miow` binding to where it has
these functions, then calls those functions in these situations.

Closes tokio-rs#397
ustulation added a commit to ustulation/crust that referenced this issue Feb 14, 2017
Since [mio-bug](tokio-rs/mio#397) which crippled windows to be a stun service was fixed, enabling that test for windows too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants