On Sat, 28 Nov 2009, Peter Stuge wrote:

I agree. But then there's nothing that prevents the lower layer functions to just use as much data it can and not to cram in more than it should into the outgoing packages.

There is for SFTP, since it is a packet based protocol. Each FXP packet starts with a length, and another FXP packet can not be started until the full packet has been sent. sftp.c must know and adjust the packet length (first 4 bytes in the SFTP packet) if lower layers can not reliably send the full packet.

I know that's how SFTP works and I still don't understand how that protocol design prevents our API/ABI to work.

App wants to send file with SFTP and calls libssh2_sftp_open().

App sends first 32k of file, expecting 32768 bytes to go out. sftp.c adds FXP protocol header and writes to the channel. channel.c adds channel protocol header and sends to transport. transport.c again adds some bytes and must now send a total of 32820 bytes onto the wire.

Yes, that's pretty much equals how an app that sends TCP uses send() but the 100 bytes the app sends equals many more IP bytes and even more ethernet bytes.

The fact that send() and recv() return such values, and all SSL libraries I've used return such numbers for their SSL_send()/SSL_recv() equivalents tell me that's a well used paradigm that I think we should keep.

The current API without sync between upper and lower layer numbers is
bad since information gets lost.

No, it's not lost information. It's a simplified world view, and I don't see how that's bad. An app that uses SFTP doesn't necessarily know about the lower layers of SSH/TCP/IP/ethernet anyway.

In order to silently work, *each* layer would require *another* state
machine which would be used to split an upper layer buffer into
multiple manageable chunks - which trickles down through all lower
layers whenever an application happens to hit the buffer size limit
for a particular layer.

I disagree. Your description is one approach to rework this to function optimally. The current way of doing it still works. It's just a bit lame with buffer sizes.

I'd like to work towards less state within libssh2, not more. :)

We will always have lots of state within libssh2. The challenge is to make the states readable and understandable.

The ABI could remain, but the API semantics need to change, and it's not so nice to make an incompatible API change without also changing the ABI. (soname I guess, but is there a big difference?)

If API semantics change, then I claim the ABI is changed as well. ABI is not just about being able to still link IMHO.

But again I don't see why this is a MUST to fix our problems.

I hope the above explains it - upper layers measure progress by how many of "their" bytes that have been sent, but each lower layer adds however many bytes it needs and there's no way for the top layer to know what is actually going out on the wire - yet "bytes sent" is being used to measure progress and track state.

Sent bytes can be used to measure state within the protocol layer, but it can of course not tell anything about the state in other layers. And it _can_ be used to measure progress, again in exactly the same way we can track a TCP transfer by counting how many bytes send() tells us it has transfered.

AFAIU libssh2 write functions returning 0 are not really well defined nor consistent, but one possibility might be to "hide" the extra bytes that way; lower layer returns 0 until all it's extra bytes have been sent.

I agree that we have some internal confusions about a return value 0, but the fact is that we MUST never treat reading or writing zero bytes as an error exactly because of the reasons you mention: it simply means that we didn't read or send any payload data but lots of protocol bits may still have flown over the wire. 0 is progress, just very little progress ;-)

Any other dealing with 0 is a bug in my eyes.

Another solution is that upper layer learns about lower layer needs; instead of counting up to 32768 in the app, it gets the 32820 number to measure progress on the wire. This is mildly confusing for app writers, but it would work well.

It would be completely crazy in my mind. What exactly would be included in that count? The SFTP_write() function is for sending N bytes to the peer. We want to know how many of those N bytes that were sent - and thus how many more we need to send before we are done. It is of no value to the app to know that when we wanted to send N bytes, M bytes were actually sent.

A better solution would be great! In any case I don't think the API can remain as is.

I disagree. The problems are not in the API or ABI, the problems are in the implementation of the functions we have.

--

 / daniel.haxx.se
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel

Reply via email to