Blame SOURCES/kvm-io-simplify-websocket-ping-reply-handling.patch

9bac43
From d467ff7abd1aa30dca064883071bdd74d238567e Mon Sep 17 00:00:00 2001
9bac43
From: "Daniel P. Berrange" <berrange@redhat.com>
9bac43
Date: Wed, 20 Dec 2017 17:56:55 +0100
9bac43
Subject: [PATCH 15/42] io: simplify websocket ping reply handling
9bac43
9bac43
RH-Author: Daniel P. Berrange <berrange@redhat.com>
9bac43
Message-id: <20171220175702.29663-14-berrange@redhat.com>
9bac43
Patchwork-id: 78465
9bac43
O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 13/20] io: simplify websocket ping reply handling
9bac43
Bugzilla: 1518649
9bac43
RH-Acked-by: John Snow <jsnow@redhat.com>
9bac43
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
9bac43
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
9bac43
We must ensure we don't get flooded with ping replies if the outbound
9bac43
channel is slow. Currently we do this by keeping the ping reply in a
9bac43
separate temporary buffer and only writing it if the encoutput buffer
9bac43
is completely empty. This is overly pessimistic, as it is reasonable
9bac43
to add a ping reply to the encoutput buffer even if it has previous
9bac43
data in it, as long as that previous data doesn't include a ping
9bac43
reply.
9bac43
9bac43
To track this better, put the ping reply directly into the encoutput
9bac43
buffer, and then record the size of encoutput at this time in
9bac43
pong_remain. As we write encoutput to the underlying channel, we
9bac43
can decrement the pong_remain counter. Once it hits zero, we can
9bac43
accept further ping replies for transmission.
9bac43
9bac43
Reviewed-by: Eric Blake <eblake@redhat.com>
9bac43
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9bac43
(cherry picked from commit 57b0cdf152b7266e68bfa3e84635d4bdb64ef2cd)
9bac43
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
---
9bac43
 include/io/channel-websock.h |  2 +-
9bac43
 io/channel-websock.c         | 28 +++++++++++++++-------------
9bac43
 2 files changed, 16 insertions(+), 14 deletions(-)
9bac43
9bac43
diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h
9bac43
index ff32d86..3762707 100644
9bac43
--- a/include/io/channel-websock.h
9bac43
+++ b/include/io/channel-websock.h
9bac43
@@ -60,8 +60,8 @@ struct QIOChannelWebsock {
9bac43
     Buffer encoutput;
9bac43
     Buffer rawinput;
9bac43
     Buffer rawoutput;
9bac43
-    Buffer ping_reply;
9bac43
     size_t payload_remain;
9bac43
+    size_t pong_remain;
9bac43
     QIOChannelWebsockMask mask;
9bac43
     guint io_tag;
9bac43
     Error *io_err;
9bac43
diff --git a/io/channel-websock.c b/io/channel-websock.c
9bac43
index 04bcc05..6083f74 100644
9bac43
--- a/io/channel-websock.c
9bac43
+++ b/io/channel-websock.c
9bac43
@@ -825,11 +825,14 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
9bac43
         }
9bac43
         return -1;
9bac43
     } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) {
9bac43
-        /* ping frames produce an immediate reply */
9bac43
-        buffer_reset(&ioc->ping_reply);
9bac43
-        qio_channel_websock_encode_buffer(
9bac43
-            ioc, &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG,
9bac43
-            &ioc->encinput);
9bac43
+        /* ping frames produce an immediate reply, as long as we've not still
9bac43
+         * got a previous pong queued, in which case we drop the new pong */
9bac43
+        if (ioc->pong_remain == 0) {
9bac43
+            qio_channel_websock_encode_buffer(
9bac43
+                ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_PONG,
9bac43
+                &ioc->encinput);
9bac43
+            ioc->pong_remain = ioc->encoutput.offset;
9bac43
+        }
9bac43
     }   /* pong frames are ignored */
9bac43
 
9bac43
     if (payload_len) {
9bac43
@@ -888,7 +891,6 @@ static void qio_channel_websock_finalize(Object *obj)
9bac43
     buffer_free(&ioc->encoutput);
9bac43
     buffer_free(&ioc->rawinput);
9bac43
     buffer_free(&ioc->rawoutput);
9bac43
-    buffer_free(&ioc->ping_reply);
9bac43
     object_unref(OBJECT(ioc->master));
9bac43
     if (ioc->io_tag) {
9bac43
         g_source_remove(ioc->io_tag);
9bac43
@@ -946,12 +948,7 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc,
9bac43
     ssize_t ret;
9bac43
     ssize_t done = 0;
9bac43
 
9bac43
-    /* ping replies take priority over binary data */
9bac43
-    if (!ioc->ping_reply.offset) {
9bac43
-        qio_channel_websock_encode(ioc);
9bac43
-    } else if (!ioc->encoutput.offset) {
9bac43
-        buffer_move_empty(&ioc->encoutput, &ioc->ping_reply);
9bac43
-    }
9bac43
+    qio_channel_websock_encode(ioc);
9bac43
 
9bac43
     while (ioc->encoutput.offset > 0) {
9bac43
         ret = qio_channel_write(ioc->master,
9bac43
@@ -968,6 +965,11 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc,
9bac43
         }
9bac43
         buffer_advance(&ioc->encoutput, ret);
9bac43
         done += ret;
9bac43
+        if (ioc->pong_remain < ret) {
9bac43
+            ioc->pong_remain = 0;
9bac43
+        } else {
9bac43
+            ioc->pong_remain -= ret;
9bac43
+        }
9bac43
     }
9bac43
     return done;
9bac43
 }
9bac43
@@ -1026,7 +1028,7 @@ static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc)
9bac43
         return;
9bac43
     }
9bac43
 
9bac43
-    if (ioc->encoutput.offset || ioc->ping_reply.offset) {
9bac43
+    if (ioc->encoutput.offset) {
9bac43
         cond |= G_IO_OUT;
9bac43
     }
9bac43
     if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER &&
9bac43
-- 
9bac43
1.8.3.1
9bac43