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

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