[Spice-devel] [RFCv5 04/47] server/red_channel (all): introduce RedChannelClient

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


This commit adds a RedChannelClient that now owns the stream connection,
but still doesn't own the pipe. There is only a single RCC per RC
right now (and RC still means RedChannel, RedClient will be introduced
later). All internal api changes are in server/red_channel.h, hence
the need to update all channels. red_worker.c is affected the most because
it makes use of direct access to some of RedChannel still.

API changes:

 1. red_channel_client_create added.
  rec_channel_create -> (red_channel_create, red_channel_client_create)
 2. two way connection: rcc->channel, channel->rcc (later channel will
  hold a list, and there will be a RedClient to hold the list of channels
  per client)
 3. seperation of channel disconnect and channel_client_disconnect
---
 server/inputs_channel.c          |   39 ++-
 server/main_channel.c            |   82 +++---
 server/red_channel.c             |  625 ++++++++++++++++++++++-------------
 server/red_channel.h             |  109 ++++---
 server/red_client_shared_cache.h |   17 +-
 server/red_tunnel_worker.c       |  214 +++++++-----
 server/red_worker.c              |  678 +++++++++++++++++++-------------------
 server/smartcard.c               |  150 +++++-----
 8 files changed, 1088 insertions(+), 826 deletions(-)

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 0cc53a2..3a4a0d0 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -164,9 +164,9 @@ const VDAgentMouseState *inputs_get_mouse_state(void)
     return &g_inputs_channel->mouse_state;
 }
 
-static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
 {
-    InputsChannel *inputs_channel = SPICE_CONTAINEROF(channel, InputsChannel, base);
+    InputsChannel *inputs_channel = SPICE_CONTAINEROF(rcc->channel, InputsChannel, base);
 
     if (msg_header->size > RECEIVE_BUF_SIZE) {
         red_printf("error: too large incoming message");
@@ -175,7 +175,7 @@ static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataH
     return inputs_channel->recv_buf;
 }
 
-static void inputs_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
+static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
                                                uint8_t *msg)
 {
 }
@@ -249,17 +249,17 @@ static void inputs_pipe_add_type(InputsChannel *channel, int type)
     red_channel_pipe_add_push(&channel->base, &pipe_item->base);
 }
 
-static void inputs_channel_release_pipe_item(RedChannel *channel,
+static void inputs_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *base, int item_pushed)
 {
     free(base);
 }
 
-static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
+static void inputs_channel_send_item(RedChannelClient *rcc, PipeItem *base)
 {
-    SpiceMarshaller *m = red_channel_get_marshaller(channel);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
-    red_channel_init_send_data(channel, base->type, base);
+    red_channel_client_init_send_data(rcc, base->type, base);
     switch (base->type) {
         case PIPE_ITEM_KEY_MODIFIERS:
         {
@@ -288,12 +288,12 @@ static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
         default:
             break;
     }
-    red_channel_begin_send_message(channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
-static int inputs_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16_t type, void *message)
+static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
 {
-    InputsChannel *inputs_channel = (InputsChannel *)channel;
+    InputsChannel *inputs_channel = (InputsChannel *)rcc->channel;
     uint8_t *buf = (uint8_t *)message;
 
     ASSERT(g_inputs_channel == inputs_channel);
@@ -446,10 +446,10 @@ static void inputs_relase_keys(void)
     kbd_push_scan(keyboard, 0x38 | 0x80); //LALT
 }
 
-static void inputs_channel_on_error(RedChannel *channel)
+static void inputs_channel_on_error(RedChannelClient *rcc)
 {
     inputs_relase_keys();
-    reds_disconnect();
+    red_channel_client_destroy(rcc);
 }
 
 static void inputs_shutdown(Channel *channel)
@@ -485,11 +485,11 @@ static void inputs_pipe_add_init(InputsChannel *inputs_channel)
     red_channel_pipe_add_push(&inputs_channel->base, &item->base);
 }
 
-static int inputs_channel_config_socket(RedChannel *channel)
+static int inputs_channel_config_socket(RedChannelClient *rcc)
 {
     int flags;
     int delay_val = 1;
-    RedsStream *stream = red_channel_get_stream(channel);
+    RedsStream *stream = red_channel_client_get_stream(rcc);
 
     if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
             &delay_val, sizeof(delay_val)) == -1) {
@@ -505,7 +505,7 @@ static int inputs_channel_config_socket(RedChannel *channel)
     return TRUE;
 }
 
-static void inputs_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void inputs_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
 }
 
@@ -514,11 +514,13 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
                         uint32_t *caps)
 {
     InputsChannel *inputs_channel;
-    red_printf("");
+    RedChannelClient *rcc;
+
     ASSERT(channel->data == NULL);
 
+    red_printf("input channel create");
     g_inputs_channel = inputs_channel = (InputsChannel*)red_channel_create_parser(
-        sizeof(*inputs_channel), stream, core, migration, FALSE /* handle_acks */
+        sizeof(*inputs_channel), core, migration, FALSE /* handle_acks */
         ,inputs_channel_config_socket
         ,spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL)
         ,inputs_channel_handle_parsed
@@ -533,6 +535,9 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
         ,NULL
         ,NULL);
     ASSERT(inputs_channel);
+    red_printf("input channel client create");
+    rcc = red_channel_client_create(sizeof(RedChannelClient), &g_inputs_channel->base, stream);
+    ASSERT(rcc);
     channel->data = inputs_channel;
     inputs_pipe_add_init(inputs_channel);
 }
diff --git a/server/main_channel.c b/server/main_channel.c
index 080ba1c..5059b3a 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -421,7 +421,8 @@ static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int seri
     data->ping_id = ping_id;
 }
 
-static uint64_t main_channel_handle_migrate_data_get_serial(RedChannel *base,
+static uint64_t main_channel_handle_migrate_data_get_serial(
+    RedChannelClient *rcc,
     uint32_t size, void *message)
 {
     MainMigrateData *data = message;
@@ -433,10 +434,10 @@ static uint64_t main_channel_handle_migrate_data_get_serial(RedChannel *base,
     return data->serial;
 }
 
-static uint64_t main_channel_handle_migrate_data(RedChannel *base,
+static uint64_t main_channel_handle_migrate_data(RedChannelClient *rcc,
     uint32_t size, void *message)
 {
-    MainChannel *main_chan = SPICE_CONTAINEROF(base, MainChannel, base);
+    MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
     MainMigrateData *data = message;
 
     if (size < sizeof(*data)) {
@@ -607,12 +608,12 @@ static void main_channel_marshall_multi_media_time(SpiceMarshaller *m,
     spice_marshall_msg_main_multi_media_time(m, &time_mes);
 }
 
-static void main_channel_send_item(RedChannel *channel, PipeItem *base)
+static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
 {
-    SpiceMarshaller *m = red_channel_get_marshaller(channel);
-    MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
+    MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
-    red_channel_init_send_data(channel, base->type, base);
+    red_channel_client_init_send_data(rcc, base->type, base);
     switch (base->type) {
         case SPICE_MSG_MAIN_CHANNELS_LIST:
             main_channel_marshall_channels(m);
@@ -642,7 +643,7 @@ static void main_channel_send_item(RedChannel *channel, PipeItem *base)
             break;
         case SPICE_MSG_MIGRATE_DATA:
             main_channel_marshall_migrate_data_item(m,
-                red_channel_get_message_serial(&main_chan->base),
+                red_channel_client_get_message_serial(rcc),
                 main_chan->ping_id);
             break;
         case SPICE_MSG_MAIN_INIT:
@@ -668,18 +669,18 @@ static void main_channel_send_item(RedChannel *channel, PipeItem *base)
             main_channel_marshall_migrate_switch(m);
             break;
     };
-    red_channel_begin_send_message(channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
-static void main_channel_release_pipe_item(RedChannel *channel,
+static void main_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *base, int item_pushed)
 {
     free(base);
 }
 
-static int main_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16_t type, void *message)
+static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
 {
-    MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
+    MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
 
     switch (type) {
     case SPICE_MSGC_MAIN_AGENT_START:
@@ -770,35 +771,36 @@ static int main_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16
     return TRUE;
 }
 
-static void main_channel_on_error(RedChannel *channel)
+static void main_channel_on_error(RedChannelClient *rcc)
 {
     reds_disconnect();
 }
 
-static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
 {
-    MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
+    MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
 
     return main_chan->recv_buf;
 }
 
-static void main_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
+static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
                                                uint8_t *msg)
 {
 }
 
-static int main_channel_config_socket(RedChannel *channel)
+static int main_channel_config_socket(RedChannelClient *rcc)
 {
     return TRUE;
 }
 
-static void main_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void main_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
 }
 
-static int main_channel_handle_migrate_flush_mark(RedChannel *base)
+static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
 {
-    main_channel_push_migrate_data_item(SPICE_CONTAINEROF(base, MainChannel, base));
+    main_channel_push_migrate_data_item(SPICE_CONTAINEROF(rcc->channel,
+                                        MainChannel, base));
     return TRUE;
 }
 
@@ -807,26 +809,30 @@ static void main_channel_link(Channel *channel, RedsStream *stream, int migratio
                         uint32_t *caps)
 {
     MainChannel *main_chan;
-    red_printf("");
     ASSERT(channel->data == NULL);
 
-    main_chan = (MainChannel*)red_channel_create_parser(
-        sizeof(*main_chan), stream, core, migration, FALSE /* handle_acks */
-        ,main_channel_config_socket
-        ,spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL)
-        ,main_channel_handle_parsed
-        ,main_channel_alloc_msg_rcv_buf
-        ,main_channel_release_msg_rcv_buf
-        ,main_channel_hold_pipe_item
-        ,main_channel_send_item
-        ,main_channel_release_pipe_item
-        ,main_channel_on_error
-        ,main_channel_on_error
-        ,main_channel_handle_migrate_flush_mark
-        ,main_channel_handle_migrate_data
-        ,main_channel_handle_migrate_data_get_serial);
-    ASSERT(main_chan);
-    channel->data = main_chan;
+    if (channel->data == NULL) {
+        red_printf("create main channel");
+        channel->data = red_channel_create_parser(
+            sizeof(*main_chan), core, migration, FALSE /* handle_acks */
+            ,main_channel_config_socket
+            ,spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL)
+            ,main_channel_handle_parsed
+            ,main_channel_alloc_msg_rcv_buf
+            ,main_channel_release_msg_rcv_buf
+            ,main_channel_hold_pipe_item
+            ,main_channel_send_item
+            ,main_channel_release_pipe_item
+            ,main_channel_on_error
+            ,main_channel_on_error
+            ,main_channel_handle_migrate_flush_mark
+            ,main_channel_handle_migrate_data
+            ,main_channel_handle_migrate_data_get_serial);
+        ASSERT(channel->data);
+    }
+    main_chan = (MainChannel*)channel->data;
+    red_printf("add main channel client");
+    red_channel_client_create(sizeof(RedChannelClient), channel->data, stream);
 }
 
 int main_channel_getsockname(Channel *channel, struct sockaddr *sa, socklen_t *salen)
diff --git a/server/red_channel.c b/server/red_channel.c
index 9ecc7ef..2758ede 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -33,8 +33,7 @@
 #include "red_channel.h"
 #include "generated_marshallers.h"
 
-static PipeItem *red_channel_pipe_get(RedChannel *channel);
-static void red_channel_event(int fd, int event, void *data);
+static void red_channel_client_event(int fd, int event, void *data);
 
 /* return the number of bytes read. -1 in case of error */
 static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
@@ -152,9 +151,14 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
     }
 }
 
+void red_channel_client_receive(RedChannelClient *rcc)
+{
+    red_peer_handle_incoming(rcc->stream, &rcc->incoming);
+}
+
 void red_channel_receive(RedChannel *channel)
 {
-    red_peer_handle_incoming(channel->stream, &channel->incoming);
+    red_channel_client_receive(channel->rcc);
 }
 
 static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
@@ -201,124 +205,194 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
     }
 }
 
-static void red_channel_on_output(void *opaque, int n)
+static void red_channel_client_on_output(void *opaque, int n)
 {
-    RedChannel *channel = opaque;
+    RedChannelClient *rcc = opaque;
 
-    stat_inc_counter(channel->out_bytes_counter, n);
+    stat_inc_counter(rcc->channel->out_bytes_counter, n);
 }
 
-void red_channel_default_peer_on_error(RedChannel *channel)
+void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
 {
-    channel->disconnect(channel);
+    rcc->channel->disconnect(rcc);
 }
 
-static void red_channel_peer_on_incoming_error(RedChannel *channel)
+static void red_channel_peer_on_incoming_error(RedChannelClient *rcc)
 {
-    channel->on_incoming_error(channel);
+    rcc->channel->on_incoming_error(rcc);
 }
 
-static void red_channel_peer_on_outgoing_error(RedChannel *channel)
+static void red_channel_peer_on_outgoing_error(RedChannelClient *rcc)
 {
-    channel->on_outgoing_error(channel);
+    rcc->channel->on_outgoing_error(rcc);
 }
 
-static int red_channel_peer_get_out_msg_size(void *opaque)
+static int red_channel_client_peer_get_out_msg_size(void *opaque)
 {
-    RedChannel *channel = (RedChannel *)opaque;
+    RedChannelClient *rcc = (RedChannelClient *)opaque;
 
-    return channel->send_data.size;
+    return rcc->send_data.size;
 }
 
-static void red_channel_peer_prepare_out_msg(void *opaque, struct iovec *vec, int *vec_size, int pos)
+static void red_channel_client_peer_prepare_out_msg(
+    void *opaque, struct iovec *vec, int *vec_size, int pos)
 {
-    RedChannel *channel = (RedChannel *)opaque;
+    RedChannelClient *rcc = (RedChannelClient *)opaque;
 
-    *vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
+    *vec_size = spice_marshaller_fill_iovec(rcc->send_data.marshaller,
                                             vec, MAX_SEND_VEC, pos);
 }
 
-static void red_channel_peer_on_out_block(void *opaque)
+static void red_channel_client_peer_on_out_block(void *opaque)
 {
-    RedChannel *channel = (RedChannel *)opaque;
+    RedChannelClient *rcc = (RedChannelClient *)opaque;
 
-    channel->send_data.blocked = TRUE;
-    channel->core->watch_update_mask(channel->stream->watch,
+    rcc->send_data.blocked = TRUE;
+    rcc->channel->core->watch_update_mask(rcc->stream->watch,
                                      SPICE_WATCH_EVENT_READ |
                                      SPICE_WATCH_EVENT_WRITE);
 }
 
-static void red_channel_reset_send_data(RedChannel *channel)
+static void red_channel_client_reset_send_data(RedChannelClient *rcc)
+{
+    spice_marshaller_reset(rcc->send_data.marshaller);
+    rcc->send_data.header = (SpiceDataHeader *)
+        spice_marshaller_reserve_space(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
+    spice_marshaller_set_base(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
+    rcc->send_data.header->type = 0;
+    rcc->send_data.header->size = 0;
+    rcc->send_data.header->sub_list = 0;
+    rcc->send_data.header->serial = ++rcc->send_data.serial;
+}
+
+void red_channel_client_push_set_ack(RedChannelClient *rcc)
 {
-    spice_marshaller_reset(channel->send_data.marshaller);
-    channel->send_data.header = (SpiceDataHeader *)
-        spice_marshaller_reserve_space(channel->send_data.marshaller, sizeof(SpiceDataHeader));
-    spice_marshaller_set_base(channel->send_data.marshaller, sizeof(SpiceDataHeader));
-    channel->send_data.header->type = 0;
-    channel->send_data.header->size = 0;
-    channel->send_data.header->sub_list = 0;
-    channel->send_data.header->serial = ++channel->send_data.serial;
+    red_channel_pipe_add_type(rcc->channel, 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);
 }
 
-static void red_channel_send_set_ack(RedChannel *channel)
+static void red_channel_client_send_set_ack(RedChannelClient *rcc)
 {
     SpiceMsgSetAck ack;
 
-    ASSERT(channel);
-    red_channel_init_send_data(channel, SPICE_MSG_SET_ACK, NULL);
-    ack.generation = ++channel->ack_data.generation;
-    ack.window = channel->ack_data.client_window;
-    channel->ack_data.messages_window = 0;
+    ASSERT(rcc);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_SET_ACK, NULL);
+    ack.generation = ++rcc->ack_data.generation;
+    ack.window = rcc->ack_data.client_window;
+    rcc->ack_data.messages_window = 0;
 
-    spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
+    spice_marshall_msg_set_ack(rcc->send_data.marshaller, &ack);
 
-    red_channel_begin_send_message(channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
-static void red_channel_send_item(RedChannel *channel, PipeItem *item)
+static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
 {
-    red_channel_reset_send_data(channel);
+    int handled = TRUE;
+
+    ASSERT(rcc->send_data.item == NULL);
+    red_channel_client_reset_send_data(rcc);
     switch (item->type) {
         case PIPE_ITEM_TYPE_SET_ACK:
-            red_channel_send_set_ack(channel);
-            return;
+            red_channel_client_send_set_ack(rcc);
+            break;
+        default:
+            handled = FALSE;
+    }
+    if (!handled) {
+        rcc->channel->send_item(rcc, item);
     }
-    /* only reached if not handled here */
-    channel->send_item(channel, item);
 }
 
-static void red_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
+static void red_channel_client_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
+    int handled = TRUE;
+
     switch (item->type) {
         case PIPE_ITEM_TYPE_SET_ACK:
             free(item);
-            return;
+            break;
+        default:
+            handled = FALSE;
+    }
+    if (!handled) {
+        rcc->channel->release_item(rcc, item, item_pushed);
     }
-    /* only reached if not handled here */
-    channel->release_item(channel, item, item_pushed);
 }
 
-static void red_channel_peer_on_out_msg_done(void *opaque)
+static inline void red_channel_client_release_sent_item(RedChannelClient *rcc)
 {
-    RedChannel *channel = (RedChannel *)opaque;
-    channel->send_data.size = 0;
-    if (channel->send_data.item) {
-        red_channel_release_item(channel, channel->send_data.item, TRUE);
-        channel->send_data.item = NULL;
+    if (rcc->send_data.item) {
+        red_channel_client_release_item(rcc,
+                                        rcc->send_data.item, TRUE);
+        rcc->send_data.item = NULL;
     }
-    if (channel->send_data.blocked) {
-        channel->send_data.blocked = FALSE;
-        channel->core->watch_update_mask(channel->stream->watch,
+}
+
+static void red_channel_peer_on_out_msg_done(void *opaque)
+{
+    RedChannelClient *rcc = (RedChannelClient *)opaque;
+
+    rcc->send_data.size = 0;
+    red_channel_client_release_sent_item(rcc);
+    if (rcc->send_data.blocked) {
+        rcc->send_data.blocked = FALSE;
+        rcc->channel->core->watch_update_mask(rcc->stream->watch,
                                          SPICE_WATCH_EVENT_READ);
     }
 }
 
-RedChannel *red_channel_create(int size, RedsStream *stream,
+static void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
+{
+    ASSERT(rcc);
+	channel->rcc = rcc;
+}
+
+RedChannelClient *red_channel_client_create(
+    int size,
+    RedChannel *channel,
+    RedsStream *stream)
+{
+    RedChannelClient *rcc = NULL;
+
+    ASSERT(stream && channel && size >= sizeof(RedChannelClient));
+    rcc = spice_malloc0(size);
+    rcc->stream = stream;
+    rcc->channel = channel;
+    rcc->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
+                                             // block flags)
+    rcc->ack_data.client_generation = ~0;
+    rcc->ack_data.client_window = CLIENT_ACK_WINDOW;
+    rcc->send_data.marshaller = spice_marshaller_new();
+
+    rcc->incoming.opaque = rcc;
+    rcc->incoming.cb = &channel->incoming_cb;
+
+    rcc->outgoing.opaque = rcc;
+    rcc->outgoing.cb = &channel->outgoing_cb;
+    rcc->outgoing.pos = 0;
+    rcc->outgoing.size = 0;
+    if (!channel->config_socket(rcc)) {
+        goto error;
+    }
+
+    stream->watch = channel->core->watch_add(stream->socket,
+                                           SPICE_WATCH_EVENT_READ,
+                                           red_channel_client_event, rcc);
+    red_channel_add_client(channel, rcc);
+    return rcc;
+error:
+    free(rcc);
+    reds_stream_free(stream);
+    return NULL;
+}
+
+RedChannel *red_channel_create(int size,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -339,7 +413,6 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
     ASSERT(config_socket && disconnect && handle_message && alloc_recv_buf &&
            release_item);
     channel = spice_malloc0(size);
-
     channel->handle_acks = handle_acks;
     channel->disconnect = disconnect;
     channel->send_item = send_item;
@@ -348,69 +421,40 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
     channel->handle_migrate_flush_mark = handle_migrate_flush_mark;
     channel->handle_migrate_data = handle_migrate_data;
     channel->handle_migrate_data_get_serial = handle_migrate_data_get_serial;
+    channel->config_socket = config_socket;
 
-    channel->stream = stream;
     channel->core = core;
-    channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
-                                             // block flags)
-    channel->ack_data.client_generation = ~0;
-    channel->ack_data.client_window = CLIENT_ACK_WINDOW;
-
     channel->migrate = migrate;
     ring_init(&channel->pipe);
-    channel->send_data.marshaller = spice_marshaller_new();
 
-    channel->incoming.opaque = channel;
     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;
     channel->incoming_cb.handle_message = (handle_message_proc)handle_message;
-    channel->incoming_cb.on_error = (on_incoming_error_proc)red_channel_default_peer_on_error;
-
-    channel->outgoing.opaque = channel;
-    channel->outgoing.pos = 0;
-    channel->outgoing.size = 0;
-
-    channel->outgoing_cb.get_msg_size = red_channel_peer_get_out_msg_size;
-    channel->outgoing_cb.prepare = red_channel_peer_prepare_out_msg;
-    channel->outgoing_cb.on_block = red_channel_peer_on_out_block;
-    channel->outgoing_cb.on_error = (on_outgoing_error_proc)red_channel_default_peer_on_error;
+    channel->incoming_cb.on_error =
+        (on_incoming_error_proc)red_channel_client_default_peer_on_error;
+    channel->outgoing_cb.get_msg_size = red_channel_client_peer_get_out_msg_size;
+    channel->outgoing_cb.prepare = red_channel_client_peer_prepare_out_msg;
+    channel->outgoing_cb.on_block = red_channel_client_peer_on_out_block;
+    channel->outgoing_cb.on_error =
+        (on_outgoing_error_proc)red_channel_client_default_peer_on_error;
     channel->outgoing_cb.on_msg_done = red_channel_peer_on_out_msg_done;
-    channel->outgoing_cb.on_output = red_channel_on_output;
-
-    channel->incoming.cb = &channel->incoming_cb;
-    channel->outgoing.cb = &channel->outgoing_cb;
+    channel->outgoing_cb.on_output = red_channel_client_on_output;
 
     channel->shut = 0; // came here from inputs, perhaps can be removed? XXX
     channel->out_bytes_counter = 0;
-
-    if (!config_socket(channel)) {
-        goto error;
-    }
-
-    channel->stream->watch = channel->core->watch_add(channel->stream->socket,
-                                                    SPICE_WATCH_EVENT_READ,
-                                                    red_channel_event, channel);
-
     return channel;
-
-error:
-    spice_marshaller_destroy(channel->send_data.marshaller);
-    free(channel);
-    reds_stream_free(stream);
-
-    return NULL;
 }
 
-static void do_nothing_disconnect(RedChannel *red_channel)
+static void do_nothing_disconnect(RedChannelClient *rcc)
 {
 }
 
-static int do_nothing_handle_message(RedChannel *red_channel, SpiceDataHeader *header, uint8_t *msg)
+static int do_nothing_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
 {
     return TRUE;
 }
 
-RedChannel *red_channel_create_parser(int size, RedsStream *stream,
+RedChannel *red_channel_create_parser(int size,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -427,7 +471,7 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                channel_handle_migrate_data_proc handle_migrate_data,
                                channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial)
 {
-    RedChannel *channel = red_channel_create(size, stream,
+    RedChannel *channel = red_channel_create(size,
         core, migrate, handle_acks, config_socket, do_nothing_disconnect,
         do_nothing_handle_message, alloc_recv_buf, release_recv_buf, hold_item,
         send_item, release_item, handle_migrate_flush_mark, handle_migrate_data,
@@ -438,62 +482,152 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
     }
     channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed;
     channel->incoming_cb.parser = parser;
-    channel->on_incoming_error = incoming_error;
-    channel->on_outgoing_error = outgoing_error;
     channel->incoming_cb.on_error = (on_incoming_error_proc)red_channel_peer_on_incoming_error;
     channel->outgoing_cb.on_error = (on_outgoing_error_proc)red_channel_peer_on_outgoing_error;
+    channel->on_incoming_error = incoming_error;
+    channel->on_outgoing_error = outgoing_error;
     return channel;
 }
 
+void red_channel_client_destroy(RedChannelClient *rcc)
+{
+    red_channel_client_disconnect(rcc);
+    spice_marshaller_destroy(rcc->send_data.marshaller);
+    free(rcc);
+}
+
 void red_channel_destroy(RedChannel *channel)
 {
     if (!channel) {
         return;
     }
-    red_channel_pipe_clear(channel);
-    reds_stream_free(channel->stream);
-    spice_marshaller_destroy(channel->send_data.marshaller);
+    if (channel->rcc) {
+        red_channel_client_destroy(channel->rcc);
+    }
     free(channel);
 }
 
+static void red_channel_client_shutdown(RedChannelClient *rcc)
+{
+    if (rcc->stream && !rcc->stream->shutdown) {
+        rcc->channel->core->watch_remove(rcc->stream->watch);
+        rcc->stream->watch = NULL;
+        shutdown(rcc->stream->socket, SHUT_RDWR);
+        rcc->stream->shutdown = TRUE;
+        rcc->incoming.shut = TRUE;
+    }
+    red_channel_client_release_sent_item(rcc);
+}
+
 void red_channel_shutdown(RedChannel *channel)
 {
-    red_printf("");
-    if (channel->stream && !channel->stream->shutdown) {
-        channel->core->watch_update_mask(channel->stream->watch,
-                                         SPICE_WATCH_EVENT_READ);
-        red_channel_pipe_clear(channel);
-        shutdown(channel->stream->socket, SHUT_RDWR);
-        channel->stream->shutdown = TRUE;
-        channel->incoming.shut = TRUE;
+    if (channel->rcc) {
+        red_channel_client_shutdown(channel->rcc);
+    }
+    red_channel_pipe_clear(channel);
+}
+
+void red_channel_client_send(RedChannelClient *rcc)
+{
+    red_peer_handle_outgoing(rcc->stream, &rcc->outgoing);
+}
+
+void red_channel_send(RedChannel *channel)
+{
+    if (channel->rcc) {
+        red_channel_client_send(channel->rcc);
     }
 }
 
+static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
+{
+    return (rcc->channel->handle_acks &&
+            (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)
+{
+    PipeItem *item;
+
+    if (!rcc || rcc->send_data.blocked
+             || red_channel_client_waiting_for_ack(rcc)
+             || !(item = (PipeItem *)ring_get_tail(&rcc->channel->pipe))) {
+        return NULL;
+    }
+    --rcc->channel->pipe_size;
+    ring_remove(&item->link);
+    return item;
+}
+
+static void red_channel_client_push(RedChannelClient *rcc)
+{
+    PipeItem *pipe_item;
+
+    if (!rcc->during_send) {
+        rcc->during_send = TRUE;
+    } else {
+        return;
+    }
+
+    if (rcc->send_data.blocked) {
+        red_channel_client_send(rcc);
+    }
+
+    while ((pipe_item = red_channel_client_pipe_get(rcc))) {
+        red_channel_client_send_item(rcc, pipe_item);
+    }
+    rcc->during_send = FALSE;
+}
+
+void red_channel_push(RedChannel *channel)
+{
+    if (!channel || !channel->rcc) {
+        return;
+    }
+    red_channel_client_push(channel->rcc);
+}
+
+static void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc)
+{
+    rcc->ack_data.messages_window = 0;
+    red_channel_client_push(rcc);
+}
+
+// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
+// specific
 void red_channel_init_outgoing_messages_window(RedChannel *channel)
 {
-    channel->ack_data.messages_window = 0;
-    red_channel_push(channel);
+    red_channel_client_init_outgoing_messages_window(channel->rcc);
 }
 
 static void red_channel_handle_migrate_flush_mark(RedChannel *channel)
 {
     if (channel->handle_migrate_flush_mark) {
-        channel->handle_migrate_flush_mark(channel);
+        channel->handle_migrate_flush_mark(channel->rcc);
     }
 }
 
-static void red_channel_handle_migrate_data(RedChannel *channel, uint32_t size, void *message)
+// TODO: the whole migration is broken with multiple clients. What do we want to do?
+// basically just
+//  1) source send mark to all
+//  2) source gets at various times the data (waits for all)
+//  3) source migrates to target
+//  4) target sends data to all
+// So need to make all the handlers work with per channel/client data (what data exactly?)
+static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
-    if (!channel->handle_migrate_data) {
+    if (!rcc->channel->handle_migrate_data) {
         return;
     }
-    ASSERT(red_channel_get_message_serial(channel) == 0);
-    red_channel_set_message_serial(channel,
-        channel->handle_migrate_data_get_serial(channel, size, message));
-    channel->handle_migrate_data(channel, size, message);
+    ASSERT(red_channel_client_get_message_serial(rcc) == 0);
+    red_channel_client_set_message_serial(rcc,
+        rcc->channel->handle_migrate_data_get_serial(rcc, size, message));
+    rcc->channel->handle_migrate_data(rcc, size, message);
 }
 
-int red_channel_handle_message(RedChannel *channel, uint32_t size,
+int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
                                uint16_t type, void *message)
 {
     switch (type) {
@@ -502,21 +636,21 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
             red_printf("bad message size");
             return FALSE;
         }
-        channel->ack_data.client_generation = *(uint32_t *)(message);
+        rcc->ack_data.client_generation = *(uint32_t *)(message);
         break;
     case SPICE_MSGC_ACK:
-        if (channel->ack_data.client_generation == channel->ack_data.generation) {
-            channel->ack_data.messages_window -= channel->ack_data.client_window;
-            red_channel_push(channel);
+        if (rcc->ack_data.client_generation == rcc->ack_data.generation) {
+            rcc->ack_data.messages_window -= rcc->ack_data.client_window;
+            red_channel_client_push(rcc);
         }
         break;
     case SPICE_MSGC_DISCONNECTING:
         break;
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        red_channel_handle_migrate_flush_mark(channel);
+        red_channel_handle_migrate_flush_mark(rcc->channel);
         break;
     case SPICE_MSGC_MIGRATE_DATA:
-        red_channel_handle_migrate_data(channel, size, message);
+        red_channel_handle_migrate_data(rcc, size, message);
         break;
     default:
         red_printf("invalid message type %u", type);
@@ -525,75 +659,54 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
     return TRUE;
 }
 
-static void red_channel_event(int fd, int event, void *data)
+static void red_channel_client_event(int fd, int event, void *data)
 {
-    RedChannel *channel = (RedChannel *)data;
+    RedChannelClient *rcc = (RedChannelClient *)data;
 
     if (event & SPICE_WATCH_EVENT_READ) {
-        red_channel_receive(channel);
+        red_channel_client_receive(rcc);
     }
     if (event & SPICE_WATCH_EVENT_WRITE) {
-        red_channel_push(channel);
+        red_channel_client_push(rcc);
     }
 }
 
-void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item)
+void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, PipeItem *item)
 {
-    ASSERT(channel->send_data.item == NULL);
-    channel->send_data.header->type = msg_type;
-    channel->send_data.item = item;
+    ASSERT(rcc->send_data.item == NULL);
+    ASSERT(msg_type != 0);
+    rcc->send_data.header->type = msg_type;
+    rcc->send_data.item = item;
     if (item) {
-        channel->hold_item(channel, item);
+        rcc->channel->hold_item(rcc, item);
     }
 }
 
-void red_channel_send(RedChannel *channel)
-{
-    red_peer_handle_outgoing(channel->stream, &channel->outgoing);
-}
-
-void red_channel_begin_send_message(RedChannel *channel)
-{
-    spice_marshaller_flush(channel->send_data.marshaller);
-    channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
-    channel->send_data.header->size =  channel->send_data.size - sizeof(SpiceDataHeader);
-    channel->ack_data.messages_window++;
-    channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
-    red_channel_send(channel);
-}
-
-void red_channel_push(RedChannel *channel)
+void red_channel_client_begin_send_message(RedChannelClient *rcc)
 {
-    PipeItem *pipe_item;
-
-    if (!channel) {
-        return;
-    }
+    SpiceMarshaller *m = rcc->send_data.marshaller;
 
-    if (!channel->during_send) {
-        channel->during_send = TRUE;
-    } else {
+    // TODO - better check: type in channel_allowed_types. Better: type in channel_allowed_types(channel_state)
+    if (rcc->send_data.header->type == 0) {
+        red_printf("BUG: header->type == 0");
         return;
     }
-
-    if (channel->send_data.blocked) {
-        red_channel_send(channel);
-    }
-
-    while ((pipe_item = red_channel_pipe_get(channel))) {
-        red_channel_send_item(channel, pipe_item);
-    }
-    channel->during_send = FALSE;
+    spice_marshaller_flush(m);
+    rcc->send_data.size = spice_marshaller_get_total_size(m);
+    rcc->send_data.header->size = rcc->send_data.size - sizeof(SpiceDataHeader);
+    rcc->ack_data.messages_window++;
+    rcc->send_data.header = NULL; /* avoid writing to this until we have a new message */
+    red_channel_client_send(rcc);
 }
 
-uint64_t red_channel_get_message_serial(RedChannel *channel)
+uint64_t red_channel_client_get_message_serial(RedChannelClient *rcc)
 {
-    return channel->send_data.serial;
+    return rcc->send_data.serial;
 }
 
-void red_channel_set_message_serial(RedChannel *channel, uint64_t serial)
+void red_channel_client_set_message_serial(RedChannelClient *rcc, uint64_t serial)
 {
-    channel->send_data.serial = serial;
+    rcc->send_data.serial = serial;
 }
 
 void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type)
@@ -657,28 +770,17 @@ void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type)
     red_channel_push(channel);
 }
 
-static inline int red_channel_waiting_for_ack(RedChannel *channel)
+int red_channel_is_connected(RedChannel *channel)
 {
-    return (channel->handle_acks && (channel->ack_data.messages_window > channel->ack_data.client_window * 2));
+    return channel->rcc != NULL;
 }
 
-static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
+void red_channel_client_clear_sent_item(RedChannelClient *rcc)
 {
-    PipeItem *item;
-
-    if (!channel || channel->send_data.blocked ||
-        red_channel_waiting_for_ack(channel) ||
-        !(item = (PipeItem *)ring_get_tail(&channel->pipe))) {
-        return NULL;
+    if (rcc->send_data.item) {
+        red_channel_client_release_item(rcc, rcc->send_data.item, TRUE);
+        rcc->send_data.item = NULL;
     }
-    --channel->pipe_size;
-    ring_remove(&item->link);
-    return item;
-}
-
-int red_channel_is_connected(RedChannel *channel)
-{
-    return !!channel->stream;
 }
 
 void red_channel_pipe_clear(RedChannel *channel)
@@ -686,82 +788,161 @@ void red_channel_pipe_clear(RedChannel *channel)
     PipeItem *item;
 
     ASSERT(channel);
-    if (channel->send_data.item) {
-        red_channel_release_item(channel, channel->send_data.item, TRUE);
-        channel->send_data.item = NULL;
+    if (channel->rcc) {
+        red_channel_client_clear_sent_item(channel->rcc);
     }
     while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
         ring_remove(&item->link);
-        red_channel_release_item(channel, item, FALSE);
+        red_channel_client_release_item(channel->rcc, item, FALSE);
     }
     channel->pipe_size = 0;
 }
 
+void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
+{
+    rcc->ack_data.messages_window = 0;
+}
+
 void red_channel_ack_zero_messages_window(RedChannel *channel)
 {
-    channel->ack_data.messages_window = 0;
+    red_channel_client_ack_zero_messages_window(channel->rcc);
 }
 
-void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
+void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window)
 {
-    channel->ack_data.client_window = client_window;
+    rcc->ack_data.client_window = client_window;
+}
+
+void red_channel_ack_set_client_window(RedChannel* channel, int client_window)
+{
+    if (channel->rcc) {
+        red_channel_client_ack_set_client_window(channel->rcc, client_window);
+    }
+}
+
+void red_channel_client_disconnect(RedChannelClient *rcc)
+{
+    red_printf("%p (channel %p)", rcc, rcc->channel);
+
+    if (rcc->send_data.item) {
+        rcc->channel->release_item(rcc, rcc->send_data.item, FALSE);
+    }
+    // TODO: clear our references from the pipe
+    reds_stream_free(rcc->stream);
+    rcc->send_data.item = NULL;
+    rcc->send_data.blocked = FALSE;
+    rcc->send_data.size = 0;
+    rcc->channel->rcc = NULL;
+}
+
+void red_channel_disconnect(RedChannel *channel)
+{
+    red_channel_pipe_clear(channel);
+    if (channel->rcc) {
+        red_channel_client_disconnect(channel->rcc);
+    }
+}
+
+int red_channel_all_clients_serials_are_zero(RedChannel *channel)
+{
+    return (!channel->rcc || channel->rcc->send_data.serial == 0);
+}
+
+void red_channel_apply_clients(RedChannel *channel, channel_client_visitor v)
+{
+    if (channel->rcc) {
+        v(channel->rcc);
+    }
+}
+
+void red_channel_apply_clients_data(RedChannel *channel, channel_client_visitor_data v, void *data)
+{
+    if (channel->rcc) {
+        v(channel->rcc, data);
+    }
+}
+
+void red_channel_set_shut(RedChannel *channel)
+{
+    if (channel->rcc) {
+        channel->rcc->incoming.shut = TRUE;
+    }
 }
 
 int red_channel_all_blocked(RedChannel *channel)
 {
-    return channel->send_data.blocked;
+    return !channel || !channel->rcc || channel->rcc->send_data.blocked;
 }
 
 int red_channel_any_blocked(RedChannel *channel)
 {
-    return channel->send_data.blocked;
+    return !channel || !channel->rcc || channel->rcc->send_data.blocked;
 }
 
-int red_channel_send_message_pending(RedChannel *channel)
+int red_channel_client_blocked(RedChannelClient *rcc)
 {
-    return channel->send_data.header->type != 0;
+    return rcc && rcc->send_data.blocked;
 }
 
-/* accessors for RedChannel */
-SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
+int red_channel_client_send_message_pending(RedChannelClient *rcc)
 {
-    return channel->send_data.marshaller;
+    return rcc->send_data.header->type != 0;
 }
 
-RedsStream *red_channel_get_stream(RedChannel *channel)
+/* accessors for RedChannelClient */
+SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc)
 {
-    return channel->stream;
+    return rcc->send_data.marshaller;
 }
 
-SpiceDataHeader *red_channel_get_header(RedChannel *channel)
+RedsStream *red_channel_client_get_stream(RedChannelClient *rcc)
 {
-    return channel->send_data.header;
+    return rcc->stream;
+}
+
+SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc)
+{
+    return rcc->send_data.header;
 }
 /* end of accessors */
 
 int red_channel_get_first_socket(RedChannel *channel)
 {
-    if (!channel->stream) {
+    if (!channel->rcc || !channel->rcc->stream) {
         return -1;
     }
-    return channel->stream->socket;
+    return channel->rcc->stream->socket;
+}
+
+int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item)
+{
+    return rcc->send_data.item == item;
 }
 
 int red_channel_item_being_sent(RedChannel *channel, PipeItem *item)
 {
-    return channel->send_data.item == item;
+    return channel->rcc && red_channel_client_item_being_sent(channel->rcc, item);
 }
 
 int red_channel_no_item_being_sent(RedChannel *channel)
 {
-    return channel->send_data.item == NULL;
+    return !channel->rcc || channel->rcc->send_data.item == NULL;
 }
 
-void red_channel_disconnect(RedChannel *channel)
+int red_channel_client_no_item_being_sent(RedChannelClient *rcc)
 {
-    red_channel_pipe_clear(channel);
-    reds_stream_free(channel->stream);
-    channel->stream = NULL;
-    channel->send_data.blocked = FALSE;
-    channel->send_data.size = 0;
+    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)
+{
+    red_channel_client_pipe_remove(rcc, item);
+    red_channel_client_release_item(rcc, item, FALSE);
 }
diff --git a/server/red_channel.h b/server/red_channel.h
index d05722c..e7a83d3 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -97,6 +97,9 @@ typedef struct BufDescriptor {
     uint8_t *data;
 } BufDescriptor;
 
+typedef struct RedChannel RedChannel;
+typedef struct RedChannelClient RedChannelClient;
+
 /* Messages handled by red_channel
  * SET_ACK - sent to client on channel connection
  * Note that the numbers don't have to correspond to spice message types,
@@ -112,37 +115,33 @@ typedef struct PipeItem {
     int type;
 } PipeItem;
 
-typedef struct RedChannel RedChannel;
-
-typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannel *channel,
+typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
                                                     SpiceDataHeader *msg_header);
-typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type,
+typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type,
                                         void *message);
-typedef int (*channel_handle_message_proc)(RedChannel *channel,
+typedef int (*channel_handle_message_proc)(RedChannelClient *rcc,
                                            SpiceDataHeader *header, uint8_t *msg);
-typedef void (*channel_release_msg_recv_buf_proc)(RedChannel *channel,
+typedef void (*channel_release_msg_recv_buf_proc)(RedChannelClient *channel,
                                                   SpiceDataHeader *msg_header, uint8_t *msg);
-typedef void (*channel_disconnect_proc)(RedChannel *channel);
-typedef int (*channel_configure_socket_proc)(RedChannel *channel);
-typedef void (*channel_send_pipe_item_proc)(RedChannel *channel, PipeItem *item);
-typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
-typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
+typedef void (*channel_disconnect_proc)(RedChannelClient *rcc);
+typedef int (*channel_configure_socket_proc)(RedChannelClient *rcc);
+typedef void (*channel_send_pipe_item_proc)(RedChannelClient *rcc, PipeItem *item);
+typedef void (*channel_hold_pipe_item_proc)(RedChannelClient *rcc, PipeItem *item);
+typedef void (*channel_release_pipe_item_proc)(RedChannelClient *rcc,
                                                PipeItem *item, int item_pushed);
-typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
-typedef void (*channel_on_outgoing_error_proc)(RedChannel *channel);
+typedef void (*channel_on_incoming_error_proc)(RedChannelClient *rcc);
+typedef void (*channel_on_outgoing_error_proc)(RedChannelClient *rcc);
 
-typedef int (*channel_handle_migrate_flush_mark_proc)(RedChannel *channel);
-typedef uint64_t (*channel_handle_migrate_data_proc)(RedChannel *channel,
+typedef int (*channel_handle_migrate_flush_mark_proc)(RedChannelClient *base);
+typedef uint64_t (*channel_handle_migrate_data_proc)(RedChannelClient *base,
                                                 uint32_t size, void *message);
-typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannel *channel,
+typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannelClient *base,
                                             uint32_t size, void *message);
 
-struct RedChannel {
+struct RedChannelClient {
+    RingItem channel_link;
+    RedChannel *channel;
     RedsStream *stream;
-    SpiceCoreInterface *core;
-    int migrate;
-    int handle_acks;
-
     struct {
         uint32_t generation;
         uint32_t client_generation;
@@ -150,9 +149,6 @@ struct RedChannel {
         uint32_t client_window;
     } ack_data;
 
-    Ring pipe;
-    uint32_t pipe_size;
-
     struct {
         SpiceMarshaller *marshaller;
         SpiceDataHeader *header;
@@ -164,16 +160,28 @@ struct RedChannel {
 
     OutgoingHandler outgoing;
     IncomingHandler incoming;
+    int during_send;
+};
+
+struct RedChannel {
+    SpiceCoreInterface *core;
+    int migrate;
+    int handle_acks;
+
+    RedChannelClient *rcc;
+
+    Ring pipe;
+    uint32_t pipe_size;
 
     OutgoingHandlerInterface outgoing_cb;
     IncomingHandlerInterface incoming_cb;
 
+    channel_configure_socket_proc config_socket;
     channel_disconnect_proc disconnect;
     channel_send_pipe_item_proc send_item;
     channel_hold_pipe_item_proc hold_item;
     channel_release_pipe_item_proc release_item;
 
-    int during_send;
     /* Stuff below added for Main and Inputs channels switch to RedChannel
      * (might be removed later) */
     channel_on_incoming_error_proc on_incoming_error; /* alternative to disconnect */
@@ -190,7 +198,7 @@ struct RedChannel {
 
 /* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
    explicitly destroy the channel */
-RedChannel *red_channel_create(int size, RedsStream *stream,
+RedChannel *red_channel_create(int size,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -207,7 +215,7 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
 
 /* alternative constructor, meant for marshaller based (inputs,main) channels,
  * will become default eventually */
-RedChannel *red_channel_create_parser(int size, RedsStream *stream,
+RedChannel *red_channel_create_parser(int size,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -223,29 +231,31 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
                                channel_handle_migrate_data_proc handle_migrate_data,
                                channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial);
-
+RedChannelClient *red_channel_client_create(int size, RedChannel *channel,
+                                            RedsStream *stream);
 int red_channel_is_connected(RedChannel *channel);
 
+void red_channel_client_destroy(RedChannelClient *rcc);
 void red_channel_destroy(RedChannel *channel);
 
 /* should be called when a new channel is ready to send messages */
 void red_channel_init_outgoing_messages_window(RedChannel *channel);
 
 /* handles general channel msgs from the client */
-int red_channel_handle_message(RedChannel *channel, uint32_t size,
+int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
                                uint16_t type, void *message);
 
 /* default error handler that disconnects channel */
-void red_channel_default_peer_on_error(RedChannel *channel);
+void red_channel_client_default_peer_on_error(RedChannelClient *rcc);
 
 /* when preparing send_data: should call init and then use marshaller */
-void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item);
+void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, PipeItem *item);
 
-uint64_t red_channel_get_message_serial(RedChannel *channel);
-void red_channel_set_message_serial(RedChannel *channel, uint64_t);
+uint64_t red_channel_client_get_message_serial(RedChannelClient *channel);
+void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t);
 
-/* when sending a msg. should first call red_channel_begin_send_message */
-void red_channel_begin_send_message(RedChannel *channel);
+/* when sending a msg. should first call red_channel_client_begin_send_message */
+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);
@@ -253,14 +263,19 @@ void red_channel_pipe_add(RedChannel *channel, PipeItem *item);
 void red_channel_pipe_add_after(RedChannel *channel, 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);
 /* 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_ack_zero_messages_window(RedChannelClient *rcc);
+void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
+void red_channel_client_push_set_ack(RedChannelClient *rcc);
 void red_channel_ack_zero_messages_window(RedChannel *channel);
 void red_channel_ack_set_client_window(RedChannel *channel, int client_window);
 void red_channel_push_set_ack(RedChannel *channel);
 
+/* TODO: This sets all clients to shut state - probably we want to close per channel */
 void red_channel_shutdown(RedChannel *channel);
 
 int red_channel_get_first_socket(RedChannel *channel);
@@ -271,8 +286,10 @@ int red_channel_all_blocked(RedChannel *channel);
 /* return TRUE if any of the connected clients to this channel are blocked */
 int red_channel_any_blocked(RedChannel *channel);
 
+int red_channel_client_blocked(RedChannelClient *rcc);
+
 /* helper for channels that have complex logic that can possibly ready a send */
-int red_channel_send_message_pending(RedChannel *channel);
+int red_channel_client_send_message_pending(RedChannelClient *rcc);
 
 /* returns TRUE if item is being sent by one of the channel clients. This will
  * be true if someone called init_send_data but send has not completed (or perhaps
@@ -281,6 +298,7 @@ int red_channel_send_message_pending(RedChannel *channel);
 int red_channel_item_being_sent(RedChannel *channel, PipeItem *item);
 
 int red_channel_no_item_being_sent(RedChannel *channel);
+int red_channel_client_no_item_being_sent(RedChannelClient *rcc);
 
 // 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
@@ -299,14 +317,18 @@ void red_channel_pipe_clear(RedChannel *channel);
 //  red_wait_pipe_item_sent
 //  handle_channel_events - this is the only one that was used before, and was in red_channel.c
 void red_channel_receive(RedChannel *channel);
+void red_channel_client_receive(RedChannelClient *rcc);
+// For red_worker
 void red_channel_send(RedChannel *channel);
+void red_channel_client_send(RedChannelClient *rcc);
 // For red_worker
 void red_channel_disconnect(RedChannel *channel);
+void red_channel_client_disconnect(RedChannelClient *rcc);
 
-/* accessors for RedChannel */
+/* accessors for RedChannelClient */
 /* Note: the valid times to call red_channel_get_marshaller are just during send_item callback. */
-SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel);
-RedsStream *red_channel_get_stream(RedChannel *channel);
+SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc);
+RedsStream *red_channel_client_get_stream(RedChannelClient *rcc);
 
 /* this is a convenience function for sending messages, sometimes (migration only?)
  * the serial from the header needs to be available for sending. Note that the header
@@ -314,5 +336,12 @@ RedsStream *red_channel_get_stream(RedChannel *channel);
  * red_channel_begin_send_message. red_channel_init_send_data changes the header (sets
  * the type in it) as a convenience function. It is preffered to do that through it and
  * not via the below accessor and direct header manipulation. */
-SpiceDataHeader *red_channel_get_header(RedChannel *channel);
+SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc);
+
+/* apply given function to all connected clients */
+typedef void (*channel_client_visitor)(RedChannelClient *rcc);
+typedef void (*channel_client_visitor_data)(RedChannelClient *rcc, void *data);
+void red_channel_apply_clients(RedChannel *channel, channel_client_visitor v);
+void red_channel_apply_clients_data(RedChannel *channel, channel_client_visitor_data v, void *data);
+
 #endif
diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index 74553c0..dddccc6 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -26,6 +26,7 @@
 #define FUNC_NAME(name) pixmap_cache_##name
 #define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
 #define CHANNEL DisplayChannel
+#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF(rcc->channel, CHANNEL, common.base);
 #define CACH_GENERATION pixmap_cache_generation
 #define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
 #else
@@ -35,12 +36,13 @@
 #endif
 
 
-static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, CHANNEL *channel)
+static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClient *rcc)
 {
+    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     NewCacheItem *item;
     uint64_t serial;
 
-    serial = red_channel_get_message_serial((RedChannel *)channel);
+    serial = red_channel_client_get_message_serial(rcc);
     pthread_mutex_lock(&cache->lock);
     item = cache->hash_table[CACHE_HASH_KEY(id)];
 
@@ -79,8 +81,9 @@ static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
     return !!item;
 }
 
-static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, CHANNEL *channel)
+static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, RedChannelClient *rcc)
 {
+    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     NewCacheItem *item;
     uint64_t serial;
     int key;
@@ -88,7 +91,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
     ASSERT(size > 0);
 
     item = spice_new(NewCacheItem, 1);
-    serial = red_channel_get_message_serial((RedChannel *)channel);
+    serial = red_channel_client_get_message_serial(rcc);
 
     pthread_mutex_lock(&cache->lock);
 
@@ -166,13 +169,14 @@ static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
     cache->items = 0;
 }
 
-static void FUNC_NAME(reset)(CACHE *cache, CHANNEL *channel, SpiceMsgWaitForChannels* sync_data)
+static void FUNC_NAME(reset)(CACHE *cache, RedChannelClient *rcc, SpiceMsgWaitForChannels* sync_data)
 {
+    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     uint8_t wait_count;
     uint64_t serial;
     uint32_t i;
 
-    serial = red_channel_get_message_serial((RedChannel *)channel);
+    serial = red_channel_client_get_message_serial(rcc);
     pthread_mutex_lock(&cache->lock);
     PRIVATE_FUNC_NAME(clear)(cache);
 
@@ -230,4 +234,5 @@ static void FUNC_NAME(destroy)(CACHE *cache)
 #undef FUNC_NAME
 #undef VAR_NAME
 #undef CHANNEL
+#undef CHANNEL_FROM_RCC
 
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 636f71e..f695777 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -1645,9 +1645,11 @@ static int tunnel_channel_handle_socket_token(TunnelChannel *channel, RedSocket
     return TRUE;
 }
 
-static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
+                                                 SpiceDataHeader *msg_header)
 {
-    TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
+    TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
+
     if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
         return (__tunnel_worker_alloc_socket_rcv_buf(tunnel_channel->worker)->buf);
     } else if ((msg_header->type == SPICE_MSGC_MIGRATE_DATA) ||
@@ -1659,10 +1661,11 @@ static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataH
 }
 
 // called by the receive routine of the channel, before the buffer was assigned to a socket
-static void tunnel_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
+static void tunnel_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
                                                uint8_t *msg)
 {
-    TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
+    TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
+
     if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
         ASSERT(!(SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf, buf)->base.usr_opaque));
         __tunnel_worker_free_socket_rcv_buf(tunnel_channel->worker,
@@ -1744,9 +1747,9 @@ static void __tunnel_channel_fill_socket_migrate_item(TunnelChannel *channel, Re
 }
 
 static void release_migrate_item(TunnelMigrateItem *item);
-static int tunnel_channel_handle_migrate_mark(RedChannel *base)
+static int tunnel_channel_handle_migrate_mark(RedChannelClient *rcc)
 {
-    TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
+    TunnelChannel *channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     TunnelMigrateItem *migrate_item = NULL;
     TunnelService *service;
     TunnelMigrateServiceItem *mig_service;
@@ -2159,7 +2162,7 @@ static inline void tunnel_channel_activate_migrated_sockets(TunnelChannel *chann
     }
 }
 
-static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannel *base,
+static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannelClient *rcc,
                                               uint32_t size, void *msg)
 {
     TunnelMigrateData *migrate_data = msg;
@@ -2172,10 +2175,10 @@ static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannel *base,
     return migrate_data->message_serial;
 }
 
-static uint64_t tunnel_channel_handle_migrate_data(RedChannel *base,
+static uint64_t tunnel_channel_handle_migrate_data(RedChannelClient *rcc,
                                               uint32_t size, void *msg)
 {
-    TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
+    TunnelChannel *channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     TunnelMigrateSocketList *sockets_list;
     TunnelMigrateServicesList *services_list;
     TunnelMigrateData *migrate_data = msg;
@@ -2242,9 +2245,9 @@ error:
 }
 
 //  msg was allocated by tunnel_channel_alloc_msg_rcv_buf
-static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *header, uint8_t *msg)
+static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
 {
-    TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
+    TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
     RedSocket *sckt = NULL;
     // retrieve the sckt
     switch (header->type) {
@@ -2268,7 +2271,7 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
         }
         break;
     default:
-        return red_channel_handle_message(channel, header->size, header->type, msg);
+        return red_channel_client_handle_message(rcc, header->size, header->type, msg);
     }
 
     switch (header->type) {
@@ -2337,7 +2340,7 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
         return tunnel_channel_handle_socket_token(tunnel_channel, sckt,
                                                   (SpiceMsgcTunnelSocketTokens *)msg);
     default:
-        return red_channel_handle_message(channel, header->size, header->type, msg);
+        return red_channel_client_handle_message(rcc, header->size, header->type, msg);
     }
     return TRUE;
 }
@@ -2346,13 +2349,16 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
 /* outgoing msgs
 ********************************/
 
-static void tunnel_channel_marshall_migrate(TunnelChannel *tunnel_channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_migrate(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
-    ASSERT(tunnel_channel);
+    TunnelChannel *tunnel_channel;
+
+    ASSERT(rcc);
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     tunnel_channel->send_data.u.migrate.flags =
         SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
     tunnel_channel->expect_migrate_mark = TRUE;
-    red_channel_init_send_data(&tunnel_channel->base, SPICE_MSG_MIGRATE, item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, item);
     spice_marshaller_add_ref(m,
         (uint8_t*)&tunnel_channel->send_data.u.migrate,
         sizeof(SpiceMsgMigrate));
@@ -2492,20 +2498,23 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
     return (cur_offset - offset);
 }
 
-static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
+static void tunnel_channel_marshall_migrate_data(RedChannelClient *rcc,
                                         SpiceMarshaller *m, PipeItem *item)
 {
-    TunnelMigrateData *migrate_data = &channel->send_data.u.migrate_data;
+    TunnelChannel *tunnel_channel;
+    TunnelMigrateData *migrate_data;
     TunnelMigrateItem *migrate_item = (TunnelMigrateItem *)item;
     int i;
 
     uint32_t data_buf_offset = 0; // current location in data[0] field
-    ASSERT(channel);
+    ASSERT(rcc);
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
+    migrate_data = &tunnel_channel->send_data.u.migrate_data;
 
     migrate_data->magic = TUNNEL_MIGRATE_DATA_MAGIC;
     migrate_data->version = TUNNEL_MIGRATE_DATA_VERSION;
-    migrate_data->message_serial = red_channel_get_message_serial(&channel->base);
-    red_channel_init_send_data(&channel->base, SPICE_MSG_MIGRATE_DATA, item);
+    migrate_data->message_serial = red_channel_client_get_message_serial(rcc);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
     spice_marshaller_add_ref(m, (uint8_t*)migrate_data, sizeof(*migrate_data));
 
     migrate_data->slirp_state = data_buf_offset;
@@ -2519,7 +2528,7 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
 
     for (i = 0; i < migrate_item->services_list->num_services; i++) {
         migrate_item->services_list->services[i] = data_buf_offset;
-        data_buf_offset += __tunnel_channel_marshall_service_migrate_data(channel, m,
+        data_buf_offset += __tunnel_channel_marshall_service_migrate_data(tunnel_channel, m,
                                                                       migrate_item->services + i,
                                                                       data_buf_offset);
     }
@@ -2532,83 +2541,93 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
 
     for (i = 0; i < migrate_item->sockets_list->num_sockets; i++) {
         migrate_item->sockets_list->sockets[i] = data_buf_offset;
-        data_buf_offset += __tunnel_channel_marshall_socket_migrate_data(channel, m,
+        data_buf_offset += __tunnel_channel_marshall_socket_migrate_data(tunnel_channel, m,
                                                                      migrate_item->sockets_data + i,
                                                                      data_buf_offset);
     }
 }
 
-static void tunnel_channel_marshall_init(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_init(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
-    ASSERT(channel);
+    TunnelChannel *channel;
 
+    ASSERT(rcc);
+    channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     channel->send_data.u.init.max_socket_data_size = MAX_SOCKET_DATA_SIZE;
     channel->send_data.u.init.max_num_of_sockets = MAX_SOCKETS_NUM;
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_INIT, item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_INIT, item);
     spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.init, sizeof(SpiceMsgTunnelInit));
 }
 
-static void tunnel_channel_marshall_service_ip_map(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_service_ip_map(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     TunnelService *service = SPICE_CONTAINEROF(item, TunnelService, pipe_item);
 
-    channel->send_data.u.service_ip.service_id = service->id;
-    channel->send_data.u.service_ip.virtual_ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
+    tunnel_channel->send_data.u.service_ip.service_id = service->id;
+    tunnel_channel->send_data.u.service_ip.virtual_ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SERVICE_IP_MAP, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.service_ip,
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SERVICE_IP_MAP, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.service_ip,
                         sizeof(SpiceMsgTunnelServiceIpMap));
     spice_marshaller_add_ref(m, (uint8_t*)&service->virt_ip.s_addr, sizeof(SpiceTunnelIPv4));
 }
 
-static void tunnel_channel_marshall_socket_open(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_open(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
 
-    channel->send_data.u.socket_open.connection_id = sckt->connection_id;
-    channel->send_data.u.socket_open.service_id = sckt->far_service->id;
-    channel->send_data.u.socket_open.tokens = SOCKET_WINDOW_SIZE;
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
+    tunnel_channel->send_data.u.socket_open.connection_id = sckt->connection_id;
+    tunnel_channel->send_data.u.socket_open.service_id = sckt->far_service->id;
+    tunnel_channel->send_data.u.socket_open.tokens = SOCKET_WINDOW_SIZE;
 
     sckt->in_data.client_total_num_tokens = SOCKET_WINDOW_SIZE;
     sckt->in_data.num_tokens = 0;
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_OPEN, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_open,
-                        sizeof(channel->send_data.u.socket_open));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_OPEN, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_open,
+                        sizeof(tunnel_channel->send_data.u.socket_open));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_marshall_socket_fin(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_fin(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
 
     ASSERT(!sckt->out_data.ready_chunks_queue.head);
 
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     if (sckt->out_data.process_queue->head) {
         red_printf("socket sent FIN but there are still buffers in outgoing process queue"
                    "(local_port=%d, service_id=%d)",
                    ntohs(sckt->local_port), sckt->far_service->id);
     }
 
-    channel->send_data.u.socket_fin.connection_id = sckt->connection_id;
+    tunnel_channel->send_data.u.socket_fin.connection_id = sckt->connection_id;
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_fin,
-                        sizeof(channel->send_data.u.socket_fin));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_fin,
+                        sizeof(tunnel_channel->send_data.u.socket_fin));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_close(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
 
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     // can happen when it is a forced close
     if (sckt->out_data.ready_chunks_queue.head) {
         red_printf("socket closed but there are still buffers in outgoing ready queue"
@@ -2623,65 +2642,71 @@ static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMa
                    ntohs(sckt->local_port), sckt->far_service->id);
     }
 
-    channel->send_data.u.socket_close.connection_id = sckt->connection_id;
+    tunnel_channel->send_data.u.socket_close.connection_id = sckt->connection_id;
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close,
-                        sizeof(channel->send_data.u.socket_close));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_close,
+                        sizeof(tunnel_channel->send_data.u.socket_close));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_marshall_socket_closed_ack(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_closed_ack(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
 
-    channel->send_data.u.socket_close_ack.connection_id = sckt->connection_id;
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
+    tunnel_channel->send_data.u.socket_close_ack.connection_id = sckt->connection_id;
 
     // pipe item is null because we free the sckt.
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close_ack,
-                        sizeof(channel->send_data.u.socket_close_ack));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_close_ack,
+                        sizeof(tunnel_channel->send_data.u.socket_close_ack));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 
     ASSERT(sckt->client_waits_close_ack && (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED));
-    tunnel_worker_free_socket(channel->worker, sckt);
-    if (CHECK_TUNNEL_ERROR(channel)) {
-        tunnel_shutdown(channel->worker);
+    tunnel_worker_free_socket(tunnel_channel->worker, sckt);
+    if (CHECK_TUNNEL_ERROR(tunnel_channel)) {
+        tunnel_shutdown(tunnel_channel->worker);
     }
 }
 
-static void tunnel_channel_marshall_socket_token(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_token(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, token_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
 
     /* notice that the num of tokens sent can be > SOCKET_TOKENS_TO_SEND, since
        the sending is performed after the pipe item was pushed */
 
-    channel->send_data.u.socket_token.connection_id = sckt->connection_id;
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
+    tunnel_channel->send_data.u.socket_token.connection_id = sckt->connection_id;
 
     if (sckt->in_data.num_tokens > 0) {
-        channel->send_data.u.socket_token.num_tokens = sckt->in_data.num_tokens;
+        tunnel_channel->send_data.u.socket_token.num_tokens = sckt->in_data.num_tokens;
     } else {
         ASSERT(!sckt->in_data.client_total_num_tokens && !sckt->in_data.ready_chunks_queue.head);
-        channel->send_data.u.socket_token.num_tokens = SOCKET_TOKENS_TO_SEND_FOR_PROCESS;
+        tunnel_channel->send_data.u.socket_token.num_tokens = SOCKET_TOKENS_TO_SEND_FOR_PROCESS;
     }
-    sckt->in_data.num_tokens -= channel->send_data.u.socket_token.num_tokens;
-    sckt->in_data.client_total_num_tokens += channel->send_data.u.socket_token.num_tokens;
+    sckt->in_data.num_tokens -= tunnel_channel->send_data.u.socket_token.num_tokens;
+    sckt->in_data.client_total_num_tokens += tunnel_channel->send_data.u.socket_token.num_tokens;
     ASSERT(sckt->in_data.client_total_num_tokens <= SOCKET_WINDOW_SIZE);
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_token,
-                        sizeof(channel->send_data.u.socket_token));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_token,
+                        sizeof(tunnel_channel->send_data.u.socket_token));
 }
 
-static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_socket_out_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
+    TunnelChannel *tunnel_channel;
+    tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, data_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
     ReadyTunneledChunk *chunk;
@@ -2701,11 +2726,11 @@ static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, Spic
     ASSERT(!sckt->out_data.push_tail);
     ASSERT(sckt->out_data.ready_chunks_queue.head->size <= MAX_SOCKET_DATA_SIZE);
 
-    channel->send_data.u.socket_data.connection_id = sckt->connection_id;
+    tunnel_channel->send_data.u.socket_data.connection_id = sckt->connection_id;
 
-    red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_DATA, item);
-    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_data,
-                        sizeof(channel->send_data.u.socket_data));
+    red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_DATA, item);
+    spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_data,
+                        sizeof(tunnel_channel->send_data.u.socket_data));
     pushed_bufs_num++;
 
     // the first chunk is in a valid size
@@ -2790,52 +2815,51 @@ static void tunnel_worker_release_socket_out_data(TunnelWorker *worker, PipeItem
     }
 }
 
-static void tunnel_channel_send_item(RedChannel *channel, PipeItem *item)
+static void tunnel_channel_send_item(RedChannelClient *rcc, PipeItem *item)
 {
-    TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
-    SpiceMarshaller *m = red_channel_get_marshaller(channel);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
     switch (item->type) {
     case PIPE_ITEM_TYPE_TUNNEL_INIT:
-        tunnel_channel_marshall_init(tunnel_channel, m, item);
+        tunnel_channel_marshall_init(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SERVICE_IP_MAP:
-        tunnel_channel_marshall_service_ip_map(tunnel_channel, m, item);
+        tunnel_channel_marshall_service_ip_map(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_OPEN:
-        tunnel_channel_marshall_socket_open(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_open(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_DATA:
-        tunnel_channel_marshall_socket_out_data(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_out_data(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_FIN:
-        tunnel_channel_marshall_socket_fin(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_fin(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_CLOSE:
-        tunnel_channel_marshall_socket_close(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_close(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK:
-        tunnel_channel_marshall_socket_closed_ack(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_closed_ack(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_TOKEN:
-        tunnel_channel_marshall_socket_token(tunnel_channel, m, item);
+        tunnel_channel_marshall_socket_token(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
-        tunnel_channel_marshall_migrate(tunnel_channel, m, item);
+        tunnel_channel_marshall_migrate(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        tunnel_channel_marshall_migrate_data(tunnel_channel, m, item);
+        tunnel_channel_marshall_migrate_data(rcc, m, item);
         break;
     default:
         red_error("invalid pipe item type");
     }
-    red_channel_begin_send_message(channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
 /* param item_pushed: distinguishes between a pipe item that was pushed for sending, and
    a pipe item that is still in the pipe and is released due to disconnection.
    see red_pipe_item_clear */
-static void tunnel_channel_release_pipe_item(RedChannel *channel, PipeItem *item, int item_pushed)
+static void tunnel_channel_release_pipe_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
     if (!item) { // e.g. when acking closed socket
         return;
@@ -2852,7 +2876,7 @@ static void tunnel_channel_release_pipe_item(RedChannel *channel, PipeItem *item
         break;
     case PIPE_ITEM_TYPE_SOCKET_DATA:
         if (item_pushed) {
-            tunnel_worker_release_socket_out_data(((TunnelChannel *)channel)->worker, item);
+            tunnel_worker_release_socket_out_data(((TunnelChannel *)rcc->channel)->worker, item);
         }
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
@@ -3321,11 +3345,11 @@ static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer,
 * channel interface and other related procedures
 ************************************************/
 
-static int tunnel_channel_config_socket(RedChannel *channel)
+static int tunnel_channel_config_socket(RedChannelClient *rcc)
 {
     int flags;
     int delay_val;
-    RedsStream *stream = red_channel_get_stream(channel);
+    RedsStream *stream = red_channel_client_get_stream(rcc);
 
     if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno)); // can't we just use red_error?
@@ -3386,6 +3410,12 @@ static void tunnel_channel_disconnect(RedChannel *channel)
     worker->channel = NULL;
 }
 
+// TODO - not MC friendly, remove
+static void tunnel_channel_disconnect_client(RedChannelClient *rcc)
+{
+    tunnel_channel_disconnect(rcc->channel);
+}
+
 /* interface for reds */
 
 static void on_new_tunnel_channel(TunnelChannel *channel)
@@ -3400,7 +3430,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
     }
 }
 
-static void tunnel_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void tunnel_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
 }
 
@@ -3415,10 +3445,10 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int
     }
 
     tunnel_channel =
-        (TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), stream, worker->core_interface,
+        (TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), worker->core_interface,
                                             migration, TRUE,
                                             tunnel_channel_config_socket,
-                                            tunnel_channel_disconnect,
+                                            tunnel_channel_disconnect_client,
                                             tunnel_channel_handle_message,
                                             tunnel_channel_alloc_msg_rcv_buf,
                                             tunnel_channel_release_msg_rcv_buf,
@@ -3432,7 +3462,7 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int
     if (!tunnel_channel) {
         return;
     }
-
+    red_channel_client_create(sizeof(RedChannelClient), &tunnel_channel->base, stream);
 
     tunnel_channel->worker = worker;
     tunnel_channel->worker->channel = tunnel_channel;
diff --git a/server/red_worker.c b/server/red_worker.c
index 7432ffb..b99927e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -927,7 +927,7 @@ static void red_display_release_stream(DisplayChannel *display, StreamAgent *age
 static inline void red_detach_stream(RedWorker *worker, Stream *stream);
 static void red_stop_stream(RedWorker *worker, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
-static inline void display_begin_send_message(DisplayChannel *channel, SpiceMarshaller *base_marshaller);
+static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller);
 static void red_release_pixmap_cache(DisplayChannel *channel);
 static void red_release_glz(DisplayChannel *channel);
 static void red_freeze_glz(DisplayChannel *channel);
@@ -1264,16 +1264,16 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
     }
 }
 
-static uint8_t *common_alloc_recv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
 {
-    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
+    CommonChannel *common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
 
     return common->recv_buf;
 }
 
-static void common_release_recv_buf(RedChannel *channel, SpiceDataHeader *msg_header, uint8_t* msg)
+static void common_release_recv_buf(RedChannelClient *rcc,
+                                    SpiceDataHeader *msg_header, uint8_t* msg)
 {
-    return;
 }
 
 #define CLIENT_PIXMAPS_CACHE
@@ -1689,7 +1689,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
             item = (PipeItem *)ring_prev(ring, (RingItem *)item);
             ring_remove(&tmp_item->link);
             worker->display_channel->common.base.release_item(
-                &worker->display_channel->common.base, tmp_item, FALSE);
+                worker->display_channel->common.base.rcc, tmp_item, FALSE);
             worker->display_channel->common.base.pipe_size--;
 
             if (!item) {
@@ -5687,16 +5687,18 @@ static inline int red_compress_image(DisplayChannel *display_channel,
     }
 }
 
-static inline void red_display_add_image_to_pixmap_cache(DisplayChannel *display_channel,
+static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
                                                          SpiceImage *image, SpiceImage *io_image,
                                                          int is_lossy)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+
     if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
         ASSERT(image->descriptor.width * image->descriptor.height > 0);
         if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) {
             if (pixmap_cache_add(display_channel->pixmap_cache, image->descriptor.id,
                                  image->descriptor.width * image->descriptor.height, is_lossy,
-                                 display_channel)) {
+                                 rcc)) {
                 io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
                 stat_inc_counter(display_channel->add_to_cache_counter, 1);
             }
@@ -5719,9 +5721,10 @@ typedef enum {
 
 /* if the number of times fill_bits can be called per one qxl_drawable increases -
    MAX_LZ_DRAWABLE_INSTANCES must be increased as well */
-static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *m,
+static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
                               SpiceImage *simage, Drawable *drawable, int can_lossy)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedWorker *worker = display_channel->common.worker;
     SpiceImage image;
     compress_send_data_t comp_send_data = {0};
@@ -5737,7 +5740,7 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
     if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
         int lossy_cache_item;
         if (pixmap_cache_hit(display_channel->pixmap_cache, image.descriptor.id,
-                             &lossy_cache_item, display_channel)) {
+                             &lossy_cache_item, rcc)) {
             if (can_lossy || !lossy_cache_item) {
                 if (!display_channel->enable_jpeg || lossy_cache_item) {
                     image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
@@ -5794,7 +5797,7 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
                                 drawable, can_lossy, &comp_send_data)) {
             SpicePalette *palette;
 
-            red_display_add_image_to_pixmap_cache(display_channel, simage, &image, FALSE);
+            red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE);
 
             *bitmap = simage->u.bitmap;
             bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
@@ -5812,7 +5815,7 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
             spice_marshaller_add_ref_chunks(m, bitmap->data);
             return FILL_BITS_TYPE_BITMAP;
         } else {
-            red_display_add_image_to_pixmap_cache(display_channel, simage, &image,
+            red_display_add_image_to_pixmap_cache(rcc, simage, &image,
                                                   comp_send_data.is_lossy);
 
             spice_marshall_Image(m, &image,
@@ -5833,7 +5836,7 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
         break;
     }
     case SPICE_IMAGE_TYPE_QUIC:
-        red_display_add_image_to_pixmap_cache(display_channel, simage, &image, FALSE);
+        red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE);
         image.u.quic = simage->u.quic;
         spice_marshall_Image(m, &image,
                              &bitmap_palette_out, &lzplt_palette_out);
@@ -5846,23 +5849,25 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
     }
 }
 
-static void fill_mask(DisplayChannel *display_channel, SpiceMarshaller *m,
+static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m,
                       SpiceImage *mask_bitmap, Drawable *drawable)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+
     if (mask_bitmap && m) {
         if (display_channel->common.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
             spice_image_compression_t save_img_comp =
                 display_channel->common.worker->image_compression;
             display_channel->common.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
-            fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
+            fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
             display_channel->common.worker->image_compression = save_img_comp;
         } else {
-            fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
+            fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
         }
     }
 }
 
-static void fill_attr(DisplayChannel *display_channel, SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id)
+static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id)
 {
     int i;
 
@@ -5963,9 +5968,11 @@ static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surfa
    to the client, returns false. "area" is for surfaces. If area = NULL,
    all the surface is considered. out_lossy_data will hold info about the bitmap, and its lossy
    area in case it is lossy and part of a surface. */
-static int is_bitmap_lossy(DisplayChannel *display_channel, SpiceImage *image, SpiceRect *area,
+static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *area,
                            Drawable *drawable, BitmapData *out_data)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+
     if (image == NULL) {
         // self bitmap
         out_data->type = BITMAP_DATA_TYPE_BITMAP;
@@ -5977,7 +5984,7 @@ static int is_bitmap_lossy(DisplayChannel *display_channel, SpiceImage *image, S
 
         out_data->id = image->descriptor.id;
         if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
-                             &is_hit_lossy, display_channel)) {
+                             &is_hit_lossy, rcc)) {
             out_data->type = BITMAP_DATA_TYPE_CACHE;
             if (is_hit_lossy) {
                 return TRUE;
@@ -6007,11 +6014,11 @@ static int is_bitmap_lossy(DisplayChannel *display_channel, SpiceImage *image, S
     }
 }
 
-static int is_brush_lossy(DisplayChannel *display_channel, SpiceBrush *brush,
+static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush,
                           Drawable *drawable, BitmapData *out_data)
 {
     if (brush->type == SPICE_BRUSH_TYPE_PATTERN) {
-        return is_bitmap_lossy(display_channel, brush->u.pattern.pat, NULL,
+        return is_bitmap_lossy(rcc, brush->u.pattern.pat, NULL,
                                drawable, out_data);
     } else {
         out_data->type = BITMAP_DATA_TYPE_INVALID;
@@ -6286,17 +6293,16 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
 }
 
 static void red_marshall_qxl_draw_fill(RedWorker *worker,
-                                   DisplayChannel *display_channel,
+                                   RedChannelClient *rcc,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceFill fill;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_FILL, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL, &item->pipe_item);
     fill_base(base_marshaller, item);
     fill = drawable->u.fill;
     spice_marshall_Fill(base_marshaller,
@@ -6305,18 +6311,19 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
                         &mask_bitmap_out);
 
     if (brush_pat_out) {
-        fill_bits(display_channel, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
     }
 
-    fill_mask(display_channel, mask_bitmap_out, fill.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, fill.mask.bitmap, item);
 }
 
 
-static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
-                                         DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
+                                         RedChannelClient *rcc,
                                          SpiceMarshaller *m,
                                          Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
 
     int dest_allowed_lossy = FALSE;
@@ -6332,7 +6339,7 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
                            (rop & SPICE_ROPD_OP_AND) ||
                            (rop & SPICE_ROPD_OP_XOR));
 
-    brush_is_lossy = is_brush_lossy(display_channel, &drawable->u.fill.brush, item,
+    brush_is_lossy = is_brush_lossy(rcc, &drawable->u.fill.brush, item,
                                     &brush_bitmap_data);
     if (!dest_allowed_lossy) {
         dest_is_lossy = is_surface_area_lossy(display_channel, item->surface_id, &drawable->bbox,
@@ -6343,8 +6350,7 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
         !(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) {
         int has_mask = !!drawable->u.fill.mask.bitmap;
 
-        red_marshall_qxl_draw_fill(worker, display_channel, m, item);
-
+        red_marshall_qxl_draw_fill(worker, rcc, m, item);
         // either the brush operation is opaque, or the dest is not lossy
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
@@ -6370,11 +6376,10 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
 }
 
 static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
-                                             DisplayChannel *display_channel,
+                                             RedChannelClient *rcc,
                                              SpiceMarshaller *base_marshaller,
                                              Drawable *item, int src_allowed_lossy)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *src_bitmap_out;
@@ -6382,7 +6387,7 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
     SpiceOpaque opaque;
     FillBitsType src_send_type;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &item->pipe_item);
     fill_base(base_marshaller, item);
     opaque = drawable->u.opaque;
     spice_marshall_Opaque(base_marshaller,
@@ -6391,22 +6396,23 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
                           &brush_pat_out,
                           &mask_bitmap_out);
 
-    src_send_type = fill_bits(display_channel, src_bitmap_out, opaque.src_bitmap, item,
+    src_send_type = fill_bits(rcc, src_bitmap_out, opaque.src_bitmap, item,
                               src_allowed_lossy);
 
     if (brush_pat_out) {
-        fill_bits(display_channel, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
     }
-    fill_mask(display_channel, mask_bitmap_out, opaque.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, opaque.mask.bitmap, item);
 
     return src_send_type;
 }
 
-static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
-                                           DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
+                                           RedChannelClient *rcc,
                                            SpiceMarshaller *m,
                                            Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
 
     int src_allowed_lossy;
@@ -6421,11 +6427,11 @@ static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
                           (rop & SPICE_ROPD_OP_AND) ||
                           (rop & SPICE_ROPD_OP_XOR));
 
-    brush_is_lossy = is_brush_lossy(display_channel, &drawable->u.opaque.brush, item,
+    brush_is_lossy = is_brush_lossy(rcc, &drawable->u.opaque.brush, item,
                                     &brush_bitmap_data);
 
     if (!src_allowed_lossy) {
-        src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.opaque.src_bitmap,
+        src_is_lossy = is_bitmap_lossy(rcc, drawable->u.opaque.src_bitmap,
                                        &drawable->u.opaque.src_area,
                                        item,
                                        &src_bitmap_data);
@@ -6436,8 +6442,7 @@ static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
         FillBitsType src_send_type;
         int has_mask = !!drawable->u.opaque.mask.bitmap;
 
-        src_send_type = red_marshall_qxl_draw_opaque(worker, display_channel, m, item, src_allowed_lossy);
-
+        src_send_type = red_marshall_qxl_draw_opaque(worker, rcc, m, item, src_allowed_lossy);
         if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
             src_is_lossy = TRUE;
         } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) {
@@ -6468,18 +6473,17 @@ static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
 }
 
 static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
-                                           DisplayChannel *display_channel,
+                                           RedChannelClient *rcc,
                                            SpiceMarshaller *base_marshaller,
                                            Drawable *item, int src_allowed_lossy)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceCopy copy;
     FillBitsType src_send_type;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->pipe_item);
     fill_base(base_marshaller, item);
     copy = drawable->u.copy;
     spice_marshall_Copy(base_marshaller,
@@ -6487,27 +6491,28 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
                         &src_bitmap_out,
                         &mask_bitmap_out);
 
-    src_send_type = fill_bits(display_channel, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
-    fill_mask(display_channel, mask_bitmap_out, copy.mask.bitmap, item);
+    src_send_type = fill_bits(rcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
+    fill_mask(rcc, mask_bitmap_out, copy.mask.bitmap, item);
 
     return src_send_type;
 }
 
-static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
-                                         DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
+                                         RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.copy.mask.bitmap;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     FillBitsType src_send_type;
 
-    src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.copy.src_bitmap,
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.copy.src_bitmap,
                                    &drawable->u.copy.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_marshall_qxl_draw_copy(worker, display_channel, base_marshaller, item, TRUE);
+    src_send_type = red_marshall_qxl_draw_copy(worker, rcc, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6520,39 +6525,38 @@ static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
 }
 
 static void red_marshall_qxl_draw_transparent(RedWorker *worker,
-                                          DisplayChannel *display_channel,
+                                          RedChannelClient *rcc,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceTransparent transparent;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &item->pipe_item);
     fill_base(base_marshaller, item);
     transparent = drawable->u.transparent;
     spice_marshall_Transparent(base_marshaller,
                                &transparent,
                                &src_bitmap_out);
-    fill_bits(display_channel, src_bitmap_out, transparent.src_bitmap, item, FALSE);
+    fill_bits(rcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
 }
 
-static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
-                                                DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
+                                                RedChannelClient *rcc,
                                                 SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
 
-    src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.transparent.src_bitmap,
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.transparent.src_bitmap,
                                    &drawable->u.transparent.src_area, item, &src_bitmap_data);
 
     if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
-        red_marshall_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
-
+        red_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, item);
         // don't update surface lossy region since transperent areas might be lossy
     } else {
         int resend_surface_ids[1];
@@ -6567,42 +6571,42 @@ static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
 }
 
 static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
-                                                  DisplayChannel *display_channel,
+                                                  RedChannelClient *rcc,
                                                   SpiceMarshaller *base_marshaller,
                                                   Drawable *item,
                                                   int src_allowed_lossy)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceAlphaBlend alpha_blend;
     FillBitsType src_send_type;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &item->pipe_item);
     fill_base(base_marshaller, item);
     alpha_blend = drawable->u.alpha_blend;
     spice_marshall_AlphaBlend(base_marshaller,
                               &alpha_blend,
                               &src_bitmap_out);
-    src_send_type = fill_bits(display_channel, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
+    src_send_type = fill_bits(rcc, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
 
     return src_send_type;
 }
 
-static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
-                                                DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
+                                                RedChannelClient *rcc,
                                                 SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     FillBitsType src_send_type;
 
-    src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.alpha_blend.src_bitmap,
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.alpha_blend.src_bitmap,
                                    &drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_marshall_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item, TRUE);
+    src_send_type = red_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6616,26 +6620,26 @@ static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
 }
 
 static void red_marshall_qxl_copy_bits(RedWorker *worker,
-                                   DisplayChannel *display_channel,
+                                   RedChannelClient *rcc,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpicePoint copy_bits;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_COPY_BITS, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_COPY_BITS, &item->pipe_item);
     fill_base(base_marshaller, item);
     copy_bits = drawable->u.copy_bits.src_pos;
     spice_marshall_Point(base_marshaller,
                          &copy_bits);
 }
 
-static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
-                                         DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
+                                         RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     SpiceRect src_rect;
     int horz_offset;
@@ -6643,7 +6647,7 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
     int src_is_lossy;
     SpiceRect src_lossy_area;
 
-    red_marshall_qxl_copy_bits(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_copy_bits(worker, rcc, base_marshaller, item);
 
     horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left;
     vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top;
@@ -6661,17 +6665,16 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
 }
 
 static void red_marshall_qxl_draw_blend(RedWorker *worker,
-                                    DisplayChannel *display_channel,
+                                    RedChannelClient *rcc,
                                     SpiceMarshaller *base_marshaller,
                                     Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlend blend;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLEND, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLEND, &item->pipe_item);
     fill_base(base_marshaller, item);
     blend = drawable->u.blend;
     spice_marshall_Blend(base_marshaller,
@@ -6679,30 +6682,31 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
                          &src_bitmap_out,
                          &mask_bitmap_out);
 
-    fill_bits(display_channel, src_bitmap_out, blend.src_bitmap, item, FALSE);
+    fill_bits(rcc, src_bitmap_out, blend.src_bitmap, item, FALSE);
 
-    fill_mask(display_channel, mask_bitmap_out, blend.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item);
 }
 
-static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
-                                          DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
+                                          RedChannelClient *rcc,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int dest_is_lossy;
     SpiceRect dest_lossy_area;
 
-    src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.blend.src_bitmap,
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.blend.src_bitmap,
                                    &drawable->u.blend.src_area, item, &src_bitmap_data);
     dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
                                           &drawable->bbox, &dest_lossy_area);
 
     if (!dest_is_lossy &&
         (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_marshall_qxl_draw_blend(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_blend(worker, rcc, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6726,16 +6730,15 @@ static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
 }
 
 static void red_marshall_qxl_draw_blackness(RedWorker *worker,
-                                        DisplayChannel *display_channel,
+                                        RedChannelClient *rcc,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlackness blackness;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &item->pipe_item);
     fill_base(base_marshaller, item);
     blackness = drawable->u.blackness;
 
@@ -6743,33 +6746,33 @@ static void red_marshall_qxl_draw_blackness(RedWorker *worker,
                              &blackness,
                              &mask_bitmap_out);
 
-    fill_mask(display_channel, mask_bitmap_out, blackness.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, blackness.mask.bitmap, item);
 }
 
-static void red_lossy_send_qxl_draw_blackness(RedWorker *worker,
-                                              DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
+                                              RedChannelClient *rcc,
                                               SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
-    red_marshall_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
 static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
-                                        DisplayChannel *display_channel,
+                                        RedChannelClient *rcc,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
-    RedChannel *channel = &display_channel->common.base;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *mask_bitmap_out;
     SpiceWhiteness whiteness;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &item->pipe_item);
     fill_base(base_marshaller, item);
     whiteness = drawable->u.whiteness;
 
@@ -6777,33 +6780,33 @@ static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
                              &whiteness,
                              &mask_bitmap_out);
 
-    fill_mask(display_channel, mask_bitmap_out, whiteness.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, whiteness.mask.bitmap, item);
 }
 
-static void red_lossy_send_qxl_draw_whiteness(RedWorker *worker,
-                                              DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_whiteness(RedWorker *worker,
+                                              RedChannelClient *rcc,
                                               SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
-    red_marshall_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
 static void red_marshall_qxl_draw_inverse(RedWorker *worker,
-                                        DisplayChannel *display_channel,
+                                        RedChannelClient *rcc,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *mask_bitmap_out;
-    RedChannel *channel = &display_channel->common.base;
     SpiceInvers inverse;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL);
     fill_base(base_marshaller, item);
     inverse = drawable->u.invers;
 
@@ -6811,30 +6814,29 @@ static void red_marshall_qxl_draw_inverse(RedWorker *worker,
                           &inverse,
                           &mask_bitmap_out);
 
-    fill_mask(display_channel, mask_bitmap_out, inverse.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, inverse.mask.bitmap, item);
 }
 
-static void red_lossy_send_qxl_draw_inverse(RedWorker *worker,
-                                            DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_inverse(RedWorker *worker,
+                                            RedChannelClient *rcc,
                                             SpiceMarshaller *base_marshaller,
                                             Drawable *item)
 {
-    red_marshall_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_inverse(worker, rcc, base_marshaller, item);
 }
 
 static void red_marshall_qxl_draw_rop3(RedWorker *worker,
-                                   DisplayChannel *display_channel,
+                                   RedChannelClient *rcc,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
-    RedChannel *channel = &display_channel->common.base;
     SpiceRop3 rop3;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *mask_bitmap_out;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ROP3, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ROP3, &item->pipe_item);
     fill_base(base_marshaller, item);
     rop3 = drawable->u.rop3;
     spice_marshall_Rop3(base_marshaller,
@@ -6843,19 +6845,20 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
                         &brush_pat_out,
                         &mask_bitmap_out);
 
-    fill_bits(display_channel, src_bitmap_out, rop3.src_bitmap, item, FALSE);
+    fill_bits(rcc, src_bitmap_out, rop3.src_bitmap, item, FALSE);
 
     if (brush_pat_out) {
-        fill_bits(display_channel, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
     }
-    fill_mask(display_channel, mask_bitmap_out, rop3.mask.bitmap, item);
+    fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item);
 }
 
-static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
-                                         DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
+                                         RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -6864,9 +6867,9 @@ static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
     int dest_is_lossy;
     SpiceRect dest_lossy_area;
 
-    src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.rop3.src_bitmap,
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.rop3.src_bitmap,
                                    &drawable->u.rop3.src_area, item, &src_bitmap_data);
-    brush_is_lossy = is_brush_lossy(display_channel, &drawable->u.rop3.brush, item,
+    brush_is_lossy = is_brush_lossy(rcc, &drawable->u.rop3.brush, item,
                                     &brush_bitmap_data);
     dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
                                           &drawable->bbox, &dest_lossy_area);
@@ -6875,8 +6878,7 @@ static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         !dest_is_lossy) {
         int has_mask = !!drawable->u.rop3.mask.bitmap;
-        red_marshall_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
-
+        red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[3];
@@ -6907,17 +6909,16 @@ static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
 }
 
 static void red_marshall_qxl_draw_stroke(RedWorker *worker,
-                                     DisplayChannel *display_channel,
+                                     RedChannelClient *rcc,
                                      SpiceMarshaller *base_marshaller,
                                      Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
-    RedChannel *channel = &display_channel->common.base;
     SpiceStroke stroke;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *style_out;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_STROKE, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_STROKE, &item->pipe_item);
     fill_base(base_marshaller, item);
     stroke = drawable->u.stroke;
     spice_marshall_Stroke(base_marshaller,
@@ -6925,17 +6926,18 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
                           &style_out,
                           &brush_pat_out);
 
-    fill_attr(display_channel, style_out, &stroke.attr, item->group_id);
+    fill_attr(style_out, &stroke.attr, item->group_id);
     if (brush_pat_out) {
-        fill_bits(display_channel, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
     }
 }
 
-static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
-                                           DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
+                                           RedChannelClient *rcc,
                                            SpiceMarshaller *base_marshaller,
                                            Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int brush_is_lossy;
     BitmapData brush_bitmap_data;
@@ -6943,7 +6945,7 @@ static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
     SpiceRect dest_lossy_area;
     int rop;
 
-    brush_is_lossy = is_brush_lossy(display_channel, &drawable->u.stroke.brush, item,
+    brush_is_lossy = is_brush_lossy(rcc, &drawable->u.stroke.brush, item,
                                     &brush_bitmap_data);
 
     // back_mode is not used at the client. Ignoring.
@@ -6961,7 +6963,7 @@ static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
     if (!dest_is_lossy &&
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)))
     {
-        red_marshall_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6983,21 +6985,19 @@ static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
         red_add_lossless_drawable_dependencies(worker, display_channel, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
-
 }
 
 static void red_marshall_qxl_draw_text(RedWorker *worker,
-                                   DisplayChannel *display_channel,
+                                   RedChannelClient *rcc,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
-    RedChannel *channel = &display_channel->common.base;
     SpiceText text;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *back_brush_pat_out;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TEXT, &item->pipe_item);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TEXT, &item->pipe_item);
     fill_base(base_marshaller, item);
     text = drawable->u.text;
     spice_marshall_Text(base_marshaller,
@@ -7006,18 +7006,19 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
                         &back_brush_pat_out);
 
     if (brush_pat_out) {
-        fill_bits(display_channel, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
     }
     if (back_brush_pat_out) {
-        fill_bits(display_channel, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
+        fill_bits(rcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
     }
 }
 
-static void red_lossy_send_qxl_draw_text(RedWorker *worker,
-                                         DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
+                                         RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int fg_is_lossy;
     BitmapData fg_bitmap_data;
@@ -7027,9 +7028,9 @@ static void red_lossy_send_qxl_draw_text(RedWorker *worker,
     SpiceRect dest_lossy_area;
     int rop = 0;
 
-    fg_is_lossy = is_brush_lossy(display_channel, &drawable->u.text.fore_brush, item,
+    fg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.fore_brush, item,
                                  &fg_bitmap_data);
-    bg_is_lossy = is_brush_lossy(display_channel, &drawable->u.text.back_brush, item,
+    bg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.back_brush, item,
                                  &bg_bitmap_data);
 
     // assuming that if the brush type is solid, the destination can
@@ -7051,7 +7052,7 @@ static void red_lossy_send_qxl_draw_text(RedWorker *worker,
     if (!dest_is_lossy &&
         (!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         (!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_marshall_qxl_draw_text(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_text(worker, rcc, base_marshaller, item);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -7079,98 +7080,98 @@ static void red_lossy_send_qxl_draw_text(RedWorker *worker,
     }
 }
 
-static void red_lossy_marshall_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
                                         SpiceMarshaller *base_marshaller, Drawable *item)
 {
     switch (item->red_drawable->type) {
     case QXL_DRAW_FILL:
-        red_lossy_send_qxl_draw_fill(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_fill(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_OPAQUE:
-        red_lossy_send_qxl_draw_opaque(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_opaque(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_COPY:
-        red_lossy_send_qxl_draw_copy(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_copy(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_lossy_send_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_lossy_send_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, item);
         break;
     case QXL_COPY_BITS:
-        red_lossy_send_qxl_copy_bits(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_copy_bits(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_BLEND:
-        red_lossy_send_qxl_draw_blend(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_blend(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_lossy_send_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
         break;
      case QXL_DRAW_WHITENESS:
-        red_lossy_send_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_INVERS:
-        red_lossy_send_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_inverse(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_ROP3:
-        red_lossy_send_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_STROKE:
-        red_lossy_send_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, item);
         break;
     case QXL_DRAW_TEXT:
-        red_lossy_send_qxl_draw_text(worker, display_channel, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_text(worker, rcc, base_marshaller, item);
         break;
     default:
         red_error("invalid type");
     }
 }
 
-static inline void red_marshall_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
-                                         SpiceMarshaller *m, Drawable *item)
+static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
+                                SpiceMarshaller *m, Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
 
     switch (drawable->type) {
     case QXL_DRAW_FILL:
-        red_marshall_qxl_draw_fill(worker, display_channel, m, item);
+        red_marshall_qxl_draw_fill(worker, rcc, m, item);
         break;
     case QXL_DRAW_OPAQUE:
-        red_marshall_qxl_draw_opaque(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_opaque(worker, rcc, m, item, FALSE);
         break;
     case QXL_DRAW_COPY:
-        red_marshall_qxl_draw_copy(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_copy(worker, rcc, m, item, FALSE);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_marshall_qxl_draw_transparent(worker, display_channel, m, item);
+        red_marshall_qxl_draw_transparent(worker, rcc, m, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_marshall_qxl_draw_alpha_blend(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_alpha_blend(worker, rcc, m, item, FALSE);
         break;
     case QXL_COPY_BITS:
-        red_marshall_qxl_copy_bits(worker, display_channel, m, item);
+        red_marshall_qxl_copy_bits(worker, rcc, m, item);
         break;
     case QXL_DRAW_BLEND:
-        red_marshall_qxl_draw_blend(worker, display_channel, m, item);
+        red_marshall_qxl_draw_blend(worker, rcc, m, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_marshall_qxl_draw_blackness(worker, display_channel, m, item);
+        red_marshall_qxl_draw_blackness(worker, rcc, m, item);
         break;
     case QXL_DRAW_WHITENESS:
-        red_marshall_qxl_draw_whiteness(worker, display_channel, m, item);
+        red_marshall_qxl_draw_whiteness(worker, rcc, m, item);
         break;
     case QXL_DRAW_INVERS:
-        red_marshall_qxl_draw_inverse(worker, display_channel, m, item);
+        red_marshall_qxl_draw_inverse(worker, rcc, m, item);
         break;
     case QXL_DRAW_ROP3:
-        red_marshall_qxl_draw_rop3(worker, display_channel, m, item);
+        red_marshall_qxl_draw_rop3(worker, rcc, m, item);
         break;
     case QXL_DRAW_STROKE:
-        red_marshall_qxl_draw_stroke(worker, display_channel, m, item);
+        red_marshall_qxl_draw_stroke(worker, rcc, m, item);
         break;
     case QXL_DRAW_TEXT:
-        red_marshall_qxl_draw_text(worker, display_channel, m, item);
+        red_marshall_qxl_draw_text(worker, rcc, m, item);
         break;
     default:
         red_error("invalid type");
@@ -7201,10 +7202,11 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
     free_list->res->resources[free_list->res->count++].id = id;
 }
 
-static inline void display_begin_send_message(DisplayChannel *channel, SpiceMarshaller *base_marshaller)
+static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
-    FreeList *free_list = &channel->send_data.free_list;
-    SpiceDataHeader *header = red_channel_get_header(&channel->common.base);
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    FreeList *free_list = &display_channel->send_data.free_list;
+    SpiceDataHeader *header = red_channel_client_get_header(rcc);
 
     if (free_list->res->count) {
         int sub_list_len = 1;
@@ -7222,7 +7224,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, SpiceMars
         spice_marshall_msg_display_inval_list(inval_m, free_list->res);
 
         for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
-            if (i != channel->common.id && free_list->sync[i] != 0) {
+            if (i != display_channel->common.id && free_list->sync[i] != 0) {
                 free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
                 free_list->wait.header.wait_list[sync_count].channel_id = i;
                 free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i];
@@ -7249,7 +7251,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, SpiceMars
         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
         header->sub_list = spice_marshaller_get_offset(sub_list_m);
     }
-    red_channel_begin_send_message((RedChannel *)channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
 static inline RedChannel *red_ref_channel(RedChannel *channel)
@@ -7450,12 +7452,12 @@ static int red_rgb16bpp_to_24 (RedWorker *worker, const SpiceRect *src,
     return TRUE;
 }
 
-static inline int red_send_stream_data(DisplayChannel *display_channel,
+static inline int red_marshall_stream_data(RedChannelClient *rcc,
                   SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     Stream *stream = drawable->stream;
     SpiceImage *image;
-    RedChannel *channel;
     RedWorker* worker;
     uint8_t *frame;
     size_t frame_stride;
@@ -7464,7 +7466,6 @@ static inline int red_send_stream_data(DisplayChannel *display_channel,
     ASSERT(stream);
     ASSERT(drawable->red_drawable->type == QXL_DRAW_COPY);
 
-    channel = &display_channel->common.base;
     worker = display_channel->common.worker;
     image = drawable->red_drawable->u.copy.src_bitmap;
 
@@ -7525,7 +7526,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel,
         red_display_share_stream_buf(display_channel);
     }
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
 
     SpiceMsgDisplayStreamData stream_data;
 
@@ -7539,72 +7540,63 @@ static inline int red_send_stream_data(DisplayChannel *display_channel,
     return TRUE;
 }
 
-static inline void marshall_qxl_drawable(DisplayChannel *display_channel,
+static inline void marshall_qxl_drawable(RedChannelClient *rcc,
     SpiceMarshaller *m, Drawable *item)
 {
-    ASSERT(display_channel);
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
-    if (item->stream && red_send_stream_data(display_channel, m, item)) {
+    ASSERT(display_channel && rcc);
+    if (item->stream && red_marshall_stream_data(rcc, m, item)) {
         return;
     }
     if (!display_channel->enable_jpeg)
-        red_marshall_qxl_drawable(display_channel->common.worker, display_channel, m, item);
+        red_marshall_qxl_drawable(display_channel->common.worker, rcc, m, item);
     else
-        red_lossy_marshall_qxl_drawable(display_channel->common.worker, display_channel, m, item);
+        red_lossy_marshall_qxl_drawable(display_channel->common.worker, rcc, m, item);
 }
 
-static inline void red_marshall_verb(RedChannel *channel, uint16_t verb)
+static inline void red_marshall_verb(RedChannelClient *rcc, uint16_t verb)
 {
-    ASSERT(channel);
-    red_channel_init_send_data(channel, verb, NULL);
+    ASSERT(rcc);
+    red_channel_client_init_send_data(rcc, verb, NULL);
 }
 
-static inline void display_marshall_verb(DisplayChannel *channel, uint16_t verb)
-{
-    ASSERT(channel);
-    red_channel_init_send_data(&channel->common.base, verb, NULL);
-}
-
-static inline void red_marshall_inval(RedChannel *channel,
+static inline void red_marshall_inval(RedChannelClient *rcc,
         SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
     SpiceMsgDisplayInvalOne inval_one;
 
-    red_channel_init_send_data(channel, cach_item->inval_type, NULL);
+    red_channel_client_init_send_data(rcc, cach_item->inval_type, NULL);
     inval_one.id = *(uint64_t *)&cach_item->id;
 
     spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
-static void red_display_marshall_inval(DisplayChannel *display_channel,
-                SpiceMarshaller *base_marshaller, CacheItem *cach_item)
-{
-    red_marshall_inval((RedChannel *)display_channel, base_marshaller, cach_item);
-}
-
-static void display_channel_marshall_migrate(DisplayChannel *display_channel, SpiceMarshaller *base_marshaller)
+static void display_channel_marshall_migrate(RedChannelClient *rcc,
+    SpiceMarshaller *base_marshaller)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceMsgMigrate migrate;
 
-    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_MIGRATE, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
     spice_marshall_msg_migrate(base_marshaller, &migrate);
     display_channel->expect_migrate_mark = TRUE;
 }
 
-static void display_channel_marshall_migrate_data(DisplayChannel *display_channel,
-                                                  SpiceMarshaller *base_marshaller)
+static void display_channel_marshall_migrate_data(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     DisplayChannelMigrateData display_data;
 
-    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_MIGRATE_DATA, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
 
     ASSERT(display_channel->pixmap_cache);
     display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
     ASSERT(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
     display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
 
-    display_data.message_serial = red_channel_get_message_serial((RedChannel *)display_channel);
+    display_data.message_serial = red_channel_client_get_message_serial(rcc);
 
     display_data.pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
     display_data.pixmap_cache_id = display_channel->pixmap_cache->id;
@@ -7623,13 +7615,13 @@ static void display_channel_marshall_migrate_data(DisplayChannel *display_channe
                              (uint8_t *)&display_data, sizeof(display_data));
 }
 
-static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel,
-                                                 SpiceMarshaller *base_marshaller)
+static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceMsgWaitForChannels wait;
     PixmapCache *pixmap_cache;
 
-    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
     pixmap_cache = display_channel->pixmap_cache;
 
     pthread_mutex_lock(&pixmap_cache->lock);
@@ -7646,21 +7638,21 @@ static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel
     spice_marshall_msg_wait_for_channels(base_marshaller, &wait);
 }
 
-static void display_channel_marshall_reset_cache(DisplayChannel *display_channel,
-                                                 SpiceMarshaller *base_marshaller)
+static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceMsgWaitForChannels wait;
 
-    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
-    pixmap_cache_reset(display_channel->pixmap_cache, display_channel, &wait);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
+    pixmap_cache_reset(display_channel->pixmap_cache, rcc, &wait);
 
     spice_marshall_msg_display_inval_all_pixmaps(base_marshaller,
                                                  &wait);
 }
 
-static void red_marshall_image(DisplayChannel *display_channel, SpiceMarshaller *m, ImageItem *item)
+static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item)
 {
-    RedChannel *channel;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceImage red_image;
     RedWorker *worker;
     SpiceBitmap bitmap;
@@ -7674,8 +7666,7 @@ static void red_marshall_image(DisplayChannel *display_channel, SpiceMarshaller
     SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
     SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
 
-    ASSERT(display_channel && item);
-    channel = &display_channel->common.base;
+    ASSERT(rcc && display_channel && item);
     worker = display_channel->common.worker;
 
     QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
@@ -7698,7 +7689,7 @@ static void red_marshall_image(DisplayChannel *display_channel, SpiceMarshaller
     chunks = spice_chunks_new_linear(item->data, bitmap.stride * bitmap.y);
     bitmap.data = chunks;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->link);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->link);
 
     copy.base.surface_id = item->surface_id;
     copy.base.box.left = item->pos.x;
@@ -7792,17 +7783,15 @@ static void red_marshall_image(DisplayChannel *display_channel, SpiceMarshaller
     spice_chunks_destroy(chunks);
 }
 
-static void red_display_marshall_upgrade(DisplayChannel *display_channel, SpiceMarshaller *m, UpgradeItem *item)
+static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller *m, UpgradeItem *item)
 {
-    RedChannel *channel;
     RedDrawable *red_drawable;
     SpiceMsgDisplayDrawCopy copy;
     SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
 
-    ASSERT(display_channel && item && item->drawable);
-    channel = &display_channel->common.base;
+    ASSERT(rcc && rcc->channel && item && item->drawable);
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->base);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->base);
 
     red_drawable = item->drawable->red_drawable;
     ASSERT(red_drawable->type == QXL_DRAW_COPY);
@@ -7818,18 +7807,18 @@ static void red_display_marshall_upgrade(DisplayChannel *display_channel, SpiceM
     spice_marshall_msg_display_draw_copy(m, &copy,
                                          &src_bitmap_out, &mask_bitmap_out);
 
-    fill_bits(display_channel, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
+    fill_bits(rcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
 }
 
-static void red_display_marshall_stream_start(DisplayChannel *display_channel,
+static void red_display_marshall_stream_start(RedChannelClient *rcc,
                      SpiceMarshaller *base_marshaller, StreamAgent *agent)
 {
-    RedChannel *channel = &display_channel->common.base;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     Stream *stream = agent->stream;
 
     agent->last_send_time = 0;
     ASSERT(stream);
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_CREATE,
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE,
         stream->current ? &stream->current->pipe_item : NULL);
     SpiceMsgDisplayStreamCreate stream_create;
     SpiceClipRects clip_rects;
@@ -7857,18 +7846,17 @@ static void red_display_marshall_stream_start(DisplayChannel *display_channel,
     spice_marshall_msg_display_stream_create(base_marshaller, &stream_create);
 }
 
-static void red_display_marshall_stream_clip(DisplayChannel *display_channel,
+static void red_display_marshall_stream_clip(RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          StreamClipItem *item)
 {
-    RedChannel *channel = &display_channel->common.base;
-
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     StreamAgent *agent = item->stream_agent;
     Stream *stream = agent->stream;
 
     ASSERT(stream);
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
     SpiceMsgDisplayStreamClip stream_clip;
 
     stream_clip.id = agent - display_channel->stream_agents;
@@ -7878,58 +7866,58 @@ static void red_display_marshall_stream_clip(DisplayChannel *display_channel,
     spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip);
 }
 
-static void red_display_marshall_stream_end(DisplayChannel *display_channel,
+static void red_display_marshall_stream_end(RedChannelClient *rcc,
                    SpiceMarshaller *base_marshaller, StreamAgent* agent)
 {
-    RedChannel *channel = &display_channel->common.base;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceMsgDisplayStreamDestroy destroy;
 
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
     destroy.id = agent - display_channel->stream_agents;
 
     spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
 }
 
-static void red_cursor_marshall_inval(CursorChannel *channel,
+static void red_cursor_marshall_inval(RedChannelClient *rcc,
                 SpiceMarshaller *m, CacheItem *cach_item)
 {
-    ASSERT(channel);
-    red_marshall_inval((RedChannel *)channel, m, cach_item);
+    ASSERT(rcc);
+    red_marshall_inval(rcc, m, cach_item);
 }
 
-static void red_marshall_cursor_init(CursorChannel *channel, SpiceMarshaller *base_marshaller)
+static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
+    CursorChannel *cursor_channel;
     RedWorker *worker;
     SpiceMsgCursorInit msg;
     AddBufInfo info;
 
-    ASSERT(channel);
-
-    worker = channel->common.worker;
+    ASSERT(rcc);
+    cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
+    worker = cursor_channel->common.worker;
 
-    red_channel_init_send_data(&channel->common.base, SPICE_MSG_CURSOR_INIT, &worker->cursor->pipe_data);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, &worker->cursor->pipe_data);
     msg.visible = worker->cursor_visible;
     msg.position = worker->cursor_position;
     msg.trail_length = worker->cursor_trail_length;
     msg.trail_frequency = worker->cursor_trail_frequency;
 
-    fill_cursor(channel, &msg.cursor, worker->cursor, &info);
+    fill_cursor(cursor_channel, &msg.cursor, worker->cursor, &info);
     spice_marshall_msg_cursor_init(base_marshaller, &msg);
     add_buf_from_info(base_marshaller, &info);
 }
 
-static void red_marshall_local_cursor(CursorChannel *cursor_channel,
+static void red_marshall_local_cursor(RedChannelClient *rcc,
           SpiceMarshaller *base_marshaller, LocalCursor *cursor)
 {
-    RedChannel *channel;
+    CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
     SpiceMsgCursorSet cursor_set;
     AddBufInfo info;
     RedWorker *worker;
 
     ASSERT(cursor_channel);
     worker = cursor_channel->common.worker;
-    channel = &cursor_channel->common.base;
-    red_channel_init_send_data(channel, SPICE_MSG_CURSOR_SET, &cursor->base.pipe_data);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, &cursor->base.pipe_data);
     cursor_set.position = cursor->position;
     cursor_set.visible = worker->cursor_visible;
 
@@ -7939,27 +7927,25 @@ static void red_marshall_local_cursor(CursorChannel *cursor_channel,
     red_release_cursor(worker, (CursorItem *)cursor);
 }
 
-static void cursor_channel_marshall_migrate(CursorChannel *cursor_channel,
-                                            SpiceMarshaller *base_marshaller)
+static void cursor_channel_marshall_migrate(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
     SpiceMsgMigrate migrate;
 
-    red_channel_init_send_data(&cursor_channel->common.base, SPICE_MSG_MIGRATE, NULL);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = 0;
 
     spice_marshall_msg_migrate(base_marshaller, &migrate);
 }
 
-static void red_marshall_cursor(CursorChannel *cursor_channel,
+static void red_marshall_cursor(RedChannelClient *rcc,
                    SpiceMarshaller *m, CursorItem *cursor)
 {
-    RedChannel *channel;
+    CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
     RedCursorCmd *cmd;
     RedWorker *worker;
 
     ASSERT(cursor_channel);
 
-    channel = &cursor_channel->common.base;
     worker = cursor_channel->common.worker;
 
     cmd = cursor->red_cursor;
@@ -7967,7 +7953,7 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
     case QXL_CURSOR_MOVE:
         {
             SpiceMsgCursorMove cursor_move;
-            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_MOVE, &cursor->pipe_data);
+            red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_MOVE, &cursor->pipe_data);
             cursor_move.position = cmd->u.position;
             spice_marshall_msg_cursor_move(m, &cursor_move);
             break;
@@ -7977,7 +7963,7 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
             SpiceMsgCursorSet cursor_set;
             AddBufInfo info;
 
-            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_SET, &cursor->pipe_data);
+            red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, &cursor->pipe_data);
             cursor_set.position = cmd->u.set.position;
             cursor_set.visible = worker->cursor_visible;
 
@@ -7987,13 +7973,13 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
             break;
         }
     case QXL_CURSOR_HIDE:
-        red_channel_init_send_data(channel, SPICE_MSG_CURSOR_HIDE, &cursor->pipe_data);
+        red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_HIDE, &cursor->pipe_data);
         break;
     case QXL_CURSOR_TRAIL:
         {
             SpiceMsgCursorTrail cursor_trail;
 
-            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_TRAIL, &cursor->pipe_data);
+            red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_TRAIL, &cursor->pipe_data);
             cursor_trail.length = cmd->u.trail.length;
             cursor_trail.frequency = cmd->u.trail.frequency;
             spice_marshall_msg_cursor_trail(m, &cursor_trail);
@@ -8002,122 +7988,118 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
     default:
         red_error("bad cursor command %d", cmd->type);
     }
-
     red_release_cursor(worker, cursor);
 }
 
-static void red_marshall_surface_create(DisplayChannel *display,
+static void red_marshall_surface_create(RedChannelClient *rcc,
     SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
 {
-    RedChannel *channel;
-
-    ASSERT(display);
-    channel = &display->common.base;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
-    region_init(&display->surface_client_lossy_region[surface_create->surface_id]);
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
+    ASSERT(display_channel);
+    region_init(&display_channel->surface_client_lossy_region[surface_create->surface_id]);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
 
     spice_marshall_msg_display_surface_create(base_marshaller, surface_create);
 }
 
-static void red_marshall_surface_destroy(DisplayChannel *display,
+static void red_marshall_surface_destroy(RedChannelClient *rcc,
        SpiceMarshaller *base_marshaller, uint32_t surface_id)
 {
-    RedChannel *channel;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     SpiceMsgSurfaceDestroy surface_destroy;
 
-    ASSERT(display);
-    channel = &display->common.base;
+    ASSERT(display_channel);
 
-    region_destroy(&display->surface_client_lossy_region[surface_id]);
-    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL);
+    region_destroy(&display_channel->surface_client_lossy_region[surface_id]);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL);
 
     surface_destroy.surface_id = surface_id;
 
     spice_marshall_msg_display_surface_destroy(base_marshaller, &surface_destroy);
 }
 
-static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
+static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
-    SpiceMarshaller *m = red_channel_get_marshaller(base);
-    DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(base);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+    DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(rcc->channel);
     RedWorker *worker = display_channel->common.worker;
 
     red_display_reset_send_data(display_channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_DRAW: {
         Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
-        marshall_qxl_drawable(display_channel, m, drawable);
+        marshall_qxl_drawable(rcc, m, drawable);
         release_drawable(worker, drawable);
         break;
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_display_marshall_inval(display_channel, m, (CacheItem *)pipe_item);
+        red_marshall_inval(rcc, m, (CacheItem *)pipe_item);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_STREAM_CREATE: {
         StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item);
-        red_display_marshall_stream_start(display_channel, m, agent);
+        red_display_marshall_stream_start(rcc, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_CLIP: {
         StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
-        red_display_marshall_stream_clip(display_channel, m, clip_item);
+        red_display_marshall_stream_clip(rcc, m, clip_item);
         red_display_release_stream_clip(display_channel, clip_item);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_DESTROY: {
         StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item);
-        red_display_marshall_stream_end(display_channel, m, agent);
+        red_display_marshall_stream_end(rcc, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_UPGRADE:
-        red_display_marshall_upgrade(display_channel, m, (UpgradeItem *)pipe_item);
+        red_display_marshall_upgrade(rcc, m, (UpgradeItem *)pipe_item);
         release_upgrade_item(worker, (UpgradeItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
-        display_marshall_verb(display_channel, ((VerbItem*)pipe_item)->verb);
+        red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        display_channel_marshall_migrate(display_channel, m);
+        display_channel_marshall_migrate(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        display_channel_marshall_migrate_data(display_channel, m);
+        display_channel_marshall_migrate_data(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_IMAGE:
-        red_marshall_image(display_channel, m, (ImageItem *)pipe_item);
+        red_marshall_image(rcc, m, (ImageItem *)pipe_item);
         release_image_item((ImageItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-        display_channel_marshall_pixmap_sync(display_channel, m);
+        display_channel_marshall_pixmap_sync(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
-        display_channel_marshall_reset_cache(display_channel, m);
+        display_channel_marshall_reset_cache(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
         red_reset_palette_cache(display_channel);
-        red_marshall_verb((RedChannel *)display_channel, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
+        red_marshall_verb(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_CREATE_SURFACE: {
         SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem,
                                                               pipe_item);
-        red_marshall_surface_create(display_channel, m, &surface_create->surface_create);
+        red_marshall_surface_create(rcc, m, &surface_create->surface_create);
         free(surface_create);
         break;
     }
     case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
         SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(pipe_item, SurfaceDestroyItem,
                                                                 pipe_item);
-        red_marshall_surface_destroy(display_channel, m, surface_destroy->surface_destroy.surface_id);
+        red_marshall_surface_destroy(rcc, m, surface_destroy->surface_destroy.surface_id);
         free(surface_destroy);
         break;
     }
@@ -8125,53 +8107,53 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         red_error("invalid pipe item type");
     }
     // a message is pending
-    if (red_channel_send_message_pending(&display_channel->common.base)) {
-        display_begin_send_message(display_channel, m);
+    if (red_channel_client_send_message_pending(rcc)) {
+        display_begin_send_message(rcc, m);
     }
     red_unref_channel(&display_channel->common.base);
 }
 
-static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
+static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
-    SpiceMarshaller *m = red_channel_get_marshaller(channel);
-    CursorChannel *cursor_channel = SPICE_CONTAINEROF(channel, CursorChannel, common.base);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+    CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
 
-    red_ref_channel(channel);
+    red_ref_channel(rcc->channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
-        red_marshall_cursor(cursor_channel, m, (CursorItem *)pipe_item);
+        red_marshall_cursor(rcc, m, (CursorItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_LOCAL_CURSOR:
-        red_marshall_local_cursor(cursor_channel, m, (LocalCursor *)pipe_item);
+        red_marshall_local_cursor(rcc, m, (LocalCursor *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_cursor_marshall_inval(cursor_channel, m, (CacheItem *)pipe_item);
+        red_cursor_marshall_inval(rcc, m, (CacheItem *)pipe_item);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
-        red_marshall_verb(channel, ((VerbItem*)pipe_item)->verb);
+        red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        cursor_channel_marshall_migrate(cursor_channel, m);
+        cursor_channel_marshall_migrate(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
         red_reset_cursor_cache(cursor_channel);
-        red_marshall_cursor_init(cursor_channel, m);
+        red_marshall_cursor_init(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
         red_reset_cursor_cache(cursor_channel);
-        red_marshall_verb(channel, SPICE_MSG_CURSOR_INVAL_ALL);
+        red_marshall_verb(rcc, SPICE_MSG_CURSOR_INVAL_ALL);
         free(pipe_item);
         break;
     default:
         red_error("invalid pipe item type");
     }
-    red_channel_begin_send_message(channel);
-    red_unref_channel(channel);
+    red_channel_client_begin_send_message(rcc);
+    red_unref_channel(rcc->channel);
 }
 
 static inline void red_push(RedWorker *worker)
@@ -8258,17 +8240,19 @@ static void red_disconnect_channel(RedChannel *channel)
     red_unref_channel(channel);
 }
 
-static void red_disconnect_display(RedChannel *channel)
+static void red_disconnect_display(RedChannelClient *rcc)
 {
+    // TODO: MC: right now we assume single channel
     DisplayChannel *display_channel;
-    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
+    CommonChannel *common;
     RedWorker *worker;
 
-    if (!channel || !red_channel_is_connected(channel)) {
+    if (!rcc || !red_channel_is_connected(rcc->channel)) {
         return;
     }
+    common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
     worker = common->worker;
-    display_channel = (DisplayChannel *)channel;
+    display_channel = (DisplayChannel *)rcc->channel;
     ASSERT(display_channel == worker->display_channel);
 #ifdef COMPRESS_STAT
     print_compress_stats(display_channel);
@@ -8287,7 +8271,18 @@ static void red_disconnect_display(RedChannel *channel)
     }
     free(display_channel->send_data.free_list.res);
     red_display_destroy_streams(display_channel);
-    red_disconnect_channel(channel);
+    red_disconnect_channel(rcc->channel);
+}
+
+void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
+{
+    // TODO: we need to record the client that actually causes the timeout. So
+    // we need to check the locations of the various pipe heads when counting,
+    // and disconnect only those/that.
+    if (!channel) {
+        return;
+    }
+    red_channel_apply_clients(channel, red_disconnect_display);
 }
 
 static void red_migrate_display(RedWorker *worker)
@@ -8520,9 +8515,11 @@ static inline void flush_display_commands(RedWorker *worker)
             red_ref_channel(channel);
             red_channel_receive(channel);
             red_channel_send(channel);
+            // TODO: MC: the whole timeout will break since it takes lowest timeout, should
+            // do it client by client.
             if (red_now() >= end_time) {
                 red_printf("update timeout");
-                red_disconnect_display(channel);
+                red_disconnect_all_display_TODO_remove_me(channel);
             } else {
                 sleep_count++;
                 usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
@@ -8614,7 +8611,7 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
         }
         if (red_now() > end_time) {
             red_printf("timeout");
-            red_disconnect_display((RedChannel *)display_channel);
+            red_disconnect_all_display_TODO_remove_me((RedChannel *)display_channel);
             break;
         }
         usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
@@ -8872,9 +8869,9 @@ static int display_channel_handle_migrate_glz_dictionary(DisplayChannel *channel
                                                              &migrate_info->glz_dict_restore_data));
 }
 
-static int display_channel_handle_migrate_mark(RedChannel *base)
+static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
 {
-    DisplayChannel *channel = SPICE_CONTAINEROF(base, DisplayChannel, common.base);
+    DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
     if (!channel->expect_migrate_mark) {
         red_printf("unexpected");
@@ -8886,7 +8883,7 @@ static int display_channel_handle_migrate_mark(RedChannel *base)
 }
 
 static uint64_t display_channel_handle_migrate_data_get_serial(
-                RedChannel *base, uint32_t size, void *message)
+                RedChannelClient *rcc, uint32_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data = message;
 
@@ -8902,11 +8899,11 @@ static uint64_t display_channel_handle_migrate_data_get_serial(
     return migrate_data->message_serial;
 }
 
-static uint64_t display_channel_handle_migrate_data(RedChannel *base, uint32_t size, void *message)
+static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data;
     int i;
-    DisplayChannel *channel = SPICE_CONTAINEROF(base, DisplayChannel, common.base);
+    DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
     if (size < sizeof(*migrate_data)) {
         red_printf("bad message size");
@@ -8953,26 +8950,26 @@ static uint64_t display_channel_handle_migrate_data(RedChannel *base, uint32_t s
     return TRUE;
 }
 
-static int display_channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
+static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
 {
     switch (type) {
     case SPICE_MSGC_DISPLAY_INIT:
-        if (!((DisplayChannel *)channel)->expect_init) {
+        if (!((DisplayChannel *)rcc->channel)->expect_init) {
             red_printf("unexpected SPICE_MSGC_DISPLAY_INIT");
             return FALSE;
         }
-        ((DisplayChannel *)channel)->expect_init = FALSE;
-        return display_channel_init((DisplayChannel *)channel, (SpiceMsgcDisplayInit *)message);
+        ((DisplayChannel *)rcc->channel)->expect_init = FALSE;
+        return display_channel_init((DisplayChannel *)rcc->channel, (SpiceMsgcDisplayInit *)message);
     default:
-        return red_channel_handle_message(channel, size, type, message);
+        return red_channel_client_handle_message(rcc, size, type, message);
     }
 }
 
-static int common_channel_config_socket(RedChannel *channel)
+static int common_channel_config_socket(RedChannelClient *rcc)
 {
     int flags;
     int delay_val;
-    RedsStream *stream = red_channel_get_stream(channel);
+    RedsStream *stream = red_channel_client_get_stream(rcc);
 
     if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno));
@@ -9033,7 +9030,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     RedChannel *channel;
     CommonChannel *common;
 
-    channel = red_channel_create_parser(size, stream, &worker_core, migrate,
+    channel = red_channel_create_parser(size, &worker_core, migrate,
                                         TRUE /* handle_acks */,
                                         common_channel_config_socket,
                                         spice_get_client_channel_parser(channel_id, NULL),
@@ -9043,8 +9040,8 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
                                         hold_item,
                                         send_item,
                                         release_item,
-                                        red_channel_default_peer_on_error,
-                                        red_channel_default_peer_on_error,
+                                        red_channel_client_default_peer_on_error,
+                                        red_channel_client_default_peer_on_error,
                                         handle_migrate_flush_mark,
                                         handle_migrate_data,
                                         handle_migrate_data_get_serial);
@@ -9052,6 +9049,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     if (!channel) {
         goto error;
     }
+    red_channel_client_create(sizeof(RedChannelClient), channel, stream);
     common->id = worker->id;
     common->listener.refs = 1;
     common->listener.action = handler;
@@ -9092,7 +9090,7 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
     }
 }
 
-static void display_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
     ASSERT(item);
     switch (item->type) {
@@ -9114,8 +9112,9 @@ static void display_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
     }
 }
 
-static void display_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed /* ignored */)
+static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed /* ignored */)
 {
+    RedChannel *channel = rcc->channel;
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
 
     ASSERT(item);
@@ -9143,7 +9142,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, in
     DisplayChannel *display_channel;
     size_t stream_buf_size;
 
-    red_disconnect_display((RedChannel *)worker->display_channel);
+    red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
 
     if (!(display_channel = (DisplayChannel *)__new_channel(worker, sizeof(*display_channel),
                                                             SPICE_CHANNEL_DISPLAY, stream,
@@ -9221,6 +9220,11 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, in
     stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
 }
 
+static void red_disconnect_cursor_client(RedChannelClient *rcc)
+{
+    red_disconnect_cursor(rcc->channel);
+}
+
 static void red_disconnect_cursor(RedChannel *channel)
 {
     CommonChannel *common;
@@ -9255,15 +9259,15 @@ static void on_new_cursor_channel(RedWorker *worker)
     }
 }
 
-static void cursor_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void cursor_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
     ASSERT(item);
     ((CursorItem *)item)->refs++;
 }
 
-static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
+static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
-    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
+    CommonChannel *common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
 
     ASSERT(item);
     switch (item->type) {
@@ -9284,11 +9288,11 @@ static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrat
     if (!(channel = (CursorChannel *)__new_channel(worker, sizeof(*channel),
                                                    SPICE_CHANNEL_CURSOR, stream, migrate,
                                                    handle_channel_events,
-                                                   red_disconnect_cursor,
+                                                   red_disconnect_cursor_client,
                                                    cursor_channel_send_item,
                                                    cursor_channel_hold_pipe_item,
                                                    cursor_channel_release_item,
-                                                   red_channel_handle_message,
+                                                   red_channel_client_handle_message,
                                                    NULL,
                                                    NULL,
                                                    NULL))) {
@@ -9383,7 +9387,8 @@ static void red_wait_outgoing_item(RedChannel *channel)
 
     if (blocked) {
         red_printf("timeout");
-        channel->disconnect(channel);
+        // TODO - not MC friendly
+        red_channel_apply_clients(channel, channel->disconnect);
     }
     red_unref_channel(channel);
 }
@@ -9401,7 +9406,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_printf("");
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     red_ref_channel(channel);
-    channel->hold_item(channel, item);
+    channel->hold_item(channel->rcc, item);
 
     end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
 
@@ -9421,14 +9426,15 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
 
     if (item_in_pipe) {
         red_printf("timeout");
-        channel->disconnect(channel);
+        // TODO - not MC friendly
+        red_channel_apply_clients(channel, channel->disconnect);
     } else {
         if (red_channel_item_being_sent(channel, item)) {
             red_wait_outgoing_item(channel);
         }
     }
 
-    channel->release_item(channel, item, FALSE);
+    channel->release_item(channel->rcc, item, FALSE);
     red_unref_channel(channel);
 }
 
@@ -9734,7 +9740,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     }
     case RED_WORKER_MESSAGE_DISPLAY_DISCONNECT:
         red_printf("disconnect");
-        red_disconnect_display((RedChannel *)worker->display_channel);
+        red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
         break;
     case RED_WORKER_MESSAGE_STOP: {
         int x;
diff --git a/server/smartcard.c b/server/smartcard.c
index fed88a5..f67552f 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -36,6 +36,7 @@ typedef struct SmartCardDeviceState {
     uint32_t             buf_size;
     uint8_t             *buf_pos;
     uint32_t             buf_used;
+    RedChannelClient    *rcc; // client providing the remote card
 } SmartCardDeviceState;
 
 enum {
@@ -58,8 +59,6 @@ typedef struct SmartCardChannel {
     RedChannel base;
 } SmartCardChannel;
 
-static SmartCardChannel *g_smartcard_channel = NULL;
-
 static struct Readers {
     uint32_t num;
     SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
@@ -69,16 +68,14 @@ static SpiceCharDeviceInstance* smartcard_readers_get_unattached();
 static SpiceCharDeviceInstance* smartcard_readers_get(uint32_t reader_id);
 static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *sin);
 static void smartcard_char_device_attach(
-    SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
-static void smartcard_char_device_detach(
-    SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
-static void smartcard_channel_write_to_reader(
-    SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
+    SpiceCharDeviceInstance *char_device, RedChannelClient *rcc);
+static void smartcard_char_device_detach(SpiceCharDeviceInstance *char_device);
+static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader);
 
 static void smartcard_char_device_on_message_from_device(
     SmartCardDeviceState *state, VSCMsgHeader *header);
 static void smartcard_on_message_from_device(
-    SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
+    RedChannelClient *rcc, VSCMsgHeader *vheader);
 static SmartCardDeviceState* smartcard_device_state_new();
 static void smartcard_device_state_free(SmartCardDeviceState* st);
 
@@ -138,12 +135,13 @@ void smartcard_char_device_on_message_from_device(
     if (state->reader_id == VSCARD_UNDEFINED_READER_ID && vheader->type != VSC_Init) {
         red_printf("error: reader_id not assigned for message of type %d", vheader->type);
     }
-    ASSERT(g_smartcard_channel != NULL);
     sent_header = spice_memdup(vheader, sizeof(*vheader) + vheader->length);
     /* We patch the reader_id, since the device only knows about itself, and
      * we know about the sum of readers. */
     sent_header->reader_id = state->reader_id;
-    smartcard_on_message_from_device(g_smartcard_channel, sent_header);
+    if (state->rcc) {
+        smartcard_on_message_from_device(state->rcc, sent_header);
+    }
 }
 
 static void smartcard_readers_detach_all(SmartCardChannel *smartcard_channel)
@@ -151,8 +149,7 @@ static void smartcard_readers_detach_all(SmartCardChannel *smartcard_channel)
     int i;
 
     for (i = 0 ; i < g_smartcard_readers.num; ++i) {
-        smartcard_char_device_detach(g_smartcard_readers.sin[i],
-                                     smartcard_channel);
+        smartcard_char_device_detach(g_smartcard_readers.sin[i]);
     }
 }
 
@@ -202,6 +199,7 @@ static SmartCardDeviceState* smartcard_device_state_new()
     st->buf = spice_malloc(st->buf_size);
     st->buf_pos = st->buf;
     st->buf_used = 0;
+    st->rcc = NULL;
     return st;
 }
 
@@ -233,7 +231,7 @@ int smartcard_device_connect(SpiceCharDeviceInstance *char_device)
 }
 
 static void smartcard_char_device_attach(
-    SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
+    SpiceCharDeviceInstance *char_device, RedChannelClient *rcc)
 {
     SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
 
@@ -241,13 +239,13 @@ static void smartcard_char_device_attach(
         return;
     }
     st->attached = TRUE;
+    st->rcc = rcc;
     VSCMsgHeader vheader = {.type = VSC_ReaderAdd, .reader_id=st->reader_id,
         .length=0};
-    smartcard_channel_write_to_reader(smartcard_channel, &vheader);
+    smartcard_channel_write_to_reader(&vheader);
 }
 
-static void smartcard_char_device_detach(
-    SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
+static void smartcard_char_device_detach(SpiceCharDeviceInstance *char_device)
 {
     SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
 
@@ -255,43 +253,44 @@ static void smartcard_char_device_detach(
         return;
     }
     st->attached = FALSE;
+    st->rcc = NULL;
     VSCMsgHeader vheader = {.type = VSC_ReaderRemove, .reader_id=st->reader_id,
         .length=0};
-    smartcard_channel_write_to_reader(smartcard_channel, &vheader);
+    smartcard_channel_write_to_reader(&vheader);
 }
 
-static int smartcard_channel_config_socket(RedChannel *channel)
+static int smartcard_channel_config_socket(RedChannelClient *rcc)
 {
     return TRUE;
 }
 
-static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
+                                                    SpiceDataHeader *msg_header)
 {
     //red_printf("allocing %d bytes", msg_header->size);
     return spice_malloc(msg_header->size);
 }
 
-static void smartcard_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
-                                               uint8_t *msg)
+static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc,
+                                SpiceDataHeader *msg_header, uint8_t *msg)
 {
     red_printf("freeing %d bytes", msg_header->size);
     free(msg);
 }
 
-static void smartcard_channel_send_data(RedChannel *channel, SpiceMarshaller *m,
+static void smartcard_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *m,
                                         PipeItem *item, VSCMsgHeader *vheader)
 {
-    ASSERT(channel);
-    ASSERT(vheader);
-    red_channel_init_send_data(channel, SPICE_MSG_SMARTCARD_DATA, item);
+    ASSERT(rcc && vheader);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_SMARTCARD_DATA, item);
     spice_marshaller_add_ref(m, (uint8_t*)vheader, sizeof(VSCMsgHeader));
     if (vheader->length > 0) {
         spice_marshaller_add_ref(m, (uint8_t*)(vheader+1), vheader->length);
     }
-    red_channel_begin_send_message(channel);
+    red_channel_client_begin_send_message(rcc);
 }
 
-static void smartcard_channel_send_message(RedChannel *channel, SpiceMarshaller *m,
+static void smartcard_channel_send_message(RedChannelClient *rcc, SpiceMarshaller *m,
     PipeItem *item, uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
 {
     VSCMsgHeader mhHeader;
@@ -305,44 +304,43 @@ static void smartcard_channel_send_message(RedChannel *channel, SpiceMarshaller
     //spice_marshaller_add(m, data, len);
     //marshaller_outgoing_write(msg);
 
-    smartcard_channel_send_data(channel, m, item, &mhHeader);
+    smartcard_channel_send_data(rcc, m, item, &mhHeader);
 }
 
 static void smartcard_channel_send_error(
-    SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
+    RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
 {
     ErrorItem* error_item = (ErrorItem*)item;
     VSCMsgError error;
 
     error.code = error_item->error;
-    smartcard_channel_send_message(&smartcard_channel->base, m, item,
-        error_item->reader_id, VSC_Error, (uint8_t*)&error, sizeof(error));
+    smartcard_channel_send_message(rcc, m, item, error_item->reader_id,
+        VSC_Error, (uint8_t*)&error, sizeof(error));
 }
 
-static void smartcard_channel_send_msg(
-    SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
+static void smartcard_channel_send_msg(RedChannelClient *rcc,
+                                       SpiceMarshaller *m, PipeItem *item)
 {
     MsgItem* msg_item = (MsgItem*)item;
 
-    smartcard_channel_send_data(&smartcard_channel->base, m, item, msg_item->vheader);
+    smartcard_channel_send_data(rcc, m, item, msg_item->vheader);
 }
 
-static void smartcard_channel_send_item(RedChannel *channel, PipeItem *item)
+static void smartcard_channel_send_item(RedChannelClient *rcc, PipeItem *item)
 {
-    SmartCardChannel *smartcard_channel = (SmartCardChannel *)channel;
-    SpiceMarshaller *m = red_channel_get_marshaller(channel);
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
     switch (item->type) {
     case PIPE_ITEM_TYPE_ERROR:
-        smartcard_channel_send_error(smartcard_channel, m, item);
+        smartcard_channel_send_error(rcc, m, item);
         break;
     case PIPE_ITEM_TYPE_MSG:
-        smartcard_channel_send_msg(smartcard_channel, m, item);
+        smartcard_channel_send_msg(rcc, m, item);
     }
 }
 
 
-static void smartcard_channel_release_pipe_item(RedChannel *channel, PipeItem *item, int item_pushed)
+static void smartcard_channel_release_pipe_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
     free(item);
     if (item->type == PIPE_ITEM_TYPE_MSG) {
@@ -350,85 +348,82 @@ static void smartcard_channel_release_pipe_item(RedChannel *channel, PipeItem *i
     }
 }
 
-static void smartcard_channel_disconnect(RedChannel *channel)
+static void smartcard_channel_disconnect(RedChannelClient *rcc)
 {
-    smartcard_readers_detach_all((SmartCardChannel*)channel);
-    red_channel_destroy(channel);
-    g_smartcard_channel = NULL;
+    smartcard_readers_detach_all((SmartCardChannel*)(rcc->channel));
+    red_channel_client_destroy(rcc);
 }
 
 /* this is called from both device input and client input. since the device is
  * a usb device, the context is still the main thread (kvm_main_loop, timers)
  * so no mutex is required. */
-static void smartcard_channel_pipe_add_push(SmartCardChannel *channel, PipeItem *item)
+static void smartcard_channel_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
 {
-    red_channel_pipe_add_push(&channel->base, item);
+    red_channel_pipe_add_push(rcc->channel, item);
 }
 
-static void smartcard_push_error(SmartCardChannel* channel, uint32_t reader_id, VSCErrorCode error)
+static void smartcard_push_error(RedChannelClient *rcc, uint32_t reader_id, VSCErrorCode error)
 {
     ErrorItem *error_item = spice_new0(ErrorItem, 1);
 
     error_item->base.type = PIPE_ITEM_TYPE_ERROR;
     error_item->reader_id = reader_id;
     error_item->error = error;
-    smartcard_channel_pipe_add_push(channel, &error_item->base);
+    smartcard_channel_pipe_add_push(rcc, &error_item->base);
 }
 
-static void smartcard_push_vscmsg(SmartCardChannel *channel, VSCMsgHeader *vheader)
+static void smartcard_push_vscmsg(RedChannelClient *rcc, VSCMsgHeader *vheader)
 {
     MsgItem *msg_item = spice_new0(MsgItem, 1);
 
     msg_item->base.type = PIPE_ITEM_TYPE_MSG;
     msg_item->vheader = vheader;
-    smartcard_channel_pipe_add_push(channel, &msg_item->base);
+    smartcard_channel_pipe_add_push(rcc, &msg_item->base);
 }
 
-void smartcard_on_message_from_device(SmartCardChannel *smartcard_channel,
-    VSCMsgHeader* vheader)
+void smartcard_on_message_from_device(RedChannelClient *rcc, VSCMsgHeader* vheader)
 {
-    smartcard_push_vscmsg(smartcard_channel, vheader);
+    smartcard_push_vscmsg(rcc, vheader);
 }
 
-static void smartcard_remove_reader(SmartCardChannel *smartcard_channel, uint32_t reader_id)
+static void smartcard_remove_reader(RedChannelClient *rcc, uint32_t reader_id)
 {
     SpiceCharDeviceInstance *char_device = smartcard_readers_get(reader_id);
     SmartCardDeviceState *state;
 
     if (char_device == NULL) {
-        smartcard_push_error(smartcard_channel, reader_id,
+        smartcard_push_error(rcc, reader_id,
             VSC_GENERAL_ERROR);
         return;
     }
 
     state = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
     if (state->attached == FALSE) {
-        smartcard_push_error(smartcard_channel, reader_id,
+        smartcard_push_error(rcc, reader_id,
             VSC_GENERAL_ERROR);
         return;
     }
-    smartcard_char_device_detach(char_device, smartcard_channel);
+    smartcard_char_device_detach(char_device);
 }
 
-static void smartcard_add_reader(SmartCardChannel *smartcard_channel, uint8_t *name)
+static void smartcard_add_reader(RedChannelClient *rcc, uint8_t *name)
 {
     // TODO - save name somewhere
     SpiceCharDeviceInstance *char_device =
             smartcard_readers_get_unattached();
 
     if (char_device != NULL) {
-        smartcard_char_device_attach(char_device, smartcard_channel);
+        smartcard_char_device_attach(char_device, rcc);
         // The device sends a VSC_Error message, we will let it through, no
         // need to send our own. We already set the correct reader_id, from
         // our SmartCardDeviceState.
     } else {
-        smartcard_push_error(smartcard_channel, VSCARD_UNDEFINED_READER_ID,
+        smartcard_push_error(rcc, VSCARD_UNDEFINED_READER_ID,
             VSC_CANNOT_ADD_MORE_READERS);
     }
 }
 
-static void smartcard_channel_write_to_reader(
-    SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader)
+static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader)
 {
     SpiceCharDeviceInstance *sin;
     SpiceCharDeviceInterface *sif;
@@ -449,19 +444,20 @@ static void smartcard_channel_write_to_reader(
     ASSERT(n == actual_length + sizeof(VSCMsgHeader));
 }
 
-static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader *header, uint8_t *msg)
+static int smartcard_channel_handle_message(RedChannelClient *rcc,
+                                            SpiceDataHeader *header,
+                                            uint8_t *msg)
 {
     VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
-    SmartCardChannel* smartcard_channel = (SmartCardChannel*)channel;
 
     ASSERT(header->size == vheader->length + sizeof(VSCMsgHeader));
     switch (vheader->type) {
         case VSC_ReaderAdd:
-            smartcard_add_reader(smartcard_channel, msg + sizeof(VSCMsgHeader));
+            smartcard_add_reader(rcc, msg + sizeof(VSCMsgHeader));
             return TRUE;
             break;
         case VSC_ReaderRemove:
-            smartcard_remove_reader(smartcard_channel, vheader->reader_id);
+            smartcard_remove_reader(rcc, vheader->reader_id);
             return TRUE;
             break;
         case VSC_Init:
@@ -483,11 +479,11 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
             vheader->type, vheader->length);
         return FALSE;
     }
-    smartcard_channel_write_to_reader(smartcard_channel, vheader);
+    smartcard_channel_write_to_reader(vheader);
     return TRUE;
 }
 
-static void smartcard_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
+static void smartcard_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 {
 }
 
@@ -496,12 +492,13 @@ static void smartcard_link(Channel *channel, RedsStream *stream,
                         uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
 {
-    if (g_smartcard_channel) {
-        red_channel_destroy(&g_smartcard_channel->base);
+    if (channel->data) {
+        red_channel_destroy((RedChannel*)channel->data);
+        channel->data = NULL;
     }
-    g_smartcard_channel =
-        (SmartCardChannel *)red_channel_create(sizeof(*g_smartcard_channel),
-                                        stream, core,
+    if (!channel->data) {
+        channel->data = red_channel_create(sizeof(SmartCardChannel),
+                                        core,
                                         migration, FALSE /* handle_acks */,
                                         smartcard_channel_config_socket,
                                         smartcard_channel_disconnect,
@@ -514,10 +511,13 @@ static void smartcard_link(Channel *channel, RedsStream *stream,
                                         NULL,
                                         NULL,
                                         NULL);
-    if (!g_smartcard_channel) {
+    }
+    if (!channel->data) {
+        red_printf("ERROR: smartcard channel creation failed");
         return;
     }
-    red_channel_init_outgoing_messages_window(&g_smartcard_channel->base);
+    red_channel_client_create(sizeof(RedChannelClient), channel->data, stream);
+    red_channel_init_outgoing_messages_window((RedChannel*)channel->data);
 }
 
 static void smartcard_shutdown(Channel *channel)
-- 
1.7.5.1



More information about the Spice-devel mailing list