Subject: Re: channel_read

Re: channel_read

From: Ben Kibbey <bjk_at_luxsci.net>
Date: Mon, 22 Jun 2009 22:16:08 -0400

On Wed, Jun 10, 2009 at 09:15:59PM -0400, Ben Kibbey wrote:
> hello,
>
> Theres a problem in _libssh2_transport_read() that when the calling
> function loops over it's return value (>0 in channel_read()) and nread
> != recv_amount but contains data, the next call to
> _libssh2_transport_read() will block while waiting for more data.
>
> For me, this breaks libssh2_channel_write() because it needs to "drain"
> incoming data and as a result calls _libssh2_channel_read().
>
> Seems there needs to be some way to let the calling function know that
> the pending data was received without needing to wait for more.

The problem is that _libssh2_transport_read() blocks until there is data
to be read which causes libssh2_channel_write() and
libssh2_channel_read() to block. If _libssh2_recv() could be made to
always do a non-blocking read, then restore the flags of the channel FD
then this fixes things. For me at least. Does anyone see a problem with
this:

diff --git a/src/transport.c b/src/transport.c
index 0a5d78a..9f8398d 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -352,6 +352,8 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
                little data to deal with, read more */
             ssize_t nread;
             size_t recv_amount;
+ int flags, oflags;
+ int e;
 
             /* move any remainder to the start of the buffer so
                that we can do a full refill */
@@ -367,9 +369,16 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
             recv_amount = PACKETBUFSIZE - remainbuf;
 
             /* now read a big chunk from the network into the temp buffer */
+ oflags = flags = fcntl(session->socket_fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(session->socket_fd, F_SETFL, flags);
             nread =
                 _libssh2_recv(session->socket_fd, &p->buf[remainbuf],
                               recv_amount, LIBSSH2_SOCKET_RECV_FLAGS(session));
+ e = errno;
+ fcntl(session->socket_fd, F_SETFL, oflags);
+ errno = e;
+
             if (nread <= 0) {
                 /* check if this is due to EAGAIN and return the special
                    return code if so, error out normally otherwise */

-- 
Ben Kibbey (bjk) @ FreeNode/OFTC/Jabber
------------------------------------------------------------------------------
Are you an open source citizen? Join us for the Open Source Bridge conference!
Portland, OR, June 17-19. Two days of sessions, one day of unconference: $250.
Need another reason to go? 24-hour hacker lounge. Register today!
http://ad.doubleclick.net/clk;215844324;13503038;v?http://opensourcebridge.org
_______________________________________________
libssh2-devel mailing list
libssh2-devel_at_lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel
Received on 2009-06-23