zerotier / libzt

Encrypted P2P sockets over ZeroTier
https://zerotier.com
Other
173 stars 53 forks source link

How to deal with scenarios that requires cancelling? #255

Open CCRcmcpe opened 1 year ago

CCRcmcpe commented 1 year ago

I'm building a port forwarding application using the .NET binding, but struggled to let it complete an iperf3 test because an issue when dealing with cleanups, like shutdown and close.

After the forwarded service send a 0 length packet to the app, the app call shutdown (send) for the zerotier socket. But the other end does not receive the 0 length packet. So it basically has no effect. The Python example does not call shutdown either.

If you call close, the other end receive a 0 length packet, which means the other end stops receiving. However, on this end, the thread that receives the data from the zerotier socket does not stop, in other words, stuck in receive method. I don't have a way to cancel it, except to kill the thread. I think is this a last resort, and is no longer possible to acheive with current .NET API.

Any advice? Should I use poll instead to determine whether there are data to receive? I don't really understand how poll works with zerotier sockets.

CCRcmcpe commented 12 months ago

BTW I'm not very familiar with socket programming. Trying to point out the core issue, per https://stackoverflow.com/questions/60083939/what-is-the-best-way-to-cancel-a-socket-receive-request I basically have to close the socket to cancel receiving. But in libzt closing the socket does not have this effect. oops.

CCRcmcpe commented 12 months ago

And to clarify, the other end did execute close after receiving the 0 length packet. So on this end it should receive a 0 length packet to indicate that too (?), but it doesn't.

joseph-henry commented 12 months ago

Normally when you're trying to react to a socket closure you need to be polling either via poll, select, or by setting the socket to non-blocking and just seeing what you get back. There is a C example here: https://github.com/zerotier/libzt/blob/2f0f25a15870ac0ae52815558c539e63d656d506/examples/c/nonblockingserver.c that should help with the concept. Unfortunately I don't have a good C# example currently.

I did a quick check of the C# wrapper and it looks like I implemented Poll(), it is intended to work just like the native C# function so I'd try that and if you find any missing or incorrect behavior I am interested in fixing that so please bring it to my attention.

Also, feel free to make a PR if you find anything else broken in that wrapper, we are interested in improving it.

P.S. Polling a set of OS and ZT sockets together in the same FD set doesn't work but I'm introducing a new "fused polling" mode to help with this and I'll try to add it to the C# wrapper if needed.

CCRcmcpe commented 12 months ago

Thanks for the response. Polling is certainly considered, but I don't really understand the return value of it. Even if the socket is already closed (by remote), poll(can recv) still returns true.

chadrockey commented 4 months ago

@CCRcmcpe how did your port forwarder work out for you?

I do feel that this is one of the most common use cases of this library (open a local port but forward it to a ZeroTier end point). Maybe it could be done in the base library and exposed to the client libraries?