Blame SOURCES/0008-_libssh2_channel_read-fix-data-drop-when-out-of-wind.patch

6fd6a0
From cae2385ba898f71038ed4dd00ddae02f85e588e7 Mon Sep 17 00:00:00 2001
6fd6a0
From: Salvador <sfandino@yahoo.com>
6fd6a0
Date: Tue, 15 Oct 2013 11:45:10 +0200
6fd6a0
Subject: [PATCH 08/11] _libssh2_channel_read: fix data drop when out of window
6fd6a0
6fd6a0
After filling the read buffer with data from the read queue, when the
6fd6a0
window size was too small, "libssh2_channel_receive_window_adjust" was
6fd6a0
called to increase it. In non-blocking mode that function could return
6fd6a0
EAGAIN and, in that case, the EAGAIN was propagated upwards and the data
6fd6a0
already read on the buffer lost.
6fd6a0
6fd6a0
The function was also moving between the two read states
6fd6a0
"libssh2_NB_state_idle" and "libssh2_NB_state_created" both of which
6fd6a0
behave in the same way (excepting a debug statment).
6fd6a0
6fd6a0
This commit modifies "_libssh2_channel_read" so that the
6fd6a0
"libssh2_channel_receive_window_adjust" call is performed first (when
6fd6a0
required) and if everything goes well, then it reads the data from the
6fd6a0
queued packets into the read buffer.
6fd6a0
6fd6a0
It also removes the useless "libssh2_NB_state_created" read state.
6fd6a0
6fd6a0
Some rotted comments have also been updated.
6fd6a0
6fd6a0
Signed-off-by: Salvador <sfandino@yahoo.com>
6fd6a0
6fd6a0
[upstream commit 27f9ac2549b7721cf9d857022c0e7a311830b367]
6fd6a0
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
6fd6a0
---
6fd6a0
 src/channel.c |   75 +++++++++++++++++++--------------------------------------
6fd6a0
 1 files changed, 25 insertions(+), 50 deletions(-)
6fd6a0
6fd6a0
diff --git a/src/channel.c b/src/channel.c
6fd6a0
index 499d815..82f6980 100644
6fd6a0
--- a/src/channel.c
6fd6a0
+++ b/src/channel.c
6fd6a0
@@ -1751,31 +1751,33 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
6fd6a0
     LIBSSH2_PACKET *read_packet;
6fd6a0
     LIBSSH2_PACKET *read_next;
6fd6a0
 
6fd6a0
-    if (channel->read_state == libssh2_NB_state_idle) {
6fd6a0
-        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
6fd6a0
-                       "channel_read() wants %d bytes from channel %lu/%lu "
6fd6a0
-                       "stream #%d",
6fd6a0
-                       (int) buflen, channel->local.id, channel->remote.id,
6fd6a0
-                       stream_id);
6fd6a0
-        channel->read_state = libssh2_NB_state_created;
6fd6a0
-    }
6fd6a0
+    _libssh2_debug(session, LIBSSH2_TRACE_CONN,
6fd6a0
+                   "channel_read() wants %d bytes from channel %lu/%lu "
6fd6a0
+                   "stream #%d",
6fd6a0
+                   (int) buflen, channel->local.id, channel->remote.id,
6fd6a0
+                   stream_id);
6fd6a0
 
6fd6a0
-    /*
6fd6a0
-     * =============================== NOTE ===============================
6fd6a0
-     * I know this is very ugly and not a really good use of "goto", but
6fd6a0
-     * this case statement would be even uglier to do it any other way
6fd6a0
-     */
6fd6a0
-    if (channel->read_state == libssh2_NB_state_jump1) {
6fd6a0
-        goto channel_read_window_adjust;
6fd6a0
-    }
6fd6a0
+    /* expand the receiving window first if it has become too narrow */
6fd6a0
+    if((channel->read_state == libssh2_NB_state_jump1) ||
6fd6a0
+       (channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30))) {
6fd6a0
+
6fd6a0
+        /* the actual window adjusting may not finish so we need to deal with
6fd6a0
+           this special state here */
6fd6a0
+        channel->read_state = libssh2_NB_state_jump1;
6fd6a0
+        rc = _libssh2_channel_receive_window_adjust(channel,
6fd6a0
+                                                    (LIBSSH2_CHANNEL_WINDOW_DEFAULT*60),
6fd6a0
+                                                    0, NULL);
6fd6a0
+        if (rc)
6fd6a0
+            return rc;
6fd6a0
 
6fd6a0
-    rc = 1; /* set to >0 to let the while loop start */
6fd6a0
+        channel->read_state = libssh2_NB_state_idle;
6fd6a0
+    }
6fd6a0
 
6fd6a0
-    /* Process all pending incoming packets in all states in order to "even
6fd6a0
-       out" the network readings. Tests prove that this way produces faster
6fd6a0
-       transfers. */
6fd6a0
-    while (rc > 0)
6fd6a0
+    /* Process all pending incoming packets. Tests prove that this way
6fd6a0
+       produces faster transfers. */
6fd6a0
+    do {
6fd6a0
         rc = _libssh2_transport_read(session);
6fd6a0
+    } while (rc > 0);
6fd6a0
 
6fd6a0
     if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN))
6fd6a0
         return _libssh2_error(session, rc, "transport read");
6fd6a0
@@ -1857,8 +1859,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
6fd6a0
     }
6fd6a0
 
6fd6a0
     if (!bytes_read) {
6fd6a0
-        channel->read_state = libssh2_NB_state_idle;
6fd6a0
-
6fd6a0
         /* If the channel is already at EOF or even closed, we need to signal
6fd6a0
            that back. We may have gotten that info while draining the incoming
6fd6a0
            transport layer until EAGAIN so we must not be fooled by that
6fd6a0
@@ -1871,34 +1871,9 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
6fd6a0
         /* if the transport layer said EAGAIN then we say so as well */
6fd6a0
         return _libssh2_error(session, rc, "would block");
6fd6a0
     }
6fd6a0
-    else {
6fd6a0
-        channel->read_avail -= bytes_read;
6fd6a0
-        channel->remote.window_size -= bytes_read;
6fd6a0
-        /* make sure we remain in the created state to focus on emptying the
6fd6a0
-           data we already have in the packet brigade before we try to read
6fd6a0
-           more off the network again */
6fd6a0
-        channel->read_state = libssh2_NB_state_created;
6fd6a0
-    }
6fd6a0
-
6fd6a0
-    if(channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30)) {
6fd6a0
-        /* the window is getting too narrow, expand it! */
6fd6a0
-
6fd6a0
-      channel_read_window_adjust:
6fd6a0
-        channel->read_state = libssh2_NB_state_jump1;
6fd6a0
-        /* the actual window adjusting may not finish so we need to deal with
6fd6a0
-           this special state here */
6fd6a0
-        rc = _libssh2_channel_receive_window_adjust(channel,
6fd6a0
-                                                    (LIBSSH2_CHANNEL_WINDOW_DEFAULT*60), 0, NULL);
6fd6a0
-        if (rc)
6fd6a0
-            return rc;
6fd6a0
 
6fd6a0
-        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
6fd6a0
-                       "channel_read() filled %d adjusted %d",
6fd6a0
-                       bytes_read, buflen);
6fd6a0
-        /* continue in 'created' state to drain the already read packages
6fd6a0
-           first before starting to empty the socket further */
6fd6a0
-        channel->read_state = libssh2_NB_state_created;
6fd6a0
-    }
6fd6a0
+    channel->read_avail -= bytes_read;
6fd6a0
+    channel->remote.window_size -= bytes_read;
6fd6a0
 
6fd6a0
     return bytes_read;
6fd6a0
 }
6fd6a0
-- 
6fd6a0
1.7.1
6fd6a0