[Spice-devel] [RFCv5 06/47] server: move pipe from RedChannel to RedChannelClient

Alon Levy alevy at redhat.com
Sun May 8 06:11:02 PDT 2011


Another cleanup patch, no change to behavior (still one client, and it
disconnects previous client if any).

The implementation for multiple client is straightforward: the pipe
remains per (channel,client) pair, so it needs to move from the RedChannel
that to RedChannelClient. Implementation using a single pipe with multiple
consumers (to reflect different latencies) doesn't fit well with pipe rewriting
that is used by the display channel. Additionally this approach is much simpler
to verify. Lastly it doesn't add considerable overhead (but see the display
channel changes in a later patch for a real place to rethink).

This patch is just technical, changing signatures to reflect the first
argument (oop style) so red_channel becomes red_channel_client. Some places
may seem odd but they should be fixed with later comits where the channels
grow to support multiple clients.

Sound (playback/record) channels are the only ones not touched - this is
consistent with previous patches, since they have been left out of the
RedChannel refactoring.  That is left as future work. (note that they don't use
a pipe, which was the reason for not refactoring).
---
 server/inputs_channel.c          |   36 ++------
 server/main_channel.c            |  175 ++++++++++++++++++++++---------------
 server/red_channel.c             |  149 +++++++++++++++++++-------------
 server/red_channel.h             |   24 +++--
 server/red_client_cache.h        |   16 +++-
 server/red_client_shared_cache.h |    3 +-
 server/red_tunnel_worker.c       |   26 +++---
 server/red_worker.c              |  129 ++++++++++++++++------------
 server/smartcard.c               |    2 +-
 9 files changed, 317 insertions(+), 243 deletions(-)

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 3a4a0d0..e350689 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -221,14 +221,6 @@ static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
     return sif->get_leds(sin);
 }
 
-static InputsPipeItem *inputs_pipe_item_new(InputsChannel *inputs_channel, int type)
-{
-    InputsPipeItem *item = spice_malloc(sizeof(InputsPipeItem));
-
-    red_channel_pipe_item_init(&inputs_channel->base, &item->base, type);
-    return item;
-}
-
 static KeyModifiersPipeItem *inputs_key_modifiers_item_new(
     InputsChannel *inputs_channel, uint8_t modifiers)
 {
@@ -240,15 +232,6 @@ static KeyModifiersPipeItem *inputs_key_modifiers_item_new(
     return item;
 }
 
-// Right now every PipeItem we add is an InputsPipeItem, later maybe make it simpler
-// for type only PipeItems
-static void inputs_pipe_add_type(InputsChannel *channel, int type)
-{
-    InputsPipeItem* pipe_item = inputs_pipe_item_new(channel, type);
-
-    red_channel_pipe_add_push(&channel->base, &pipe_item->base);
-}
-
 static void inputs_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *base, int item_pushed)
 {
@@ -318,7 +301,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
         SpiceMsgcMouseMotion *mouse_motion = (SpiceMsgcMouseMotion *)buf;
 
         if (++inputs_channel->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
-            inputs_pipe_add_type(inputs_channel, PIPE_ITEM_MOUSE_MOTION_ACK);
+            red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
         }
         if (mouse && reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
             SpiceMouseInterface *sif;
@@ -333,7 +316,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
         SpiceMsgcMousePosition *pos = (SpiceMsgcMousePosition *)buf;
 
         if (++inputs_channel->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
-            inputs_pipe_add_type(inputs_channel, PIPE_ITEM_MOUSE_MOTION_ACK);
+            red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
         }
         if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) {
             break;
@@ -468,21 +451,20 @@ static void inputs_shutdown(Channel *channel)
 static void inputs_migrate(Channel *channel)
 {
     InputsChannel *inputs_channel = channel->data;
-    InputsPipeItem *item;
+    RedChannelClient *rcc = inputs_channel->base.rcc;
 
     ASSERT(g_inputs_channel == (InputsChannel *)channel->data);
-    item = inputs_pipe_item_new(inputs_channel, PIPE_ITEM_MIGRATE);
-    red_channel_pipe_add_push(&inputs_channel->base, &item->base);
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MIGRATE);
 }
 
-static void inputs_pipe_add_init(InputsChannel *inputs_channel)
+static void inputs_pipe_add_init(RedChannelClient *rcc)
 {
     InputsInitPipeItem *item = spice_malloc(sizeof(InputsInitPipeItem));
 
-    red_channel_pipe_item_init(&inputs_channel->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                PIPE_ITEM_INPUTS_INIT);
     item->modifiers = kbd_get_leds(keyboard);
-    red_channel_pipe_add_push(&inputs_channel->base, &item->base);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static int inputs_channel_config_socket(RedChannelClient *rcc)
@@ -539,7 +521,7 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
     rcc = red_channel_client_create(sizeof(RedChannelClient), &g_inputs_channel->base, stream);
     ASSERT(rcc);
     channel->data = inputs_channel;
-    inputs_pipe_add_init(inputs_channel);
+    inputs_pipe_add_init(rcc);
 }
 
 static void inputs_push_keyboard_modifiers(uint8_t modifiers)
@@ -550,7 +532,7 @@ static void inputs_push_keyboard_modifiers(uint8_t modifiers)
         return;
     }
     item = inputs_key_modifiers_item_new(g_inputs_channel, modifiers);
-    red_channel_pipe_add_push(&g_inputs_channel->base, &item->base);
+    red_channel_client_pipe_add_push(g_inputs_channel->base.rcc, &item->base);
 }
 
 void inputs_on_keyboard_leds_change(void *opaque, uint8_t leds)
diff --git a/server/main_channel.c b/server/main_channel.c
index 5059b3a..9ccb5cb 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -146,68 +146,64 @@ static void main_disconnect(MainChannel *main_chan)
     bitrate_per_sec = ~0;
 }
 
+static int main_channel_client_push_ping(RedChannelClient *rcc, int size);
+
 void main_channel_start_net_test(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc;
 
-    if (!main_chan || main_chan->net_test_id) {
+    if (!main_chan || !main_chan->base.rcc || main_chan->net_test_id) {
         return;
     }
+    rcc = main_chan->base.rcc;
 
-    if (main_channel_push_ping(channel, NET_TEST_WARMUP_BYTES)
-        && main_channel_push_ping(channel, 0)
-        && main_channel_push_ping(channel, NET_TEST_BYTES)) {
+    if (main_channel_client_push_ping(rcc, NET_TEST_WARMUP_BYTES)
+        && main_channel_client_push_ping(rcc, 0)
+        && main_channel_client_push_ping(rcc, NET_TEST_BYTES)) {
         main_chan->net_test_id = main_chan->ping_id - 2;
         main_chan->net_test_stage = NET_TEST_STAGE_WARMUP;
     }
 }
 
-static RedsOutItem *main_pipe_item_new(MainChannel *main_chan, int type)
-{
-    RedsOutItem *item = spice_malloc(sizeof(RedsOutItem));
-
-    red_channel_pipe_item_init(&main_chan->base, &item->base, type);
-    return item;
-}
-
-static MouseModePipeItem *main_mouse_mode_item_new(MainChannel *main_chan,
+static MouseModePipeItem *main_mouse_mode_item_new(RedChannelClient *rcc,
     int current_mode, int is_client_mouse_allowed)
 {
     MouseModePipeItem *item = spice_malloc(sizeof(MouseModePipeItem));
 
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_MAIN_MOUSE_MODE);
     item->current_mode = current_mode;
     item->is_client_mouse_allowed = is_client_mouse_allowed;
     return item;
 }
 
-static PingPipeItem *main_ping_item_new(MainChannel *channel, int size)
+static PingPipeItem *main_ping_item_new(RedChannelClient *rcc, int size)
 {
     PingPipeItem *item = spice_malloc(sizeof(PingPipeItem));
 
-    red_channel_pipe_item_init(&channel->base, &item->base, SPICE_MSG_PING);
+    red_channel_pipe_item_init(rcc->channel, &item->base, SPICE_MSG_PING);
     item->size = size;
     return item;
 }
 
-static TokensPipeItem *main_tokens_item_new(MainChannel *main_chan, int tokens)
+static TokensPipeItem *main_tokens_item_new(RedChannelClient *rcc, int tokens)
 {
     TokensPipeItem *item = spice_malloc(sizeof(TokensPipeItem));
 
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_MAIN_AGENT_TOKEN);
     item->tokens = tokens;
     return item;
 }
 
-static AgentDataPipeItem *main_agent_data_item_new(MainChannel *channel,
+static AgentDataPipeItem *main_agent_data_item_new(RedChannelClient *rcc,
            uint8_t* data, size_t len,
            spice_marshaller_item_free_func free_data, void *opaque)
 {
     AgentDataPipeItem *item = spice_malloc(sizeof(AgentDataPipeItem));
 
-    red_channel_pipe_item_init(&channel->base, &item->base, SPICE_MSG_MAIN_AGENT_DATA);
+    red_channel_pipe_item_init(rcc->channel, &item->base, SPICE_MSG_MAIN_AGENT_DATA);
     item->data = data;
     item->len = len;
     item->free_data = free_data;
@@ -215,14 +211,14 @@ static AgentDataPipeItem *main_agent_data_item_new(MainChannel *channel,
     return item;
 }
 
-static InitPipeItem *main_init_item_new(MainChannel *main_chan,
+static InitPipeItem *main_init_item_new(RedChannelClient *rcc,
     int connection_id, int display_channels_hint, int current_mouse_mode,
     int is_client_mouse_allowed, int multi_media_time,
     int ram_hint)
 {
     InitPipeItem *item = spice_malloc(sizeof(InitPipeItem));
 
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_MAIN_INIT);
     item->connection_id = connection_id;
     item->display_channels_hint = display_channels_hint;
@@ -233,12 +229,12 @@ static InitPipeItem *main_init_item_new(MainChannel *main_chan,
     return item;
 }
 
-static NotifyPipeItem *main_notify_item_new(MainChannel *main_chan,
+static NotifyPipeItem *main_notify_item_new(RedChannelClient *rcc,
                                         uint8_t *mess, const int mess_len)
 {
     NotifyPipeItem *item = spice_malloc(sizeof(NotifyPipeItem));
 
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_NOTIFY);
     item->mess = mess;
     item->mess_len = mess_len;
@@ -246,13 +242,13 @@ static NotifyPipeItem *main_notify_item_new(MainChannel *main_chan,
 }
 
 static MigrateBeginPipeItem *main_migrate_begin_item_new(
-    MainChannel *main_chan, int port, int sport,
+    RedChannelClient *rcc, int port, int sport,
     char *host, uint16_t cert_pub_key_type, uint32_t cert_pub_key_len,
     uint8_t *cert_pub_key)
 {
     MigrateBeginPipeItem *item = spice_malloc(sizeof(MigrateBeginPipeItem));
 
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_MAIN_MIGRATE_BEGIN);
     item->port = port;
     item->sport = sport;
@@ -264,23 +260,20 @@ static MigrateBeginPipeItem *main_migrate_begin_item_new(
 }
 
 static MultiMediaTimePipeItem *main_multi_media_time_item_new(
-    MainChannel *main_chan, int time)
+    RedChannelClient *rcc, int time)
 {
     MultiMediaTimePipeItem *item;
 
     item = spice_malloc(sizeof(MultiMediaTimePipeItem));
-    red_channel_pipe_item_init(&main_chan->base, &item->base,
+    red_channel_pipe_item_init(rcc->channel, &item->base,
                                SPICE_MSG_MAIN_MULTI_MEDIA_TIME);
     item->time = time;
     return item;
 }
 
-static void main_channel_push_channels(MainChannel *main_chan)
+static void main_channel_push_channels(RedChannelClient *rcc)
 {
-    RedsOutItem *item;
-
-    item = main_pipe_item_new(main_chan, SPICE_MSG_MAIN_CHANNELS_LIST);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MAIN_CHANNELS_LIST);
 }
 
 static void main_channel_marshall_channels(SpiceMarshaller *m)
@@ -294,17 +287,23 @@ static void main_channel_marshall_channels(SpiceMarshaller *m)
     free(channels_info);
 }
 
+int main_channel_client_push_ping(RedChannelClient *rcc, int size)
+{
+    PingPipeItem *item;
+
+    item = main_ping_item_new(rcc, size);
+    red_channel_client_pipe_add_push(rcc, &item->base);
+    return TRUE;
+}
+
 int main_channel_push_ping(Channel *channel, int size)
 {
     MainChannel *main_chan = channel->data;
-    PingPipeItem *item;
-    
-    if (main_chan == NULL) {
+
+    if (main_chan->base.rcc == NULL) {
         return FALSE;
     }
-    item = main_ping_item_new(main_chan, size);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
-    return TRUE;
+    return main_channel_client_push_ping(main_chan->base.rcc, size);
 }
 
 static void main_channel_marshall_ping(SpiceMarshaller *m, int size, int ping_id)
@@ -324,15 +323,28 @@ static void main_channel_marshall_ping(SpiceMarshaller *m, int size, int ping_id
     }
 }
 
+static void main_channel_client_push_mouse_mode(RedChannelClient *rcc, int current_mode,
+                                         int is_client_mouse_allowed);
+
 void main_channel_push_mouse_mode(Channel *channel, int current_mode,
                                   int is_client_mouse_allowed)
 {
     MainChannel *main_chan = channel->data;
+
+    if (main_chan && main_chan->base.rcc != NULL) {
+        main_channel_client_push_mouse_mode(main_chan->base.rcc, current_mode,
+                                            is_client_mouse_allowed);
+    }
+}
+
+static void main_channel_client_push_mouse_mode(RedChannelClient *rcc, int current_mode,
+                                         int is_client_mouse_allowed)
+{
     MouseModePipeItem *item;
 
-    item = main_mouse_mode_item_new(main_chan, current_mode,
+    item = main_mouse_mode_item_new(rcc, current_mode,
                                     is_client_mouse_allowed);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static void main_channel_marshall_mouse_mode(SpiceMarshaller *m, int current_mode, int is_client_mouse_allowed)
@@ -348,20 +360,20 @@ static void main_channel_marshall_mouse_mode(SpiceMarshaller *m, int current_mod
 
 void main_channel_push_agent_connected(Channel *channel)
 {
-    RedsOutItem *item;
-    MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = ((MainChannel*)channel->data)->base.rcc;
 
-    item = main_pipe_item_new(main_chan, SPICE_MSG_MAIN_AGENT_CONNECTED);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MAIN_AGENT_CONNECTED);
 }
 
 void main_channel_push_agent_disconnected(Channel *channel)
 {
-    RedsOutItem *item;
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    item = main_pipe_item_new(main_chan, SPICE_MSG_MAIN_AGENT_DISCONNECTED);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    if (!rcc) {
+        return;
+    }
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MAIN_AGENT_DISCONNECTED);
 }
 
 static void main_channel_marshall_agent_disconnected(SpiceMarshaller *m)
@@ -374,10 +386,15 @@ static void main_channel_marshall_agent_disconnected(SpiceMarshaller *m)
 
 void main_channel_push_tokens(Channel *channel, uint32_t num_tokens)
 {
+    TokensPipeItem *item;
     MainChannel *main_chan = channel->data;
-    TokensPipeItem *item = main_tokens_item_new(main_chan, num_tokens);
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    if (!rcc) {
+        return;
+    }
+    item = main_tokens_item_new(rcc, num_tokens);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static void main_channel_marshall_tokens(SpiceMarshaller *m, uint32_t num_tokens)
@@ -392,10 +409,11 @@ void main_channel_push_agent_data(Channel *channel, uint8_t* data, size_t len,
            spice_marshaller_item_free_func free_data, void *opaque)
 {
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = main_chan->base.rcc;
     AgentDataPipeItem *item;
 
-    item = main_agent_data_item_new(main_chan, data, len, free_data, opaque);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    item = main_agent_data_item_new(rcc, data, len, free_data, opaque);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static void main_channel_marshall_agent_data(SpiceMarshaller *m,
@@ -407,9 +425,12 @@ static void main_channel_marshall_agent_data(SpiceMarshaller *m,
 
 static void main_channel_push_migrate_data_item(MainChannel *main_chan)
 {
-    RedsOutItem *item = main_pipe_item_new(main_chan, SPICE_MSG_MIGRATE_DATA);
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    if (!rcc) {
+        return;
+    }
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MIGRATE_DATA);
 }
 
 static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int serial, int ping_id)
@@ -456,11 +477,12 @@ void main_channel_push_init(Channel *channel, int connection_id,
 {
     InitPipeItem *item;
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    item = main_init_item_new(main_chan,
+    item = main_init_item_new(rcc,
              connection_id, display_channels_hint, current_mouse_mode,
              is_client_mouse_allowed, multi_media_time, ram_hint);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static void main_channel_marshall_init(SpiceMarshaller *m,
@@ -485,9 +507,11 @@ static void main_channel_marshall_init(SpiceMarshaller *m,
 void main_channel_push_notify(Channel *channel, uint8_t *mess, const int mess_len)
 {
     MainChannel *main_chan = channel->data;
-    NotifyPipeItem *item = main_notify_item_new(main_chan, mess, mess_len);
+    RedChannelClient *rcc = main_chan->base.rcc;
+    NotifyPipeItem *item;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    item = main_notify_item_new(rcc, mess, mess_len);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static uint64_t get_time_stamp(void)
@@ -515,10 +539,12 @@ void main_channel_push_migrate_begin(Channel *channel, int port, int sport,
     uint8_t *cert_pub_key)
 {
     MainChannel *main_chan = channel->data;
-    MigrateBeginPipeItem *item = main_migrate_begin_item_new(main_chan, port,
-        sport, host, cert_pub_key_type, cert_pub_key_len, cert_pub_key);
+    RedChannelClient *rcc = main_chan->base.rcc;
+    MigrateBeginPipeItem *item;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    item = main_migrate_begin_item_new(rcc, port,
+        sport, host, cert_pub_key_type, cert_pub_key_len, cert_pub_key);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static void main_channel_marshall_migrate_begin(SpiceMarshaller *m,
@@ -539,9 +565,12 @@ static void main_channel_marshall_migrate_begin(SpiceMarshaller *m,
 void main_channel_push_migrate(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
-    RedsOutItem *item = main_pipe_item_new(main_chan, SPICE_MSG_MIGRATE);
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    if (!rcc) {
+        return;
+    }
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MIGRATE);
 }
 
 static void main_channel_marshall_migrate(SpiceMarshaller *m)
@@ -555,19 +584,22 @@ static void main_channel_marshall_migrate(SpiceMarshaller *m)
 void main_channel_push_migrate_cancel(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
-    RedsOutItem *item = main_pipe_item_new(main_chan,
-                                           SPICE_MSG_MAIN_MIGRATE_CANCEL);
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    if (!rcc) {
+        return;
+    }
+    red_channel_client_pipe_add_type(rcc, SPICE_MSG_MAIN_MIGRATE_CANCEL);
 }
 
 void main_channel_push_multi_media_time(Channel *channel, int time)
 {
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = main_chan->base.rcc;
+    MultiMediaTimePipeItem *item;
 
-    MultiMediaTimePipeItem *item =
-        main_multi_media_time_item_new(main_chan, time);
-    red_channel_pipe_add_push(&main_chan->base, &item->base);
+    item =main_multi_media_time_item_new(rcc, time);
+    red_channel_client_pipe_add_push(rcc, &item->base);
 }
 
 static PipeItem *main_migrate_switch_item_new(MainChannel *main_chan)
@@ -582,8 +614,9 @@ static PipeItem *main_migrate_switch_item_new(MainChannel *main_chan)
 void main_channel_push_migrate_switch(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
+    RedChannelClient *rcc = main_chan->base.rcc;
 
-    red_channel_pipe_add_push(&main_chan->base,
+    red_channel_client_pipe_add_push(rcc,
         main_migrate_switch_item_new(main_chan));
 }
 
@@ -697,7 +730,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
     case SPICE_MSGC_MAIN_AGENT_TOKEN:
         break;
     case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
-        main_channel_push_channels(main_chan);
+        main_channel_push_channels(rcc);
         break;
     case SPICE_MSGC_MAIN_MIGRATE_CONNECTED:
         red_printf("connected");
diff --git a/server/red_channel.c b/server/red_channel.c
index 2758ede..934fc85 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -267,13 +267,12 @@ static void red_channel_client_reset_send_data(RedChannelClient *rcc)
 
 void red_channel_client_push_set_ack(RedChannelClient *rcc)
 {
-    red_channel_pipe_add_type(rcc->channel, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_SET_ACK);
 }
 
 void red_channel_push_set_ack(RedChannel *channel)
 {
-    // TODO - MC, should replace with add_type_all (or whatever I'll name it)
-    red_channel_pipe_add_type(channel, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_SET_ACK);
 }
 
 static void red_channel_client_send_set_ack(RedChannelClient *rcc)
@@ -347,6 +346,12 @@ static void red_channel_peer_on_out_msg_done(void *opaque)
     }
 }
 
+static void red_channel_client_pipe_remove(RedChannelClient *rcc, PipeItem *item)
+{
+    rcc->pipe_size--;
+    ring_remove(&item->link);
+}
+
 static void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
 {
     ASSERT(rcc);
@@ -381,9 +386,13 @@ RedChannelClient *red_channel_client_create(
         goto error;
     }
 
+    ring_init(&rcc->pipe);
+    rcc->pipe_size = 0;
+
     stream->watch = channel->core->watch_add(stream->socket,
                                            SPICE_WATCH_EVENT_READ,
                                            red_channel_client_event, rcc);
+    rcc->id = 0;
     red_channel_add_client(channel, rcc);
     return rcc;
 error:
@@ -425,7 +434,6 @@ RedChannel *red_channel_create(int size,
 
     channel->core = core;
     channel->migrate = migrate;
-    ring_init(&channel->pipe);
 
     channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)alloc_recv_buf;
     channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)release_recv_buf;
@@ -501,6 +509,7 @@ void red_channel_destroy(RedChannel *channel)
     if (!channel) {
         return;
     }
+    red_channel_pipes_clear(channel);
     if (channel->rcc) {
         red_channel_client_destroy(channel->rcc);
     }
@@ -524,7 +533,7 @@ void red_channel_shutdown(RedChannel *channel)
     if (channel->rcc) {
         red_channel_client_shutdown(channel->rcc);
     }
-    red_channel_pipe_clear(channel);
+    red_channel_pipes_clear(channel);
 }
 
 void red_channel_client_send(RedChannelClient *rcc)
@@ -545,23 +554,20 @@ static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
             (rcc->ack_data.messages_window > rcc->ack_data.client_window * 2));
 }
 
-// TODO: add refs and target to PipeItem. Right now this only works for a
-// single client (or actually, it's worse - first come first served)
-static inline PipeItem *red_channel_client_pipe_get(RedChannelClient *rcc)
+static inline PipeItem *red_channel_client_pipe_item_get(RedChannelClient *rcc)
 {
     PipeItem *item;
 
     if (!rcc || rcc->send_data.blocked
              || red_channel_client_waiting_for_ack(rcc)
-             || !(item = (PipeItem *)ring_get_tail(&rcc->channel->pipe))) {
+             || !(item = (PipeItem *)ring_get_tail(&rcc->pipe))) {
         return NULL;
     }
-    --rcc->channel->pipe_size;
-    ring_remove(&item->link);
+    red_channel_client_pipe_remove(rcc, item);
     return item;
 }
 
-static void red_channel_client_push(RedChannelClient *rcc)
+void red_channel_client_push(RedChannelClient *rcc)
 {
     PipeItem *pipe_item;
 
@@ -575,7 +581,7 @@ static void red_channel_client_push(RedChannelClient *rcc)
         red_channel_client_send(rcc);
     }
 
-    while ((pipe_item = red_channel_client_pipe_get(rcc))) {
+    while ((pipe_item = red_channel_client_pipe_item_get(rcc))) {
         red_channel_client_send_item(rcc, pipe_item);
     }
     rcc->during_send = FALSE;
@@ -599,13 +605,15 @@ static void red_channel_client_init_outgoing_messages_window(RedChannelClient *r
 // specific
 void red_channel_init_outgoing_messages_window(RedChannel *channel)
 {
-    red_channel_client_init_outgoing_messages_window(channel->rcc);
+    if (channel->rcc) {
+        red_channel_client_init_outgoing_messages_window(channel->rcc);
+    }
 }
 
-static void red_channel_handle_migrate_flush_mark(RedChannel *channel)
+static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
 {
-    if (channel->handle_migrate_flush_mark) {
-        channel->handle_migrate_flush_mark(channel->rcc);
+    if (rcc->channel->handle_migrate_flush_mark) {
+        rcc->channel->handle_migrate_flush_mark(rcc);
     }
 }
 
@@ -647,7 +655,7 @@ int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
     case SPICE_MSGC_DISCONNECTING:
         break;
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        red_channel_handle_migrate_flush_mark(rcc->channel);
+        red_channel_handle_migrate_flush_mark(rcc);
         break;
     case SPICE_MSGC_MIGRATE_DATA:
         red_channel_handle_migrate_data(rcc, size, message);
@@ -715,64 +723,86 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type)
     item->type = type;
 }
 
-void red_channel_pipe_add(RedChannel *channel, PipeItem *item)
+void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item)
 {
-    ASSERT(channel);
-
-    channel->pipe_size++;
-    ring_add(&channel->pipe, &item->link);
+    ASSERT(rcc && item);
+    rcc->pipe_size++;
+    ring_add(&rcc->pipe, &item->link);
 }
 
-void red_channel_pipe_add_push(RedChannel *channel, PipeItem *item)
+void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
 {
-    ASSERT(channel);
-
-    channel->pipe_size++;
-    ring_add(&channel->pipe, &item->link);
-    red_channel_push(channel);
+    red_channel_client_pipe_add(rcc, item);
+    red_channel_client_push(rcc);
 }
 
-void red_channel_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos)
+void red_channel_client_pipe_add_after(RedChannelClient *rcc,
+                                       PipeItem *item, PipeItem *pos)
 {
-    ASSERT(channel);
+    ASSERT(rcc);
     ASSERT(pos);
     ASSERT(item);
 
-    channel->pipe_size++;
+    rcc->pipe_size++;
     ring_add_after(&item->link, &pos->link);
 }
 
-int red_channel_pipe_item_is_linked(RedChannel *channel, PipeItem *item)
+int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
+                                           PipeItem *item)
 {
     return ring_item_is_linked(&item->link);
 }
 
-void red_channel_pipe_item_remove(RedChannel *channel, PipeItem *item)
+int red_channel_pipe_item_is_linked(RedChannel *channel, PipeItem *item)
 {
-    ring_remove(&item->link);
+    return channel->rcc && red_channel_client_pipe_item_is_linked(channel->rcc, item);
 }
 
-void red_channel_pipe_add_tail(RedChannel *channel, PipeItem *item)
+void red_channel_client_pipe_add_tail_no_push(RedChannelClient *rcc,
+                                              PipeItem *item)
 {
-    ASSERT(channel);
-    channel->pipe_size++;
-    ring_add_before(&item->link, &channel->pipe);
+    ASSERT(rcc);
+    rcc->pipe_size++;
+    ring_add_before(&item->link, &rcc->pipe);
+}
 
-    red_channel_push(channel);
+void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item)
+{
+    ASSERT(rcc);
+    rcc->pipe_size++;
+    ring_add_before(&item->link, &rcc->pipe);
+    red_channel_client_push(rcc);
 }
 
-void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type)
+void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type)
 {
     PipeItem *item = spice_new(PipeItem, 1);
-    red_channel_pipe_item_init(channel, item, pipe_item_type);
-    red_channel_pipe_add(channel, item);
 
-    red_channel_push(channel);
+    red_channel_pipe_item_init(rcc->channel, item, pipe_item_type);
+    red_channel_client_pipe_add(rcc, item);
+    red_channel_client_push(rcc);
+}
+
+void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
+{
+    if (channel->rcc) {
+        red_channel_client_pipe_add_type(channel->rcc, pipe_item_type);
+    }
+}
+
+int red_channel_client_is_connected(RedChannelClient *rcc)
+{
+    return rcc->stream != NULL;
+}
+
+void red_channel_pipe_item_remove(RedChannel *channel, PipeItem *item)
+{
+    ring_remove(&item->link);
 }
 
 int red_channel_is_connected(RedChannel *channel)
 {
-    return channel->rcc != NULL;
+    return (channel->rcc != NULL) && red_channel_client_is_connected(channel->rcc);
 }
 
 void red_channel_client_clear_sent_item(RedChannelClient *rcc)
@@ -783,19 +813,26 @@ void red_channel_client_clear_sent_item(RedChannelClient *rcc)
     }
 }
 
-void red_channel_pipe_clear(RedChannel *channel)
+void red_channel_client_pipe_clear(RedChannelClient *rcc)
 {
     PipeItem *item;
 
-    ASSERT(channel);
-    if (channel->rcc) {
-        red_channel_client_clear_sent_item(channel->rcc);
+    if (rcc) {
+        red_channel_client_clear_sent_item(rcc);
     }
-    while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
+    while ((item = (PipeItem *)ring_get_head(&rcc->pipe))) {
         ring_remove(&item->link);
-        red_channel_client_release_item(channel->rcc, item, FALSE);
+        red_channel_client_release_item(rcc, item, FALSE);
+    }
+    rcc->pipe_size = 0;
+}
+
+void red_channel_pipes_clear(RedChannel *channel)
+{
+    if (!channel || !channel->rcc) {
+        return;
     }
-    channel->pipe_size = 0;
+    red_channel_client_pipe_clear(channel->rcc);
 }
 
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
@@ -837,7 +874,7 @@ void red_channel_client_disconnect(RedChannelClient *rcc)
 
 void red_channel_disconnect(RedChannel *channel)
 {
-    red_channel_pipe_clear(channel);
+    red_channel_pipes_clear(channel);
     if (channel->rcc) {
         red_channel_client_disconnect(channel->rcc);
     }
@@ -934,12 +971,6 @@ int red_channel_client_no_item_being_sent(RedChannelClient *rcc)
     return !rcc || rcc->send_data.item == NULL;
 }
 
-static void red_channel_client_pipe_remove(RedChannelClient *rcc, PipeItem *item)
-{
-    rcc->channel->pipe_size--;
-    ring_remove(&item->link);
-}
-
 void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc,
                                                 PipeItem *item)
 {
diff --git a/server/red_channel.h b/server/red_channel.h
index e7a83d3..2bd3054 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -161,6 +161,9 @@ struct RedChannelClient {
     OutgoingHandler outgoing;
     IncomingHandler incoming;
     int during_send;
+    int id; // debugging purposes
+    Ring pipe;
+    uint32_t pipe_size;
 };
 
 struct RedChannel {
@@ -170,9 +173,6 @@ struct RedChannel {
 
     RedChannelClient *rcc;
 
-    Ring pipe;
-    uint32_t pipe_size;
-
     OutgoingHandlerInterface outgoing_cb;
     IncomingHandlerInterface incoming_cb;
 
@@ -258,15 +258,16 @@ void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t);
 void red_channel_client_begin_send_message(RedChannelClient *rcc);
 
 void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type);
-void red_channel_pipe_add_push(RedChannel *channel, PipeItem *item);
-void red_channel_pipe_add(RedChannel *channel, PipeItem *item);
-void red_channel_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos);
+void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item);
+void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item);
+void red_channel_client_pipe_add_after(RedChannelClient *rcc, PipeItem *item, PipeItem *pos);
 int red_channel_pipe_item_is_linked(RedChannel *channel, PipeItem *item);
 void red_channel_pipe_item_remove(RedChannel *channel, PipeItem *item);
 void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc, PipeItem *item);
-void red_channel_pipe_add_tail(RedChannel *channel, PipeItem *item);
+void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item);
 /* for types that use this routine -> the pipe item should be freed */
-void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type);
+void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type);
+void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type);
 
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
 void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
@@ -296,19 +297,24 @@ int red_channel_client_send_message_pending(RedChannelClient *rcc);
  * hasn't even begun, i.e. no one called begin_send_)
  * */
 int red_channel_item_being_sent(RedChannel *channel, PipeItem *item);
+int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item);
 
 int red_channel_no_item_being_sent(RedChannel *channel);
 int red_channel_client_no_item_being_sent(RedChannelClient *rcc);
 
+void red_channel_pipes_remove(RedChannel *channel, PipeItem *item);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
 // should not make any difference.
 void red_channel_push(RedChannel *channel);
+void red_channel_client_push(RedChannelClient *rcc);
 // TODO: again - what is the context exactly? this happens in channel disconnect. but our
 // current red_channel_shutdown also closes the socket - is there a socket to close?
 // are we reading from an fd here? arghh
-void red_channel_pipe_clear(RedChannel *channel);
+void red_channel_pipes_clear(RedChannel *channel);
+void red_channel_client_pipe_clear(RedChannelClient *rcc);
 // Again, used in various places outside of event handler context (or in other event handler
 // contexts):
 //  flush_display_commands/flush_cursor_commands
diff --git a/server/red_client_cache.h b/server/red_client_cache.h
index fae4b2a..6c17ba6 100644
--- a/server/red_client_cache.h
+++ b/server/red_client_cache.h
@@ -24,6 +24,7 @@
 #define FUNC_NAME(name) red_cursor_cache_##name
 #define VAR_NAME(name) cursor_cache_##name
 #define CHANNEL CursorChannel
+#define CHANNELCLIENT RedChannelClient
 
 #elif defined(CLIENT_PALETTE_CACHE)
 
@@ -34,12 +35,15 @@
 #define FUNC_NAME(name) red_palette_cache_##name
 #define VAR_NAME(name) palette_cache_##name
 #define CHANNEL DisplayChannel
+#define CHANNELCLIENT RedChannelClient
 #else
 
 #error "no cache type."
 
 #endif
 
+#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
+
 static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
 {
     CacheItem *item = channel->CACHE_NAME[CACHE_HASH_KEY(id)];
@@ -55,9 +59,10 @@ static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
     return item;
 }
 
-static void FUNC_NAME(remove)(CHANNEL *channel, CacheItem *item)
+static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
 {
     CacheItem **now;
+    CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
     ASSERT(item);
 
     now = &channel->CACHE_NAME[CACHE_HASH_KEY(item->id)];
@@ -74,11 +79,12 @@ static void FUNC_NAME(remove)(CHANNEL *channel, CacheItem *item)
     channel->VAR_NAME(available) += item->size;
 
     red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
-    red_channel_pipe_add_tail(&channel->common.base, &item->u.pipe_data); // for now
+    red_channel_client_pipe_add_tail(channel_client, &item->u.pipe_data); // for now
 }
 
-static int FUNC_NAME(add)(CHANNEL *channel, uint64_t id, size_t size)
+static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
 {
+    CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
     CacheItem *item;
     int key;
 
@@ -92,7 +98,7 @@ static int FUNC_NAME(add)(CHANNEL *channel, uint64_t id, size_t size)
             free(item);
             return FALSE;
         }
-        FUNC_NAME(remove)(channel, tail);
+        FUNC_NAME(remove)(channel_client, tail);
     }
     ++channel->VAR_NAME(items);
     item->u.cache_data.next = channel->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
@@ -130,4 +136,4 @@ static void FUNC_NAME(reset)(CHANNEL *channel, long size)
 #undef FUNC_NAME
 #undef VAR_NAME
 #undef CHANNEL
-
+#undef CHANNEL_FROM_RCC
diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index dddccc6..6b1f975 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -97,7 +97,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
 
     if (cache->generation != channel->CACH_GENERATION) {
         if (!channel->pending_pixmaps_sync) {
-            red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_SYNC);
+            red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_PIXMAP_SYNC);
             channel->pending_pixmaps_sync = TRUE;
         }
         pthread_mutex_unlock(&cache->lock);
@@ -235,4 +235,3 @@ static void FUNC_NAME(destroy)(CACHE *cache)
 #undef VAR_NAME
 #undef CHANNEL
 #undef CHANNEL_FROM_RCC
-
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index f695777..c18c773 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -734,7 +734,7 @@ static inline void __process_rcv_buf_tokens(TunnelChannel *channel, RedSocket *s
     if ((sckt->in_data.num_tokens >= SOCKET_TOKENS_TO_SEND) ||
         (!sckt->in_data.client_total_num_tokens && !sckt->in_data.ready_chunks_queue.head)) {
         sckt->out_data.token_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_TOKEN;
-        red_channel_pipe_add(&channel->base, &sckt->out_data.token_pipe_item);
+        red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.token_pipe_item);
     }
 }
 
@@ -1094,7 +1094,7 @@ static inline TunnelService *__tunnel_worker_add_service(TunnelWorker *worker, u
 #endif
     if (!virt_ip) {
         new_service->pipe_item.type = PIPE_ITEM_TYPE_SERVICE_IP_MAP;
-        red_channel_pipe_add(&worker->channel->base, &new_service->pipe_item);
+        red_channel_client_pipe_add(worker->channel->base.rcc, &new_service->pipe_item);
     }
 
     return new_service;
@@ -1347,7 +1347,7 @@ static inline void __tunnel_socket_add_fin_to_pipe(TunnelChannel *channel, RedSo
 {
     ASSERT(!red_channel_pipe_item_is_linked(&channel->base, &sckt->out_data.status_pipe_item));
     sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_FIN;
-    red_channel_pipe_add(&channel->base, &sckt->out_data.status_pipe_item);
+    red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.status_pipe_item);
 }
 
 static inline void __tunnel_socket_add_close_to_pipe(TunnelChannel *channel, RedSocket *sckt)
@@ -1361,7 +1361,7 @@ static inline void __tunnel_socket_add_close_to_pipe(TunnelChannel *channel, Red
     }
     sckt->pushed_close = TRUE;
     sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_CLOSE;
-    red_channel_pipe_add(&channel->base, &sckt->out_data.status_pipe_item);
+    red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.status_pipe_item);
 }
 
 static inline void __tunnel_socket_add_close_ack_to_pipe(TunnelChannel *channel, RedSocket *sckt)
@@ -1375,7 +1375,7 @@ static inline void __tunnel_socket_add_close_ack_to_pipe(TunnelChannel *channel,
     }
 
     sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK;
-    red_channel_pipe_add(&channel->base, &sckt->out_data.status_pipe_item);
+    red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.status_pipe_item);
 }
 
 /*
@@ -1639,7 +1639,7 @@ static int tunnel_channel_handle_socket_token(TunnelChannel *channel, RedSocket
         !red_channel_pipe_item_is_linked(&channel->base, &sckt->out_data.data_pipe_item)) {
         // data is pending to be sent
         sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
-        red_channel_pipe_add(&channel->base, &sckt->out_data.data_pipe_item);
+        red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.data_pipe_item);
     }
 
     return TRUE;
@@ -1809,7 +1809,7 @@ static int tunnel_channel_handle_migrate_mark(RedChannelClient *rcc)
         }
     }
 
-    red_channel_pipe_add((RedChannel *)channel, &migrate_item->base);
+    red_channel_client_pipe_add(channel->base.rcc, &migrate_item->base);
 
     return TRUE;
 error:
@@ -2113,7 +2113,7 @@ static void tunnel_channel_restore_socket_state(TunnelChannel *channel, RedSocke
         if (!red_channel_pipe_item_is_linked(
                 &channel->base, &sckt->out_data.data_pipe_item)) {
             sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
-            red_channel_pipe_add(&channel->base, &sckt->out_data.data_pipe_item);
+            red_channel_client_pipe_add(channel->base.rcc, &sckt->out_data.data_pipe_item);
         }
     }
 
@@ -2795,7 +2795,7 @@ static void tunnel_worker_release_socket_out_data(TunnelWorker *worker, PipeItem
                 if (!red_channel_pipe_item_is_linked(
                         &worker->channel->base, &sckt_out_data->data_pipe_item)) {
                     sckt_out_data->data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
-                    red_channel_pipe_add(&worker->channel->base, &sckt_out_data->data_pipe_item);
+                    red_channel_client_pipe_add(worker->channel->base.rcc, &sckt_out_data->data_pipe_item);
                 }
             } else if ((sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND) ||
                        (sckt->slirp_status == SLIRP_SCKT_STATUS_WAIT_CLOSE)) {
@@ -2959,7 +2959,7 @@ static int tunnel_socket_connect(SlirpUsrNetworkInterface *usr_interface,
 #endif
     *o_usr_s = sckt;
     sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_OPEN;
-    red_channel_pipe_add(&worker->channel->base, &sckt->out_data.status_pipe_item);
+    red_channel_client_pipe_add(worker->channel->base.rcc, &sckt->out_data.status_pipe_item);
 
     errno = EINPROGRESS;
     return -1;
@@ -3048,7 +3048,7 @@ static int tunnel_socket_send(SlirpUsrNetworkInterface *usr_interface, UserSocke
             !red_channel_pipe_item_is_linked(&worker->channel->base,
                                              &sckt->out_data.data_pipe_item)) {
             sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
-            red_channel_pipe_add(&worker->channel->base, &sckt->out_data.data_pipe_item);
+            red_channel_client_pipe_add(worker->channel->base.rcc, &sckt->out_data.data_pipe_item);
         }
     }
 
@@ -3426,7 +3426,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
         channel->expect_migrate_data = TRUE;
     } else {
         red_channel_init_outgoing_messages_window(&channel->base);
-        red_channel_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_TUNNEL_INIT);
+        red_channel_client_pipe_add_type(channel->base.rcc, PIPE_ITEM_TYPE_TUNNEL_INIT);
     }
 }
 
@@ -3484,6 +3484,6 @@ static void handle_tunnel_channel_migrate(struct Channel *channel)
     TunnelChannel *tunnel_channel = ((TunnelWorker *)channel->data)->channel;
     tunnel_channel->mig_inprogress = TRUE;
     net_slirp_freeze();
-    red_channel_pipe_add_type(&tunnel_channel->base, PIPE_ITEM_TYPE_MIGRATE);
+    red_channel_client_pipe_add_type(tunnel_channel->base.rcc, PIPE_ITEM_TYPE_MIGRATE);
 }
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 4c6da6b..185e67a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1135,16 +1135,26 @@ static inline void pipe_item_remove(PipeItem *item)
     ring_remove(&item->link);
 }
 
-static void red_pipe_add_verb(RedChannel* channel, uint16_t verb)
+static void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
 {
     VerbItem *item = spice_new(VerbItem, 1);
-    red_channel_pipe_item_init(channel, &item->base, PIPE_ITEM_TYPE_VERB);
+
+    red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_VERB);
     item->verb = verb;
-    red_channel_pipe_add(channel, &item->base);
+    red_channel_client_pipe_add(rcc, &item->base);
 }
 
 static inline void red_create_surface_item(RedWorker *worker, int surface_id);
 static void red_add_surface_image(RedWorker *worker, int surface_id);
+static void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
+{
+    RedChannelClient *rcc = channel->rcc;
+
+    if (!rcc) {
+        return;
+    }
+    red_pipe_add_verb(rcc, verb);
+}
 
 static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker, Drawable *drawable)
 {
@@ -1194,7 +1204,7 @@ static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable)
     red_handle_drawable_surfaces_client_synced(worker, drawable);
 
     drawable->refs++;
-    red_channel_pipe_add(&worker->display_channel->common.base, &drawable->pipe_item);
+    red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &drawable->pipe_item);
 }
 
 static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *drawable)
@@ -1203,7 +1213,7 @@ static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *dr
         return;
     }
     drawable->refs++;
-    red_channel_pipe_add_tail(&worker->display_channel->common.base, &drawable->pipe_item);
+    red_channel_client_pipe_add_tail(worker->display_channel->common.base.rcc, &drawable->pipe_item);
 }
 
 static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *drawable,
@@ -1218,7 +1228,7 @@ static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *draw
         return;
     }
     drawable->refs++;
-    red_channel_pipe_add_after(&worker->display_channel->common.base, &drawable->pipe_item, &pos_after->pipe_item);
+    red_channel_client_pipe_add_after(worker->display_channel->common.base.rcc, &drawable->pipe_item, &pos_after->pipe_item);
 }
 
 static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
@@ -1227,17 +1237,16 @@ static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
         return NULL;
     }
 
-    return (PipeItem*)ring_get_tail(&worker->display_channel->common.base.pipe);
+    return (PipeItem*)ring_get_tail(&worker->display_channel->common.base.rcc->pipe);
 }
 
 static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id);
 
 static inline void red_pipe_remove_drawable(RedWorker *worker, Drawable *drawable)
 {
-    if (ring_item_is_linked(&drawable->pipe_item.link)) {
-        worker->display_channel->common.base.pipe_size--;
-        ring_remove(&drawable->pipe_item.link);
-        release_drawable(worker, drawable);
+    if (pipe_item_is_linked(&drawable->pipe_item)) {
+        red_channel_client_pipe_remove_and_release(
+            worker->display_channel->common.base.rcc, &drawable->pipe_item);
     }
 }
 
@@ -1247,7 +1256,7 @@ static inline void red_pipe_add_image_item(RedWorker *worker, ImageItem *item)
         return;
     }
     item->refs++;
-    red_channel_pipe_add(&worker->display_channel->common.base, &item->link);
+    red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &item->link);
 }
 
 static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *item,
@@ -1257,7 +1266,7 @@ static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *i
         return;
     }
     item->refs++;
-    red_channel_pipe_add_after(&worker->display_channel->common.base, &item->link, pos);
+    red_channel_client_pipe_add_after(worker->display_channel->common.base.rcc, &item->link, pos);
 }
 
 static void release_image_item(ImageItem *item)
@@ -1367,7 +1376,7 @@ static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_
     worker->display_channel->surface_client_created[surface_id] = FALSE;
     channel = &worker->display_channel->common.base;
     destroy = get_surface_destroy_item(channel, surface_id);
-    red_channel_pipe_add(channel, &destroy->pipe_item);
+    red_channel_client_pipe_add(channel->rcc, &destroy->pipe_item);
 }
 
 static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
@@ -1683,7 +1692,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
     /* removing the newest drawables that their destination is surface_id and
        no other drawable depends on them */
 
-    ring = &worker->display_channel->common.base.pipe;
+    ring = &worker->display_channel->common.base.rcc->pipe;
     item = (PipeItem *) ring;
     while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
         Drawable *drawable;
@@ -1702,7 +1711,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
             ring_remove(&tmp_item->link);
             worker->display_channel->common.base.release_item(
                 worker->display_channel->common.base.rcc, tmp_item, FALSE);
-            worker->display_channel->common.base.pipe_size--;
+            worker->display_channel->common.base.rcc->pipe_size--;
 
             if (!item) {
                 item = (PipeItem *)ring;
@@ -2162,7 +2171,7 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
         item->rects->num_rects = n_rects;
         region_ret_rects(&drawable->tree_item.base.rgn, item->rects->rects, n_rects);
     }
-    red_channel_pipe_add((RedChannel*)channel, (PipeItem *)item);
+    red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
 }
 
 static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
@@ -2180,7 +2189,7 @@ static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
     item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
     item->rects->num_rects = n_rects;
     region_ret_rects(&agent->vis_region, item->rects->rects, n_rects);
-    red_channel_pipe_add((RedChannel*)channel, (PipeItem *)item);
+    red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
 }
 
 static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item)
@@ -2225,7 +2234,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
         region_clear(&stream_agent->vis_region);
         ASSERT(!pipe_item_is_linked(&stream_agent->destroy_item));
         stream->refs++;
-        red_channel_pipe_add(&channel->common.base, &stream_agent->destroy_item);
+        red_channel_client_pipe_add(channel->common.base.rcc, &stream_agent->destroy_item);
     }
     ring_remove(&stream->link);
     red_release_stream(worker, stream);
@@ -2250,7 +2259,7 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
         upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
-        red_channel_pipe_add((RedChannel *)channel, &upgrade_item->base);
+        red_channel_client_pipe_add(channel->common.base.rcc, &upgrade_item->base);
     }
     red_detach_stream(worker, stream);
 }
@@ -2403,7 +2412,7 @@ static void red_display_create_stream(DisplayChannel *display, Stream *stream)
     agent->drops = 0;
     agent->fps = MAX_FPS;
     reset_rate(agent);
-    red_channel_pipe_add(&display->common.base, &agent->create_item);
+    red_channel_client_pipe_add(display->common.base.rcc, &agent->create_item);
 }
 
 static void red_create_stream(RedWorker *worker, Drawable *drawable)
@@ -4172,7 +4181,7 @@ static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint
 
     if (worker->cursor_channel && (worker->mouse_mode == SPICE_MOUSE_MODE_SERVER ||
                                    cursor_cmd->type != QXL_CURSOR_MOVE || cursor_show)) {
-        red_channel_pipe_add(&worker->cursor_channel->common.base, &item->pipe_data);
+        red_channel_client_pipe_add(worker->cursor_channel->common.base.rcc, &item->pipe_data);
     } else {
         red_release_cursor(worker, item);
     }
@@ -4193,7 +4202,8 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ri
     int n = 0;
 
     *ring_is_empty = FALSE;
-    while (!cursor_is_connected(worker) || worker->cursor_channel->common.base.pipe_size <= max_pipe_size) {
+    while (!cursor_is_connected(worker) ||
+           worker->cursor_channel->common.base.rcc->pipe_size <= max_pipe_size) {
         if (!worker->qxl->st->qif->get_cursor_command(worker->qxl, &ext_cmd)) {
             *ring_is_empty = TRUE;
             if (worker->repoll_cursor_ring < CMD_RING_POLL_RETRIES) {
@@ -4233,7 +4243,8 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
     uint64_t start = red_now();
     
     *ring_is_empty = FALSE;
-    while (!display_is_connected(worker) || worker->display_channel->common.base.pipe_size <= max_pipe_size) {
+    while (!display_is_connected(worker)
+           || worker->display_channel->common.base.rcc->pipe_size <= max_pipe_size) {
         if (!worker->qxl->st->qif->get_command(worker->qxl, &ext_cmd)) {
             *ring_is_empty = TRUE;;
             if (worker->repoll_cmd_ring < CMD_RING_POLL_RETRIES) {
@@ -4491,7 +4502,7 @@ static inline void fill_palette(DisplayChannel *display_channel,
             *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
             return;
         }
-        if (red_palette_cache_add(display_channel, palette->unique, 1)) {
+        if (red_palette_cache_add(display_channel->common.base.rcc, palette->unique, 1)) {
             *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
         }
     }
@@ -5917,7 +5928,7 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
                 red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
                 return;
             }
-            if (red_cursor_cache_add(cursor_channel, red_cursor->header.unique, 1)) {
+            if (red_cursor_cache_add(cursor_channel->common.base.rcc, red_cursor->header.unique, 1)) {
                 red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
             }
         }
@@ -6166,7 +6177,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
     Ring *pipe;
 
     ASSERT(num_surfaces);
-    pipe = &display_channel->common.base.pipe;
+    pipe = &display_channel->common.base.rcc->pipe;
 
     for (pipe_item = (PipeItem *)ring_get_head(pipe);
          pipe_item;
@@ -6204,7 +6215,7 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
     resent_areas[0] = *first_area;
     num_resent = 1;
 
-    pipe = &display_channel->common.base.pipe;
+    pipe = &display_channel->common.base.rcc->pipe;
 
     // going from the oldest to the newest
     for (pipe_item = (PipeItem *)ring_get_tail(pipe);
@@ -8307,8 +8318,9 @@ void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
 static void red_migrate_display(RedWorker *worker)
 {
     if (worker->display_channel) {
-        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
-        red_channel_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
+        red_pipes_add_verb(&worker->display_channel->common.base,
+                           SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+        red_channel_pipes_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
     }
 }
 
@@ -8437,7 +8449,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
 
     worker->display_channel->surface_client_created[surface_id] = TRUE;
 
-    red_channel_pipe_add(&worker->display_channel->common.base, &create->pipe_item);
+    red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &create->pipe_item);
 }
 
 static inline void red_create_surface_item(RedWorker *worker, int surface_id)
@@ -8527,7 +8539,7 @@ static inline void flush_display_commands(RedWorker *worker)
         for (;;) {
             red_channel_push(&worker->display_channel->common.base);
             if (!display_is_connected(worker) ||
-                 worker->display_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
+                 worker->display_channel->common.base.rcc->pipe_size <= MAX_PIPE_SIZE) {
                 break;
             }
             RedChannel *channel = (RedChannel *)worker->display_channel;
@@ -8570,8 +8582,8 @@ static inline void flush_cursor_commands(RedWorker *worker)
         int sleep_count = 0;
         for (;;) {
             red_channel_push(&worker->cursor_channel->common.base);
-            if (!cursor_is_connected(worker) ||
-                                        worker->cursor_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
+            if (!cursor_is_connected(worker)
+                || worker->cursor_channel->common.base.rcc->pipe_size <= MAX_PIPE_SIZE) {
                 break;
             }
             RedChannel *channel = (RedChannel *)worker->cursor_channel;
@@ -8601,7 +8613,7 @@ static void push_new_primary_surface(RedWorker *worker)
     DisplayChannel *display_channel;
 
     if ((display_channel = worker->display_channel)) {
-        red_channel_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+        red_channel_client_pipe_add_type(display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
         if (!display_channel->common.base.migrate) {
             red_create_surface_item(worker, 0);
         }
@@ -8659,7 +8671,7 @@ static void on_new_display_channel(RedWorker *worker)
         push_new_primary_surface(worker);
         red_add_surface_image(worker, 0);
         if (red_channel_is_connected(&display_channel->common.base)) {
-            red_pipe_add_verb(&display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
+            red_pipe_add_verb(display_channel->common.base.rcc, SPICE_MSG_DISPLAY_MARK);
             red_disply_start_streams(display_channel);
         }
     }
@@ -8897,7 +8909,7 @@ static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
         return FALSE;
     }
     channel->expect_migrate_mark = FALSE;
-    red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
+    red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_MIGRATE_DATA);
     return TRUE;
 }
 
@@ -8951,7 +8963,7 @@ static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint3
 
     if (migrate_data->pixmap_cache_freezer) {
         channel->pixmap_cache->size = migrate_data->pixmap_cache_size;
-        red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_RESET);
+        red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_PIXMAP_RESET);
     }
 
     if (display_channel_handle_migrate_glz_dictionary(channel, migrate_data)) {
@@ -8964,7 +8976,7 @@ static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint3
         PANIC("restoring global lz dictionary failed");
     }
 
-    red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+    red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
     red_channel_ack_zero_messages_window(&channel->common.base);
     return TRUE;
 }
@@ -9260,9 +9272,11 @@ static void red_disconnect_cursor(RedChannel *channel)
 
 static void red_migrate_cursor(RedWorker *worker)
 {
-    if (worker->cursor_channel) {
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
+    if (cursor_is_connected(worker)) {
+        red_channel_pipes_add_type(&worker->cursor_channel->common.base,
+                                   PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_pipes_add_type(&worker->cursor_channel->common.base,
+                                   PIPE_ITEM_TYPE_MIGRATE);
     }
 }
 
@@ -9274,7 +9288,7 @@ static void on_new_cursor_channel(RedWorker *worker)
     red_channel_ack_zero_messages_window(&channel->common.base);
     red_channel_push_set_ack(&channel->common.base);
     if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
+        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 }
 
@@ -9578,16 +9592,16 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
     if (worker->cursor_channel) {
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
-            red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
+            red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
         }
         ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
     }
 
     if (worker->display_channel) {
-        red_channel_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+        red_channel_client_pipe_add_type(worker->display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+        red_pipe_add_verb(worker->display_channel->common.base.rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
     }
 
     red_display_clear_glz_drawables(worker->display_channel);
@@ -9624,13 +9638,15 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
 
-    if (worker->display_channel) {
-        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
+    if (display_is_connected(worker)) {
+        red_pipes_add_verb(&worker->display_channel->common.base,
+                           SPICE_MSG_DISPLAY_MARK);
         red_channel_push(&worker->display_channel->common.base);
     }
 
-    if (worker->cursor_channel) {
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
+    if (cursor_is_connected(worker)) {
+        red_channel_pipes_add_type(&worker->cursor_channel->common.base,
+                                   PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 
     message = RED_WORKER_MESSAGE_READY;
@@ -9654,9 +9670,9 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
     if (worker->cursor_channel) {
-        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
-            red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
+            red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
         }
         ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
     }
@@ -9702,7 +9718,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
             red_printf("oom current %u pipe %u", worker->current_size,
                        worker->display_channel ?
-                       display_red_channel->pipe_size : 0);
+                       display_red_channel->rcc->pipe_size : 0);
             red_free_some(worker);
             worker->qxl->st->qif->flush_resources(worker->qxl);
         }
@@ -9716,9 +9732,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
 
         red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
         if (worker->cursor_channel) {
-            red_channel_pipe_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+            red_channel_client_pipe_add_type(cursor_red_channel->rcc,
+                                             PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
             if (!cursor_red_channel->migrate) {
-                red_pipe_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
+                red_pipe_add_verb(cursor_red_channel->rcc, SPICE_MSG_CURSOR_RESET);
             }
             ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
 
diff --git a/server/smartcard.c b/server/smartcard.c
index f67552f..36855a1 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -359,7 +359,7 @@ static void smartcard_channel_disconnect(RedChannelClient *rcc)
  * so no mutex is required. */
 static void smartcard_channel_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
 {
-    red_channel_pipe_add_push(rcc->channel, item);
+    red_channel_client_pipe_add_push(rcc, item);
 }
 
 static void smartcard_push_error(RedChannelClient *rcc, uint32_t reader_id, VSCErrorCode error)
-- 
1.7.5.1



More information about the Spice-devel mailing list