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

Add sock to stream connect parameters #344

Closed
wants to merge 17 commits into from

Conversation

diegomrsantos
Copy link
Contributor

In order to do hole punching, a peer must be able to bind to the same port as it is listening to during the dialling synchronization.

@diegomrsantos diegomrsantos force-pushed the bind-to-local-addr-new-connect branch 15 times, most recently from 8ff5ba0 to 053c806 Compare January 13, 2023 14:06
@diegomrsantos diegomrsantos marked this pull request as ready for review January 17, 2023 15:05
@diegomrsantos diegomrsantos requested review from arnetheduck and cheatfate and removed request for arnetheduck and cheatfate January 25, 2023 15:57
@diegomrsantos diegomrsantos self-assigned this Jan 25, 2023
@Menduist Menduist changed the title Bind to local addr new connect Add sock to stream connect parameters Jan 30, 2023
@cheatfate
Copy link
Collaborator

Now everything looks good, the only issue i see is that its possible to create socket which is bound to IPv6 and call connect with IPv4 address. I think we should get some work done on this case. There actually 4 cases, but the most interesting only 2:

  1. socket is IPv4 and address is IPv6 - we should check if address is IPv6 mapped address and if so, we should unwrap it and obtain IPv4 address and connect to it, or we should just raise specific exception (maybe Defect or maybe any other specific error based TransportError).
  2. socket is IPv6 and address is IPv4 - we should transform address into IPv6 mapped address and try to establish connection with it, or we should just raise specific exception (maybe Defect or maybe any other specific error based TransportError).

Why i think this is important, because different OS will start generate different TransportOSError which could become confusing at some cases and its why i think we should avoid it.

cc @arnetheduck @Menduist @diegomrsantos

@Menduist
Copy link
Collaborator

@cheatfate good point, I will take a look. Maybe you could add some helpers to #354 for this, to check if IPv6 addresses are in the "ipv4 mapped range", and helpers to switch between the two?

@Menduist
Copy link
Collaborator

Menduist commented Jan 31, 2023

Indeed, I missed them, sorry!

There is actually 3 place where the domain needs to match:
createNativeSocket
bindSocket
connect

If there is a mismatch somewhere, it will raise (22) Invalid argument [TransportOsError] on linux, or (1214) The format of the specific network name is invalid. [TransportOsError] on windows

@Menduist
Copy link
Collaborator

@cheatfate anything else blocking here? Do you want to create a specific TransportOsError exception and check for domain mismatchs in bindSocket and connect?

@arnetheduck
Copy link
Member

arnetheduck commented Feb 21, 2023

The greater problem, which somewhat goes in hand with ipv6 support, is the ownership question: after passing in a random socket, who is the owner of that socket?

This has an effect on chronos in several ways, but above all, which assumptions chronos can make about it: is it blocking? is it dual stack? is it bound? what's the buffer size -> this in turns affects the API that chronos offers, or how "thin" of a layer it is.

If a user passes in a socket which is blocking, should chronos force it to be non-blocking? This is a requirement for chronos to work, but whose responsibility is it to set the options? Should we instead expose some other socket-creation API that ensures that the socket has been created appropriately? Who closes it? Should there be a way to release the socket back to the application? what happens with in-flight requests?

Before merging this PR, this architectural question should be answered, else we end up with an API that may become unsupportable.

@Menduist
Copy link
Collaborator

Note that this api type isn't new in chronos, it's based on the datagram transport that already allows to pass in an existing socket

sock: AsyncFD = asyncInvalidSocket,

@cheatfate
Copy link
Collaborator

After a long discussion of this PR with @arnetheduck, he points my attention that this PR has significant flaw. And it is my fault that this flaw appears (createServer() definition). And i think because of this i misguided you about same functionality for connect.

The problem i'm trying to describe is owner transfership.

When chronos creates the socket it could manage it and definitely should close it by itself. Also its possible to perform any operation on every OS chronos supports.

When application creates the socket and transfers this socket to chronos via createStreamServer() or connect() - chronos should use it without any modifications and definitely should not close it. I'm trying to keep such logic everywhere in chronos, but looks like i have missed this specific case. The problem become more visible on Windows where we can't just unregister socket from IOCP queue handle, the only way to unregister handle/socket from IOCP is to close it.

So the only way to go further is to add all the options and addresses into the connect call and remove socket argument/option from both connect() and createStreamServer().

@arnetheduck
Copy link
Member

Relevant to this PR as well: #25

Re ownership, we could indeed introduce that as an "official" API, meaning that chronos takes over ownership and becomes responsible for closing later on: it would also solve the problem of socket options where chronos would set all the options it needs on the socket.

The key point would be that this needs to be made consistently clear in the API in some way: naming, sink, a special "transfer" type like unique_ptr in C++ etc - not sure what the best approach is, but as long as it is done consistently for all API, it's a possibility to explore.

The lack of solid ownership tracking in Nim will indeed open up the possibility for users to abuse ownership transfer (for example by using the socket after transferring ownership) - this is a general problem however and as long as the method we choose is well-documented and explicit, this risk is acceptable.

@Menduist
Copy link
Collaborator

Menduist commented Apr 3, 2023

#362 got merged instead

@Menduist Menduist closed this Apr 3, 2023
@arnetheduck arnetheduck deleted the bind-to-local-addr-new-connect branch June 8, 2023 09: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
Development

Successfully merging this pull request may close these issues.

None yet

4 participants