[spice-server,3/4] red-channel-client: Allows to block receiving data

Submitted by Frediano Ziglio on June 17, 2019, 3:40 p.m.

Details

Message ID 20190617154011.20310-3-fziglio@redhat.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Frediano Ziglio June 17, 2019, 3:40 p.m.
If the client is keeping sending data while we can't handle them
(for instance because we need to forward to a device but the
device is not fast enough to receive that amount of data) allows
to stop RedChannelClient to read data.
This after a bit will stop the client sending data as its output
buffer will become full.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---
 server/red-channel-client.c | 28 ++++++++++++++++++++++++++++
 server/red-channel-client.h |  4 ++++
 2 files changed, 32 insertions(+)

Patch hide | download patch | download mbox

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 4978f3567..03d565be8 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -145,6 +145,7 @@  struct RedChannelClientPrivate
         } urgent;
     } send_data;
 
+    bool block_read;
     bool during_send;
     GQueue pipe;
 
@@ -974,10 +975,32 @@  red_channel_client_watch_update_mask(RedChannelClient *rcc, int event_mask)
         return;
     }
 
+    if (rcc->priv->block_read) {
+        event_mask &= ~SPICE_WATCH_EVENT_READ;
+    }
+
     core = red_channel_get_core_interface(rcc->priv->channel);
     core->watch_update_mask(core, rcc->priv->stream->watch, event_mask);
 }
 
+void red_channel_client_block_read(RedChannelClient *rcc)
+{
+    if (rcc->priv->block_read) {
+        return;
+    }
+    rcc->priv->block_read = true;
+    red_channel_client_watch_update_mask(rcc, SPICE_WATCH_EVENT_WRITE);
+}
+
+void red_channel_client_unblock_read(RedChannelClient *rcc)
+{
+    if (!rcc->priv->block_read) {
+        return;
+    }
+    rcc->priv->block_read = false;
+    red_channel_client_watch_update_mask(rcc, SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
+}
+
 static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
 {
     rcc->priv->wait_migrate_data = FALSE;
@@ -1221,6 +1244,11 @@  static void red_channel_client_handle_incoming(RedChannelClient *rcc)
         if (buffer->msg_pos < msg_size) {
             if (!buffer->msg) {
                 buffer->msg = red_channel_client_alloc_msg_buf(rcc, msg_type, msg_size);
+                if (buffer->msg == NULL && rcc->priv->block_read) {
+                    // if we are blocked by flow control just return, message will be read
+                    // when data will be available
+                    return;
+                }
                 if (buffer->msg == NULL) {
                     red_channel_warning(channel, "ERROR: channel refused to allocate buffer.");
                     red_channel_client_disconnect(rcc);
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index 1ca0ad717..56e006ec5 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -137,6 +137,10 @@  gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc);
 void red_channel_client_set_destroying(RedChannelClient *rcc);
 bool red_channel_client_is_destroying(RedChannelClient *rcc);
 
+/* allow to block or unblock reading */
+void red_channel_client_block_read(RedChannelClient *rcc);
+void red_channel_client_unblock_read(RedChannelClient *rcc);
+
 struct RedChannelClient
 {
     GObject parent;