-
-
Notifications
You must be signed in to change notification settings - Fork 61
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
Add guppy:// support #638
base: dev
Are you sure you want to change the base?
Add guppy:// support #638
Conversation
Unfortunately, the Socket class is meant to be for TCP only. Perhaps you missed the Datagram class in the_Foundation? That implements an API appropriate for UDP where there is no concept of two-way connections, just writing out and receiving messages. Please take a look at it and see if it can be used instead. For async usage, Datagram has the |
The first draft used this API, but I had to duplicate some parts of socket.c inside gmrequest.c (the async DNS resolver stuff) and wait with the request until DNS resolution succeeds. Using the Socket API with UDP made things much simpler because it takes care of DNS and connect(), maximizing code reuse and abstracting away TCP vs. UDP differences. I'll see if I can re-implement things with Datagram, I'm much more familiar with the the_Foundation API now. |
The async address resolving is done by the Address class. The Socket constructor you modified is basically just for convenience. You can always do the resolving manually with Address first. Is this the part of Socket you were duplicating? In any case, I am unwilling to change the Socket class as you were proposing initially. |
Yes, I had to keep an iAddress inside iGmRequest and pretty much duplicate addressLookedUp_Socket_(), open_Socket_(), etc'. |
I see. Another change I would request that you do is move everything related to Guppy out of gmrequest.c into a guppy.c, and have a top-level object called Guppy is different enough from Gemini and the other protocols supported by GmRequest so it's better to keep the implementation separate. I understand you're trying to reuse code, but for an experimental protocol that is not even TCP-based, the reuse should be occurring at a lower level. |
Two unhandled corner cases:
EDIT: first problem can be fixed by a small patch to run_SocketThread_():
connect() returns 0 (succeeds immediately) and errors are reported by the recv() that follows. EDIT 2: |
@skyjake Please take a second look, I moved almost everything minus the parts that change |
99017db
to
8bf17c3
Compare
Status update: Don't worry, I haven't forgotten about this. I've just been too busy to look into this more closely. The plan is to get this into the v1.18 release of Lagrange. |
Thanks for the update @skyjake! |
I reviewed the latest changes here in the PR and they look fine apart from the UDP Socket stuff, as discussed before (i.e., should use Datagram instead of Socket). Could you provide a complete patch set including changes in the_Foundation? |
Yes. Should I just fork https://git.skyjake.fi/skyjake/the_Foundation and supply a branch name? |
Yes, a branch in a forked repo should do. |
dimkr/the_Foundation@main...udp This is what I had when I opened this PR, a short patch that allows Socket to use UDP, so GmRequest can work pretty much the same way across Gemini and Guppy. EDIT: haven't tested the Windows part at all EDIT 2: oh yes, I thought it would be cleaner to make Socket support UDP, because it handles corner cases like ECONNREFUSED and takes care of DNS resolution, maximizing shared code |
Protocol is described in gemini://gemini.dimakrasner.com/guppy-v0.4.gmi (or guppy://gemini.dimakrasner.com/guppy-v0.4.gmi). EDIT: moved to gemini://guppy.000090000.xyz, guppy://guppy.000090000.xyz and https://github.com/dimkr/guppy-protocol
I was thinking, if Lagrange supports Nex, maybe it would be nice to support Guppy too, especially if this doesn't complicate the implementation of other protocols and doesn't introduce stability or security risks for those who don't use this protocol at all. v0.4 of the protocol includes additions and changes (like status code 1) that increase code reuse if support for this protocol is added to an existing Gemini client. If this protocol takes off thanks to high quality implementations of clients and servers, great! If not, this is not the end of the world and I understand that a new protocol needs special treatment in the crowded space of gmrequest.c (especially if it's based on UDP and not TCP like the others) and every line of code can be a burden.
This PR implements Guppy v0.4 support with:
This implementation is naive in some ways, I can't rule out the possibility of memory leaks or corner cases I haven't fixed, and I can see places where the implementation can be optimized to reduce memory copying at the cost of extra code complexity.
Tested against guppy://hd.206267.xyz, server code is available at https://github.com/dimkr/tootik/compare/guppy and the protocol spec contains Python examples that might be easier to understand and scrutinize for corner cases that need to be handled in a reliable and well-behaving client.
For this to work, iSocket constructor needs to receive an additional socket type parameter:
(plus something similar for win32)