impl / libcurvecpr

A portable implementation of CurveCP
40 stars 10 forks source link

There is no way to send an Initiate packet with no content #5

Open habnabit opened 11 years ago

habnabit commented 11 years ago

This is required for server-speaks-first protocols. Trying to send 0 bytes returns EINVAL, and trying to process the sendq aborts because no Message packets have been received to acknowledge, either by ID or by range.

impl commented 11 years ago

I think this is actually a flaw in the protocol itself. There's no way to send a completely empty message. Obviously that could be solved by using an implementation-specific message and handling it internally in the library, but that would break non libcurvecpr servers.

My preference however would be to solve this at a protocol level: if you need to wait for a server message, send a timestamp message or an empty string (i.e., the byte '\0'). Would that be okay?

tarcieri commented 11 years ago

Why can't you send a zero-length message? From the CurveCP message spec:

2 bytes: a 16-bit unsigned integer in little-endian form, the sum of the following integers:
* D, an integer between 0 and 1024, the size of the data block being sent as part of this message.

Why can't D be 0?

impl commented 11 years ago

Oh, interesting. The way that I had originally read the spec lead me to believe that D should only be 0 in the following cases:

However, on rereading the spec, I don't think that's true. You're right -- it should be able to be empty.

I suppose because I understood the protocol to be a stream at the highest level (which is what the GLib part of this library is trying to provide -- if you swapped in your own implementation, you could certainly implement it to be able to return 0-byte blocks when the sendq_head() callback is invoked), it didn't really make sense to support sending no data at all. (E.g., you could technically send an empty TCP packet, but why would you, except for acks?)

I feel like it'd make the API a little uglier to support "forced" empty message sending, but if the consensus is that it would be beneficial overall, I don't mind adding it. Thoughts?

habnabit commented 11 years ago

Honestly, I think that a client implementation should automatically send an empty message. In my own implementation, I send a 0-length Initiate packet with message/previous IDs 0 as soon as the Cookie packet is received. It allows either end to speak first, which seems like what you'd want as a library.

The nacl curvecpmessage seems to be able to handle this, and will specifically send a similar message (except I believe it calls this message 1) when started as curvecpmessage -c (from the usage, "program is a client; server starts first").

impl commented 11 years ago

That makes sense; the only concern I would have is that very simple protocols that have sessions only lasting a few messages would be at a disadvantage as they'd lose the ability to send data in one of those messages. Maybe that doesn't matter for the Internet these days, though.

I think it makes sense to add this as an option to the client_messager_glib implementation, in the same way that curvecpmessage provides. Sound cool?

tarcieri commented 11 years ago

Honestly, I think that a client implementation should automatically send an empty message.

I don't. In cases where the client wants to speak first (pretty much any RPC system), it's advantageous to be able to send a message in the initiate packet.