Subject: Re: proper use of non-blocking read

Re: proper use of non-blocking read

From: Eric Frias <>
Date: Mon, 15 Apr 2013 15:27:21 -0400

On 4/11/2013 5:14 PM, Daniel Stenberg wrote:
> If we really need to make two classes, then so be it. But I don't
> think it is that easy to split them up like that. Lots of the
> functions do multiple operations and EAGAIN just means that one of
> them couldn't complete and it returned out and it keeps the state for
> next call.
It's a much more minor problem than the BAD_USE problem, so it's
probably better to deal with it later.
> I agree with Chris that we should most probably strive towards more
> queueing so that we basically do "high level" atomic packet-operations
> and then we have a more lower level "data pump" that just keeps
> sending out the packets in order.
I've been looking into this, and I think it could be done in two ways.
The basic problem is that when we call _libssh2_transport_send(), there
are three possibilities: none, some, or all of the data might be sent.
Currently, the return codes for _libssh2_transport_send() will tell you
that either none or some of the data was sent via LIBSSH2_ERROR_EAGAIN,
or that all of the data was sent via LIBSSH2_ERROR_NONE.
 - The first way, which I think everyone is envisioning, is to use a
queue. When you call _libssh2_transport_send(), if it can't send the
message immediately, it will add it to a queue of messages to be sent
later, and allow the calling function to continue as if the message had
been sent. This makes the function act as if the "none sent", "some
sent", and "all sent" cases are the same, by queueing up the data to be
sent later.
 - The second is to make _libssh2_transport_send() return different
values for the "none sent" and "some sent" cases. In the "none sent",
the calling function would return LIBSSH2_ERROR_EAGAIN (and if the
calling function has state, it would not advance to the next state). In
the "some sent" case, the message is left in the session.packet to be
sent later, and the calling function will continue as if the message had
been sent. Here, "some sent" and "all sent" are handled the same, "none
sent" is handled differently.

Using a queue has the advantage of fewer cases in the state machines.
Handling the "none sent" case differently avoids the queue management
and dynamic allocation. Both solutions would require exposing some sort
of data pump function, because the caller wouldn't know if the libssh2
API function actually wrote the data or just stored it off in the
queue/session object.

So far I don't have a strong preference between the two solutions. Are
there other ways of fixing the problem worth considering?
Received on 2013-04-15