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

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