[Spice-commits] 40 commits - common/ring.h common/spice_common.h server/inputs_channel.c server/main_channel.c server/red_channel.c server/red_channel.h server/red_client_cache.h server/red_client_shared_cache.h server/red_common.h server/red_tunnel_worker.c server/red_worker.c server/smartcard.c

Alon Levy alon at kemper.freedesktop.org
Wed Mar 2 07:28:21 PST 2011


 common/ring.h                    |   21 
 common/spice_common.h            |   70 ++
 server/inputs_channel.c          |   25 
 server/main_channel.c            |  150 ++--
 server/red_channel.c             |  279 +++++++--
 server/red_channel.h             |  125 +++-
 server/red_client_cache.h        |    2 
 server/red_client_shared_cache.h |    8 
 server/red_common.h              |   46 -
 server/red_tunnel_worker.c       |  232 +++----
 server/red_worker.c              | 1189 ++++++++++++++-------------------------
 server/smartcard.c               |   36 -
 12 files changed, 1064 insertions(+), 1119 deletions(-)

New commits:
commit 23ba2ce3e5707f50c8ee0dab276a62f85dbabf33
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Nov 13 16:54:12 2010 +0200

    server/red_worker: use red_channel_pipe_item_init
    
    replaces in file red_pipe_item_init.

diff --git a/server/red_client_cache.h b/server/red_client_cache.h
index 28f9955..a79944a 100644
--- a/server/red_client_cache.h
+++ b/server/red_client_cache.h
@@ -73,7 +73,7 @@ static void FUNC_NAME(remove)(CHANNEL *channel, CacheItem *item)
     channel->VAR_NAME(items)--;
     channel->VAR_NAME(available) += item->size;
 
-    red_pipe_item_init(&item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
+    red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
     red_pipe_add_tail(&channel->common.base, &item->u.pipe_data); // for now
 }
 
diff --git a/server/red_worker.c b/server/red_worker.c
index c6a49ce..83f1798 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1122,12 +1122,6 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
            draw_item->base.rgn.extents.y2);
 }
 
-static inline void red_pipe_item_init(PipeItem *item, int type)
-{
-    ring_item_init(&item->link);
-    item->type = type;
-}
-
 static inline int pipe_item_is_linked(PipeItem *item)
 {
     return ring_item_is_linked(&item->link);
@@ -1148,7 +1142,7 @@ static inline void red_pipe_add_tail(RedChannel *channel, PipeItem *item)
 static void red_pipe_add_verb(RedChannel* channel, uint16_t verb)
 {
     VerbItem *item = spice_new(VerbItem, 1);
-    red_pipe_item_init(&item->base, PIPE_ITEM_TYPE_VERB);
+    red_channel_pipe_item_init(channel, &item->base, PIPE_ITEM_TYPE_VERB);
     item->verb = verb;
     red_channel_pipe_add(channel, &item->base);
 }
@@ -1338,7 +1332,8 @@ static void drawables_init(RedWorker *worker)
 
 static void red_reset_stream_trace(RedWorker *worker);
 
-static SurfaceDestroyItem *get_surface_destroy_item(uint32_t surface_id)
+static SurfaceDestroyItem *get_surface_destroy_item(RedChannel *channel,
+                                                    uint32_t surface_id)
 {
     SurfaceDestroyItem *destroy;
 
@@ -1347,7 +1342,8 @@ static SurfaceDestroyItem *get_surface_destroy_item(uint32_t surface_id)
 
     destroy->surface_destroy.surface_id = surface_id;
 
-    red_pipe_item_init(&destroy->pipe_item, PIPE_ITEM_TYPE_DESTROY_SURFACE);
+    red_channel_pipe_item_init(channel,
+        &destroy->pipe_item, PIPE_ITEM_TYPE_DESTROY_SURFACE);
 
     return destroy;
 }
@@ -1355,16 +1351,15 @@ static SurfaceDestroyItem *get_surface_destroy_item(uint32_t surface_id)
 static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_id)
 {
     SurfaceDestroyItem *destroy;
+    RedChannel *channel;
 
     if (!worker->display_channel) {
         return;
     }
-
     worker->display_channel->surface_client_created[surface_id] = FALSE;
-
-    destroy = get_surface_destroy_item(surface_id);
-
-    red_channel_pipe_add(&worker->display_channel->common.base, &destroy->pipe_item);
+    channel = &worker->display_channel->common.base;
+    destroy = get_surface_destroy_item(channel, surface_id);
+    red_channel_pipe_add(channel, &destroy->pipe_item);
 }
 
 static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
@@ -2128,7 +2123,8 @@ static inline void red_detach_stream(RedWorker *worker, Stream *stream)
 static StreamClipItem *__new_stream_clip(DisplayChannel* channel, StreamAgent *agent)
 {
     StreamClipItem *item = spice_new(StreamClipItem, 1);
-    red_pipe_item_init((PipeItem *)item, PIPE_ITEM_TYPE_STREAM_CLIP);
+    red_channel_pipe_item_init(&channel->common.base,
+                    (PipeItem *)item, PIPE_ITEM_TYPE_STREAM_CLIP);
 
     item->stream_agent = agent;
     agent->stream->refs++;
@@ -2238,7 +2234,8 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
 
         upgrade_item = spice_new(UpgradeItem, 1);
         upgrade_item->refs = 1;
-        red_pipe_item_init(&upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
+        red_channel_pipe_item_init(&channel->common.base,
+                &upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
@@ -2459,8 +2456,10 @@ static void red_display_init_streams(DisplayChannel *display)
         StreamAgent *agent = &display->stream_agents[i];
         agent->stream = &display->common.worker->streams_buf[i];
         region_init(&agent->vis_region);
-        red_pipe_item_init(&agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
-        red_pipe_item_init(&agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
+        red_channel_pipe_item_init(&display->common.base,
+                    &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
+        red_channel_pipe_item_init(&display->common.base,
+                    &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
     }
 }
 
@@ -3238,7 +3237,8 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
     drawable->tree_item.base.type = TREE_ITEM_TYPE_DRAWABLE;
     region_init(&drawable->tree_item.base.rgn);
     drawable->tree_item.effect = effect;
-    red_pipe_item_init(&drawable->pipe_item, PIPE_ITEM_TYPE_DRAW);
+    red_channel_pipe_item_init(&worker->display_channel->common.base,
+        &drawable->pipe_item, PIPE_ITEM_TYPE_DRAW);
     drawable->red_drawable = red_drawable;
     drawable->group_id = group_id;
 
@@ -4122,7 +4122,8 @@ static CursorItem *get_cursor_item(RedWorker *worker, RedCursorCmd *cmd, uint32_
     PANIC_ON(!(cursor_item = alloc_cursor_item(worker)));
 
     cursor_item->refs = 1;
-    red_pipe_item_init(&cursor_item->pipe_data, PIPE_ITEM_TYPE_CURSOR);
+    red_channel_pipe_item_init(&worker->cursor_channel->common.base,
+                        &cursor_item->pipe_data, PIPE_ITEM_TYPE_CURSOR);
     cursor_item->type = CURSOR_TYPE_INVALID;
     cursor_item->group_id = group_id;
     cursor_item->red_cursor = cmd;
@@ -4350,7 +4351,8 @@ static ImageItem *red_add_surface_area_image(RedWorker *worker, int surface_id,
                                       
     item = (ImageItem *)spice_malloc_n_m(height, stride, sizeof(ImageItem));
 
-    red_pipe_item_init(&item->link, PIPE_ITEM_TYPE_IMAGE);
+    red_channel_pipe_item_init(&worker->display_channel->common.base,
+                               &item->link, PIPE_ITEM_TYPE_IMAGE);
 
     item->refs = 1;
     item->surface_id = surface_id;
@@ -8390,8 +8392,10 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
     };
 }
 
-static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t width,
-                                                  uint32_t height, uint32_t format, uint32_t flags)
+static SurfaceCreateItem *get_surface_create_item(
+    RedChannel* channel,
+    uint32_t surface_id, uint32_t width,
+    uint32_t height, uint32_t format, uint32_t flags)
 {
     SurfaceCreateItem *create;
 
@@ -8404,8 +8408,8 @@ static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t
     create->surface_create.flags = flags;
     create->surface_create.format = format;
 
-    red_pipe_item_init(&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
-
+    red_channel_pipe_item_init(channel,
+            &create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
     return create;
 }
 
@@ -8420,7 +8424,8 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
 
     surface = &worker->surfaces[surface_id];
 
-    create = get_surface_create_item(surface_id, surface->context.width, surface->context.height,
+    create = get_surface_create_item(&worker->display_channel->common.base,
+            surface_id, surface->context.width, surface->context.height,
                                      surface->context.format, flags);
 
     worker->display_channel->surface_client_created[surface_id] = TRUE;
@@ -9315,13 +9320,15 @@ typedef struct __attribute__ ((__packed__)) CursorData {
     SpiceCursor _cursor;
 } CursorData;
 
-static LocalCursor *_new_local_cursor(SpiceCursorHeader *header, int data_size, SpicePoint16 position)
+static LocalCursor *_new_local_cursor(RedChannel *channel,
+    SpiceCursorHeader *header, int data_size, SpicePoint16 position)
 {
     LocalCursor *local;
 
     local = (LocalCursor *)spice_malloc0(sizeof(LocalCursor) + data_size);
 
-    red_pipe_item_init(&local->base.pipe_data, PIPE_ITEM_TYPE_LOCAL_CURSOR);
+    red_channel_pipe_item_init(channel, &local->base.pipe_data,
+                               PIPE_ITEM_TYPE_LOCAL_CURSOR);
     local->base.refs = 1;
     local->base.type = CURSOR_TYPE_LOCAL;
 
@@ -9352,7 +9359,8 @@ static void red_cursor_flush(RedWorker *worker)
     ASSERT(cursor_cmd->type == QXL_CURSOR_SET);
     cursor = &cursor_cmd->u.set.shape;
 
-    local = _new_local_cursor(&cursor->header, cursor->data_size,
+    local = _new_local_cursor(&worker->cursor_channel->common.base,
+                              &cursor->header, cursor->data_size,
                               worker->cursor_position);
     ASSERT(local);
     memcpy(local->red_cursor.data, cursor->data, local->data_size);
commit c7711822749fd46d92a40f485d9e8ffabcd58ad0
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 14:39:28 2010 +0200

    server/red_channel: move out_bytes_counter from Outgoing to RedChannel

diff --git a/server/red_channel.c b/server/red_channel.c
index 783fa48..2585498 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -186,7 +186,7 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
             }
         } else {
             handler->pos += n;
-            stat_inc_counter(handler->out_bytes_counter, n);
+            handler->cb->on_output(handler->opaque, n);
             if (handler->pos == handler->size) { // finished writing data
                 handler->cb->on_msg_done(handler->opaque);
                 handler->vec = handler->vec_buf;
@@ -198,6 +198,13 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
     }
 }
 
+void red_channel_on_output(void *opaque, int n)
+{
+    RedChannel *channel = opaque;
+
+    stat_inc_counter(channel->out_bytes_counter, n);
+}
+
 void red_channel_default_peer_on_error(RedChannel *channel)
 {
     channel->disconnect(channel);
@@ -359,18 +366,19 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
     channel->outgoing.opaque = channel;
     channel->outgoing.pos = 0;
     channel->outgoing.size = 0;
-    channel->outgoing.out_bytes_counter = NULL;
 
     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->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->shut = 0; // came here from inputs, perhaps can be removed? XXX
+    channel->out_bytes_counter = 0;
 
     if (!config_socket(channel)) {
         goto error;
diff --git a/server/red_channel.h b/server/red_channel.h
index 7ec0734..97da5a8 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -69,6 +69,7 @@ typedef void (*prepare_outgoing_proc)(void *opaque, struct iovec *vec, int *vec_
 typedef void (*on_outgoing_error_proc)(void *opaque);
 typedef void (*on_outgoing_block_proc)(void *opaque);
 typedef void (*on_outgoing_msg_done_proc)(void *opaque);
+typedef void (*on_output_proc)(void *opaque, int n);
 
 typedef struct OutgoingHandlerInterface {
     get_outgoing_msg_size_proc get_msg_size;
@@ -76,6 +77,7 @@ typedef struct OutgoingHandlerInterface {
     on_outgoing_error_proc on_error;
     on_outgoing_block_proc on_block;
     on_outgoing_msg_done_proc on_msg_done;
+    on_output_proc on_output;
 } OutgoingHandlerInterface;
 
 typedef struct OutgoingHandler {
@@ -86,9 +88,6 @@ typedef struct OutgoingHandler {
     struct iovec *vec;
     int pos;
     int size;
-#ifdef RED_STATISTICS
-    uint64_t *out_bytes_counter;
-#endif
 } OutgoingHandler;
 
 /* Red Channel interface */
@@ -184,6 +183,9 @@ struct RedChannel {
     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;
+#ifdef RED_STATISTICS
+    uint64_t *out_bytes_counter;
+#endif
 };
 
 /* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
diff --git a/server/red_worker.c b/server/red_worker.c
index 446c72e..c6a49ce 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9163,7 +9163,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, in
     }
 #ifdef RED_STATISTICS
     display_channel->stat = stat_add_node(worker->stat, "display_channel", TRUE);
-    display_channel->common.base.outgoing.out_bytes_counter = stat_add_counter(display_channel->stat,
+    display_channel->common.base.out_bytes_counter = stat_add_counter(display_channel->stat,
                                                                "out_bytes", TRUE);
     display_channel->cache_hits_counter = stat_add_counter(display_channel->stat,
                                                            "cache_hits", TRUE);
@@ -9298,7 +9298,7 @@ static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrat
     }
 #ifdef RED_STATISTICS
     channel->stat = stat_add_node(worker->stat, "cursor_channel", TRUE);
-    channel->common.base.outgoing.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
+    channel->common.base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
 #endif
     ring_init(&channel->cursor_cache_lru);
     channel->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
commit 692b41f946a598bb459419bb94f4fb55474dd55e
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 12:54:14 2010 +0200

    server/red_channel: split Incoming/Outgoing to callback and state
    
    This allows later to have the callback table under RedChannel when
    the callbacks actually get used by RedChannelClient. Since the cb's
    are identical for different clients of the same channel it makes sense
    to store the callback pointers in one place per channel. The rest of
    the incoming and outgoing struct just gets moved to RedChannelClient.

diff --git a/server/red_channel.c b/server/red_channel.c
index 0a36698..783fa48 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -84,7 +84,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           ((uint8_t *)&handler->header) + handler->header_pos,
                                           sizeof(SpiceDataHeader) - handler->header_pos);
             if (bytes_read == -1) {
-                handler->on_error(handler->opaque);
+                handler->cb->on_error(handler->opaque);
                 return;
             }
             handler->header_pos += bytes_read;
@@ -96,10 +96,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
 
         if (handler->msg_pos < handler->header.size) {
             if (!handler->msg) {
-                handler->msg = handler->alloc_msg_buf(handler->opaque, &handler->header);
+                handler->msg = handler->cb->alloc_msg_buf(handler->opaque, &handler->header);
                 if (handler->msg == NULL) {
                     red_printf("ERROR: channel refused to allocate buffer.");
-                    handler->on_error(handler->opaque);
+                    handler->cb->on_error(handler->opaque);
                     return;
                 }
             }
@@ -108,8 +108,8 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->msg + handler->msg_pos,
                                           handler->header.size - handler->msg_pos);
             if (bytes_read == -1) {
-                handler->release_msg_buf(handler->opaque, &handler->header, handler->msg);
-                handler->on_error(handler->opaque);
+                handler->cb->release_msg_buf(handler->opaque, &handler->header, handler->msg);
+                handler->cb->on_error(handler->opaque);
                 return;
             }
             handler->msg_pos += bytes_read;
@@ -118,24 +118,24 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             }
         }
 
-        if (handler->parser) {
-            parsed = handler->parser(handler->msg,
+        if (handler->cb->parser) {
+            parsed = handler->cb->parser(handler->msg,
                 handler->msg + handler->header.size, handler->header.type,
                 SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
             if (parsed == NULL) {
                 red_printf("failed to parse message type %d", handler->header.type);
-                handler->on_error(handler->opaque);
+                handler->cb->on_error(handler->opaque);
                 return;
             }
-            ret_handle = handler->handle_parsed(handler->opaque, parsed_size,
+            ret_handle = handler->cb->handle_parsed(handler->opaque, parsed_size,
                                     handler->header.type, parsed);
             parsed_free(parsed);
         } else {
-            ret_handle = handler->handle_message(handler->opaque, &handler->header,
+            ret_handle = handler->cb->handle_message(handler->opaque, &handler->header,
                                                  handler->msg);
         }
         if (handler->shut) {
-            handler->on_error(handler->opaque);
+            handler->cb->on_error(handler->opaque);
             return;
         }
         handler->msg_pos = 0;
@@ -143,7 +143,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         handler->header_pos = 0;
 
         if (!ret_handle) {
-            handler->on_error(handler->opaque);
+            handler->cb->on_error(handler->opaque);
             return;
         }
     }
@@ -160,35 +160,35 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
 
     if (handler->size == 0) {
         handler->vec = handler->vec_buf;
-        handler->size = handler->get_msg_size(handler->opaque);
+        handler->size = handler->cb->get_msg_size(handler->opaque);
         if (!handler->size) {  // nothing to be sent
             return;
         }
     }
 
     for (;;) {
-        handler->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
+        handler->cb->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
         n = reds_stream_writev(stream, handler->vec, handler->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
-                handler->on_block(handler->opaque);
+                handler->cb->on_block(handler->opaque);
                 return;
             case EINTR:
                 continue;
             case EPIPE:
-                handler->on_error(handler->opaque);
+                handler->cb->on_error(handler->opaque);
                 return;
             default:
                 red_printf("%s", strerror(errno));
-                handler->on_error(handler->opaque);
+                handler->cb->on_error(handler->opaque);
                 return;
             }
         } else {
             handler->pos += n;
             stat_inc_counter(handler->out_bytes_counter, n);
             if (handler->pos == handler->size) { // finished writing data
-                handler->on_msg_done(handler->opaque);
+                handler->cb->on_msg_done(handler->opaque);
                 handler->vec = handler->vec_buf;
                 handler->pos = 0;
                 handler->size = 0;
@@ -351,21 +351,24 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
     channel->send_data.marshaller = spice_marshaller_new();
 
     channel->incoming.opaque = channel;
-    channel->incoming.alloc_msg_buf = (alloc_msg_recv_buf_proc)alloc_recv_buf;
-    channel->incoming.release_msg_buf = (release_msg_recv_buf_proc)release_recv_buf;
-    channel->incoming.handle_message = (handle_message_proc)handle_message;
-    channel->incoming.on_error = (on_incoming_error_proc)red_channel_default_peer_on_error;
+    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.out_bytes_counter = NULL;
 
-    channel->outgoing.get_msg_size = red_channel_peer_get_out_msg_size;
-    channel->outgoing.prepare = red_channel_peer_prepare_out_msg;
-    channel->outgoing.on_block = red_channel_peer_on_out_block;
-    channel->outgoing.on_error = (on_outgoing_error_proc)red_channel_default_peer_on_error;
-    channel->outgoing.on_msg_done = red_channel_peer_on_out_msg_done;
+    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->outgoing_cb.on_msg_done = red_channel_peer_on_out_msg_done;
+
+    channel->incoming.cb = &channel->incoming_cb;
+    channel->outgoing.cb = &channel->outgoing_cb;
 
     channel->shut = 0; // came here from inputs, perhaps can be removed? XXX
 
@@ -422,12 +425,12 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
     if (channel == NULL) {
         return NULL;
     }
-    channel->incoming.handle_parsed = (handle_parsed_proc)handle_parsed;
-    channel->incoming.parser = parser;
+    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.on_error = (on_incoming_error_proc)red_channel_peer_on_incoming_error;
-    channel->outgoing.on_error = (on_outgoing_error_proc)red_channel_peer_on_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;
     return channel;
 }
 
diff --git a/server/red_channel.h b/server/red_channel.h
index 15c3b3c..7ec0734 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -44,12 +44,7 @@ typedef void (*release_msg_recv_buf_proc)(void *opaque,
                                           SpiceDataHeader *msg_header, uint8_t *msg);
 typedef void (*on_incoming_error_proc)(void *opaque);
 
-typedef struct IncomingHandler {
-    void *opaque;
-    SpiceDataHeader header;
-    uint32_t header_pos;
-    uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
-    uint32_t msg_pos;
+typedef struct IncomingHandlerInterface {
     handle_message_proc handle_message;
     alloc_msg_recv_buf_proc alloc_msg_buf;
     on_incoming_error_proc on_error; // recv error or handle_message error
@@ -57,6 +52,15 @@ typedef struct IncomingHandler {
     // The following is an optional alternative to handle_message, used if not null
     spice_parse_channel_func_t parser;
     handle_parsed_proc handle_parsed;
+} IncomingHandlerInterface;
+
+typedef struct IncomingHandler {
+    IncomingHandlerInterface *cb;
+    void *opaque;
+    SpiceDataHeader header;
+    uint32_t header_pos;
+    uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
+    uint32_t msg_pos;
     int shut; // came here from inputs_channel. Not sure if it is really required or can be removed. XXX
 } IncomingHandler;
 
@@ -65,18 +69,23 @@ typedef void (*prepare_outgoing_proc)(void *opaque, struct iovec *vec, int *vec_
 typedef void (*on_outgoing_error_proc)(void *opaque);
 typedef void (*on_outgoing_block_proc)(void *opaque);
 typedef void (*on_outgoing_msg_done_proc)(void *opaque);
+
+typedef struct OutgoingHandlerInterface {
+    get_outgoing_msg_size_proc get_msg_size;
+    prepare_outgoing_proc prepare;
+    on_outgoing_error_proc on_error;
+    on_outgoing_block_proc on_block;
+    on_outgoing_msg_done_proc on_msg_done;
+} OutgoingHandlerInterface;
+
 typedef struct OutgoingHandler {
+    OutgoingHandlerInterface *cb;
     void *opaque;
     struct iovec vec_buf[MAX_SEND_VEC];
     int vec_size;
     struct iovec *vec;
     int pos;
     int size;
-    get_outgoing_msg_size_proc get_msg_size;
-    prepare_outgoing_proc prepare;
-    on_outgoing_error_proc on_error;
-    on_outgoing_block_proc on_block;
-    on_outgoing_msg_done_proc on_msg_done;
 #ifdef RED_STATISTICS
     uint64_t *out_bytes_counter;
 #endif
@@ -157,6 +166,9 @@ struct RedChannel {
     OutgoingHandler outgoing;
     IncomingHandler incoming;
 
+    OutgoingHandlerInterface outgoing_cb;
+    IncomingHandlerInterface incoming_cb;
+
     channel_disconnect_proc disconnect;
     channel_send_pipe_item_proc send_item;
     channel_hold_pipe_item_proc hold_item;
commit d1feaeb2820c7566c6d82a2e7dbb62d237eeb440
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 11:18:30 2010 +0200

    server/red_channel: no opaque in red_channel_peer_on_*_error

diff --git a/server/red_channel.c b/server/red_channel.c
index 18c7f35..0a36698 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -203,17 +203,13 @@ void red_channel_default_peer_on_error(RedChannel *channel)
     channel->disconnect(channel);
 }
 
-static void red_channel_peer_on_incoming_error(void *opaque)
+static void red_channel_peer_on_incoming_error(RedChannel *channel)
 {
-    RedChannel *channel = (RedChannel *)opaque;
-
     channel->on_incoming_error(channel);
 }
 
-static void red_channel_peer_on_outgoing_error(void *opaque)
+static void red_channel_peer_on_outgoing_error(RedChannel *channel)
 {
-    RedChannel *channel = (RedChannel *)opaque;
-
     channel->on_outgoing_error(channel);
 }
 
@@ -430,8 +426,8 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
     channel->incoming.parser = parser;
     channel->on_incoming_error = incoming_error;
     channel->on_outgoing_error = outgoing_error;
-    channel->incoming.on_error = red_channel_peer_on_incoming_error;
-    channel->outgoing.on_error = red_channel_peer_on_outgoing_error;
+    channel->incoming.on_error = (on_incoming_error_proc)red_channel_peer_on_incoming_error;
+    channel->outgoing.on_error = (on_outgoing_error_proc)red_channel_peer_on_outgoing_error;
     return channel;
 }
 
commit b5ae7133c000c392c2c402b77707f03e179d8477
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 11:11:01 2010 +0200

    server/red_worker: use red_channel_is_connected

diff --git a/server/red_worker.c b/server/red_worker.c
index 14e8fef..446c72e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8269,7 +8269,7 @@ static void red_disconnect_display(RedChannel *channel)
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     RedWorker *worker;
 
-    if (!channel || !channel->stream) {
+    if (!channel || !red_channel_is_connected(channel)) {
         return;
     }
     worker = common->worker;
@@ -8601,7 +8601,7 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
     uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
     for (;;) {
         red_channel_receive((RedChannel *)display_channel);
-        if (!display_channel->common.base.stream) {
+        if (!red_channel_is_connected(&display_channel->common.base)) {
             break;
         }
         if (display_channel->pixmap_cache && display_channel->glz_dict) {
@@ -9227,7 +9227,7 @@ static void red_disconnect_cursor(RedChannel *channel)
 {
     CommonChannel *common;
 
-    if (!channel || !channel->stream) {
+    if (!channel || !red_channel_is_connected(channel)) {
         return;
     }
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
commit 7890b623b55cba6e0b3e99322d377633d94127d6
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 10:42:25 2010 +0200

    server/red_channel: add red_channel_disconnect, use in red_worker
    
    replace channel_release_res in red_worker with red_channel_disconnect.

diff --git a/server/red_channel.c b/server/red_channel.c
index 4330236..18c7f35 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -751,3 +751,12 @@ int red_channel_no_item_being_sent(RedChannel *channel)
 {
     return channel->send_data.item == NULL;
 }
+
+void red_channel_disconnect(RedChannel *channel)
+{
+    red_channel_pipe_clear(channel);
+    reds_stream_free(channel->stream);
+    channel->stream = NULL;
+    channel->send_data.blocked = FALSE;
+    channel->send_data.size = 0;
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index d08b661..15c3b3c 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -286,6 +286,8 @@ void red_channel_pipe_clear(RedChannel *channel);
 //  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_send(RedChannel *channel);
+// For red_worker
+void red_channel_disconnect(RedChannel *channel);
 
 /* accessors for RedChannel */
 /* Note: the valid times to call red_channel_get_marshaller are just during send_item callback. */
diff --git a/server/red_worker.c b/server/red_worker.c
index d9b7032..14e8fef 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7182,15 +7182,6 @@ static inline void red_marshall_qxl_drawable(RedWorker *worker, DisplayChannel *
     }
 }
 
-static void inline channel_release_res(RedChannel *channel)
-{
-    if (!channel->send_data.item) {
-        return;
-    }
-    channel->release_item(channel, channel->send_data.item, FALSE);
-    channel->send_data.item = NULL;
-}
-
 static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
                                          uint64_t* sync_data)
 {
@@ -8268,12 +8259,7 @@ void red_show_tree(RedWorker *worker)
 // TODO: move to red_channel
 static void red_disconnect_channel(RedChannel *channel)
 {
-    channel_release_res(channel);
-    red_channel_pipe_clear(channel);
-    reds_stream_free(channel->stream);
-    channel->stream = NULL;
-    channel->send_data.blocked = FALSE;
-    channel->send_data.size = 0;
+    red_channel_disconnect(channel);
     red_unref_channel(channel);
 }
 
commit aa5d23fdecaec827ab0f7fc736e31ef1ffd6502e
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Nov 12 10:41:37 2010 +0200

    server/red_channel: reset send_data.item to NULL after release

diff --git a/server/red_channel.c b/server/red_channel.c
index 8eb4e0d..4330236 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -683,6 +683,7 @@ void red_channel_pipe_clear(RedChannel *channel)
     ASSERT(channel);
     if (channel->send_data.item) {
         red_channel_release_item(channel, channel->send_data.item, TRUE);
+        channel->send_data.item = NULL;
     }
     while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
         ring_remove(&item->link);
commit d4c187c0434d0da99a905174ad358dd939fb5976
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 21:06:42 2010 +0200

    server/red_worker: remove RedChannel argument from add_buf_from_info
    
    It was unused.

diff --git a/server/red_worker.c b/server/red_worker.c
index b5bb3b3..d9b7032 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4432,7 +4432,7 @@ static void marshaller_add_compressed(RedWorker *worker, SpiceMarshaller *m,
 }
 
 
-static void add_buf_from_info(RedChannel *channel, SpiceMarshaller *m, AddBufInfo *info)
+static void add_buf_from_info(SpiceMarshaller *m, AddBufInfo *info)
 {
     if (info->data) {
         switch (info->type) {
@@ -7929,7 +7929,7 @@ static void red_marshall_cursor_init(CursorChannel *channel, SpiceMarshaller *ba
 
     fill_cursor(channel, &msg.cursor, worker->cursor, &info);
     spice_marshall_msg_cursor_init(base_marshaller, &msg);
-    add_buf_from_info(&channel->common.base, base_marshaller, &info);
+    add_buf_from_info(base_marshaller, &info);
 }
 
 static void red_marshall_local_cursor(CursorChannel *cursor_channel,
@@ -7949,7 +7949,7 @@ static void red_marshall_local_cursor(CursorChannel *cursor_channel,
 
     fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
     spice_marshall_msg_cursor_set(base_marshaller, &cursor_set);
-    add_buf_from_info(channel, base_marshaller, &info);
+    add_buf_from_info(base_marshaller, &info);
     red_release_cursor(worker, (CursorItem *)cursor);
 }
 
@@ -7997,7 +7997,7 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
 
             fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
             spice_marshall_msg_cursor_set(m, &cursor_set);
-            add_buf_from_info(channel, m, &info);
+            add_buf_from_info(m, &info);
             break;
         }
     case QXL_CURSOR_HIDE:
commit 5575d6e5fac35e92ccc563c82e6cd98031388081
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 19:15:45 2010 +0200

    server/red_channel: add red_channel_{,no_}item_being_sent

diff --git a/server/red_channel.c b/server/red_channel.c
index f2665a4..8eb4e0d 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -727,6 +727,12 @@ RedsStream *red_channel_get_stream(RedChannel *channel)
     return channel->stream;
 }
 
+SpiceDataHeader *red_channel_get_header(RedChannel *channel)
+{
+    return channel->send_data.header;
+}
+/* end of accessors */
+
 int red_channel_get_first_socket(RedChannel *channel)
 {
     if (!channel->stream) {
@@ -735,7 +741,12 @@ int red_channel_get_first_socket(RedChannel *channel)
     return channel->stream->socket;
 }
 
-SpiceDataHeader *red_channel_get_header(RedChannel *channel)
+int red_channel_item_being_sent(RedChannel *channel, PipeItem *item)
 {
-    return channel->send_data.header;
+    return channel->send_data.item == item;
+}
+
+int red_channel_no_item_being_sent(RedChannel *channel)
+{
+    return channel->send_data.item == NULL;
 }
diff --git a/server/red_channel.h b/server/red_channel.h
index ce8ef20..d08b661 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -260,6 +260,14 @@ int red_channel_any_blocked(RedChannel *channel);
 /* helper for channels that have complex logic that can possibly ready a send */
 int red_channel_send_message_pending(RedChannel *channel);
 
+/* 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
+ * hasn't even begun, i.e. no one called begin_send_)
+ * */
+int red_channel_item_being_sent(RedChannel *channel, PipeItem *item);
+
+int red_channel_no_item_being_sent(RedChannel *channel);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
diff --git a/server/red_worker.c b/server/red_worker.c
index 357ddee..b5bb3b3 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9436,7 +9436,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
         red_printf("timeout");
         channel->disconnect(channel);
     } else {
-        if (channel->send_data.item == item) {
+        if (red_channel_item_being_sent(channel, item)) {
             red_wait_outgoing_item(channel);
         }
     }
@@ -9522,7 +9522,7 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
     // there is one during sending.
     red_wait_outgoing_item((RedChannel *)worker->display_channel);
     if (worker->display_channel) {
-        ASSERT(!worker->display_channel->common.base.send_data.item);
+        ASSERT(red_channel_no_item_being_sent(&worker->display_channel->common.base));
     }
 }
 
@@ -9570,7 +9570,7 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
         if (!worker->cursor_channel->common.base.migrate) {
             red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
-        ASSERT(!worker->cursor_channel->common.base.send_data.item);
+        ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
     }
 
     if (worker->display_channel) {
@@ -9646,7 +9646,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
         if (!worker->cursor_channel->common.base.migrate) {
             red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
-        ASSERT(!worker->cursor_channel->common.base.send_data.item);
+        ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
     }
 
     flush_all_qxl_commands(worker);
@@ -9708,7 +9708,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
             if (!cursor_red_channel->migrate) {
                 red_pipe_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
             }
-            ASSERT(!cursor_red_channel->send_data.item);
+            ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
 
             worker->cursor_visible = TRUE;
             worker->cursor_position.x = worker->cursor_position.y = 0;
commit 17ebd6a71946b456345b2f997861a55535e9c39d
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 18:39:02 2010 +0200

    server/red_worker: complete removal of send_data.marshaller use

diff --git a/server/red_worker.c b/server/red_worker.c
index a841f71..357ddee 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -924,7 +924,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);
+static inline void display_begin_send_message(DisplayChannel *channel, 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);
@@ -7215,9 +7215,10 @@ 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)
+static inline void display_begin_send_message(DisplayChannel *channel, SpiceMarshaller *base_marshaller)
 {
     FreeList *free_list = &channel->send_data.free_list;
+    SpiceDataHeader *header = red_channel_get_header(&channel->common.base);
 
     if (free_list->res->count) {
         int sub_list_len = 1;
@@ -7226,7 +7227,7 @@ static inline void display_begin_send_message(DisplayChannel *channel)
         int sync_count = 0;
         int i;
 
-        inval_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
+        inval_m = spice_marshaller_get_submarshaller(base_marshaller);
 
         /* type + size + submessage */
         spice_marshaller_add_uint16(inval_m, SPICE_MSG_DISPLAY_INVAL_LIST);
@@ -7244,7 +7245,7 @@ static inline void display_begin_send_message(DisplayChannel *channel)
         free_list->wait.header.wait_count = sync_count;
 
         if (sync_count) {
-            wait_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
+            wait_m = spice_marshaller_get_submarshaller(base_marshaller);
 
             /* type + size + submessage */
             spice_marshaller_add_uint16(wait_m, SPICE_MSG_WAIT_FOR_CHANNELS);
@@ -7254,13 +7255,13 @@ static inline void display_begin_send_message(DisplayChannel *channel)
             sub_list_len++;
         }
 
-        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
+        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(base_marshaller);
         spice_marshaller_add_uint16(sub_list_m, sub_list_len);
         if (wait_m) {
             spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
         }
         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
-        channel->common.base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
+        header->sub_list = spice_marshaller_get_offset(sub_list_m);
     }
     red_channel_begin_send_message((RedChannel *)channel);
 }
@@ -7605,7 +7606,8 @@ static void display_channel_marshall_migrate(DisplayChannel *display_channel, Sp
     display_channel->expect_migrate_mark = TRUE;
 }
 
-static void display_channel_marshall_migrate_data(DisplayChannel *display_channel)
+static void display_channel_marshall_migrate_data(DisplayChannel *display_channel,
+                                                  SpiceMarshaller *base_marshaller)
 {
     DisplayChannelMigrateData display_data;
 
@@ -7631,11 +7633,12 @@ static void display_channel_marshall_migrate_data(DisplayChannel *display_channe
                                         &display_data.glz_dict_restore_data,
                                         &display_channel->glz_data.usr);
 
-    spice_marshaller_add_ref(display_channel->common.base.send_data.marshaller,
+    spice_marshaller_add_ref(base_marshaller,
                              (uint8_t *)&display_data, sizeof(display_data));
 }
 
-static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel)
+static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel,
+                                                 SpiceMarshaller *base_marshaller)
 {
     SpiceMsgWaitForChannels wait;
     PixmapCache *pixmap_cache;
@@ -7654,17 +7657,18 @@ static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel
 
     pthread_mutex_unlock(&pixmap_cache->lock);
 
-    spice_marshall_msg_wait_for_channels(display_channel->common.base.send_data.marshaller, &wait);
+    spice_marshall_msg_wait_for_channels(base_marshaller, &wait);
 }
 
-static void display_channel_marshall_reset_cache(DisplayChannel *display_channel)
+static void display_channel_marshall_reset_cache(DisplayChannel *display_channel,
+                                                 SpiceMarshaller *base_marshaller)
 {
     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);
 
-    spice_marshall_msg_display_inval_all_pixmaps(display_channel->common.base.send_data.marshaller,
+    spice_marshall_msg_display_inval_all_pixmaps(base_marshaller,
                                                  &wait);
 }
 
@@ -7907,7 +7911,7 @@ static void red_cursor_marshall_inval(CursorChannel *channel,
     red_marshall_inval((RedChannel *)channel, m, cach_item);
 }
 
-static void red_marshall_cursor_init(CursorChannel *channel)
+static void red_marshall_cursor_init(CursorChannel *channel, SpiceMarshaller *base_marshaller)
 {
     RedWorker *worker;
     SpiceMsgCursorInit msg;
@@ -7924,8 +7928,8 @@ static void red_marshall_cursor_init(CursorChannel *channel)
     msg.trail_frequency = worker->cursor_trail_frequency;
 
     fill_cursor(channel, &msg.cursor, worker->cursor, &info);
-    spice_marshall_msg_cursor_init(channel->common.base.send_data.marshaller, &msg);
-    add_buf_from_info(&channel->common.base, channel->common.base.send_data.marshaller, &info);
+    spice_marshall_msg_cursor_init(base_marshaller, &msg);
+    add_buf_from_info(&channel->common.base, base_marshaller, &info);
 }
 
 static void red_marshall_local_cursor(CursorChannel *cursor_channel,
@@ -7949,14 +7953,15 @@ static void red_marshall_local_cursor(CursorChannel *cursor_channel,
     red_release_cursor(worker, (CursorItem *)cursor);
 }
 
-static void cursor_channel_marshall_migrate(CursorChannel *cursor_channel)
+static void cursor_channel_marshall_migrate(CursorChannel *cursor_channel,
+                                            SpiceMarshaller *base_marshaller)
 {
     SpiceMsgMigrate migrate;
 
     red_channel_init_send_data(&cursor_channel->common.base, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = 0;
 
-    spice_marshall_msg_migrate(cursor_channel->common.base.send_data.marshaller, &migrate);
+    spice_marshall_msg_migrate(base_marshaller, &migrate);
 }
 
 static void red_marshall_cursor(CursorChannel *cursor_channel,
@@ -8096,7 +8101,7 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        display_channel_marshall_migrate_data(display_channel);
+        display_channel_marshall_migrate_data(display_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_IMAGE:
@@ -8104,11 +8109,11 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         release_image_item((ImageItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-        display_channel_marshall_pixmap_sync(display_channel);
+        display_channel_marshall_pixmap_sync(display_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
-        display_channel_marshall_reset_cache(display_channel);
+        display_channel_marshall_reset_cache(display_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
@@ -8135,7 +8140,7 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     }
     // a message is pending
     if (red_channel_send_message_pending(&display_channel->common.base)) {
-        display_begin_send_message(display_channel);
+        display_begin_send_message(display_channel, m);
     }
     red_unref_channel(&display_channel->common.base);
 }
@@ -8163,12 +8168,12 @@ static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        cursor_channel_marshall_migrate(cursor_channel);
+        cursor_channel_marshall_migrate(cursor_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
         red_reset_cursor_cache(cursor_channel);
-        red_marshall_cursor_init(cursor_channel);
+        red_marshall_cursor_init(cursor_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
commit 992252104c84d97aa0684ee92b8095dfe555da27
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 17:24:57 2010 +0200

    server/red_worker: replace _send_ functions by _marshall_
    
    Changes in display channel for a code size win.
    
    A note about this and the previous cursor change: it will appear that we are
    now (with these changes) releasing resources too early. This is not so - send
    always has the option of blocking, which means after send you can not release
    resources anyway, that's what the release_item callback is for. So both the
    code before and now are doing the same accounting.

diff --git a/server/red_worker.c b/server/red_worker.c
index 41c53c4..a841f71 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -6290,7 +6290,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
     }
 }
 
-static void red_send_qxl_draw_fill(RedWorker *worker,
+static void red_marshall_qxl_draw_fill(RedWorker *worker,
                                    DisplayChannel *display_channel,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
@@ -6348,7 +6348,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_send_qxl_draw_fill(worker, display_channel, m, item);
+        red_marshall_qxl_draw_fill(worker, display_channel, 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);
@@ -6374,7 +6374,7 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
     }
 }
 
-static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
+static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
                                              DisplayChannel *display_channel,
                                              SpiceMarshaller *base_marshaller,
                                              Drawable *item, int src_allowed_lossy)
@@ -6441,7 +6441,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_send_qxl_draw_opaque(worker, display_channel, m, item, src_allowed_lossy);
+        src_send_type = red_marshall_qxl_draw_opaque(worker, display_channel, m, item, src_allowed_lossy);
 
         if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
             src_is_lossy = TRUE;
@@ -6472,7 +6472,7 @@ static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
     }
 }
 
-static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
+static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
                                            DisplayChannel *display_channel,
                                            SpiceMarshaller *base_marshaller,
                                            Drawable *item, int src_allowed_lossy)
@@ -6512,7 +6512,7 @@ static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.copy.src_bitmap,
                                    &drawable->u.copy.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_send_qxl_draw_copy(worker, display_channel, base_marshaller, item, TRUE);
+    src_send_type = red_marshall_qxl_draw_copy(worker, display_channel, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6524,7 +6524,7 @@ static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
                                 src_is_lossy);
 }
 
-static void red_send_qxl_draw_transparent(RedWorker *worker,
+static void red_marshall_qxl_draw_transparent(RedWorker *worker,
                                           DisplayChannel *display_channel,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
@@ -6556,7 +6556,7 @@ static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
                                    &drawable->u.transparent.src_area, item, &src_bitmap_data);
 
     if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
-        red_send_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
 
         // don't update surface lossy region since transperent areas might be lossy
     } else {
@@ -6571,7 +6571,7 @@ static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
     }
 }
 
-static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
+static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
                                                   DisplayChannel *display_channel,
                                                   SpiceMarshaller *base_marshaller,
                                                   Drawable *item,
@@ -6607,7 +6607,7 @@ static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.alpha_blend.src_bitmap,
                                    &drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_send_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item, TRUE);
+    src_send_type = red_marshall_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6620,7 +6620,7 @@ static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
     } // else, the area stays lossy/lossless as the destination
 }
 
-static void red_send_qxl_copy_bits(RedWorker *worker,
+static void red_marshall_qxl_copy_bits(RedWorker *worker,
                                    DisplayChannel *display_channel,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
@@ -6648,7 +6648,7 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
     int src_is_lossy;
     SpiceRect src_lossy_area;
 
-    red_send_qxl_copy_bits(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_copy_bits(worker, display_channel, 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;
@@ -6665,7 +6665,7 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
                                 src_is_lossy);
 }
 
-static void red_send_qxl_draw_blend(RedWorker *worker,
+static void red_marshall_qxl_draw_blend(RedWorker *worker,
                                     DisplayChannel *display_channel,
                                     SpiceMarshaller *base_marshaller,
                                     Drawable *item)
@@ -6707,7 +6707,7 @@ static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
 
     if (!dest_is_lossy &&
         (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_send_qxl_draw_blend(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_blend(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6730,7 +6730,7 @@ static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
     }
 }
 
-static void red_send_qxl_draw_blackness(RedWorker *worker,
+static void red_marshall_qxl_draw_blackness(RedWorker *worker,
                                         DisplayChannel *display_channel,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
@@ -6759,12 +6759,12 @@ static void red_lossy_send_qxl_draw_blackness(RedWorker *worker,
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
-    red_send_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
-static void red_send_qxl_draw_whiteness(RedWorker *worker,
+static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
                                         DisplayChannel *display_channel,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
@@ -6793,12 +6793,12 @@ static void red_lossy_send_qxl_draw_whiteness(RedWorker *worker,
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
-    red_send_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
-static void red_send_qxl_draw_inverse(RedWorker *worker,
+static void red_marshall_qxl_draw_inverse(RedWorker *worker,
                                         DisplayChannel *display_channel,
                                         SpiceMarshaller *base_marshaller,
                                         Drawable *item)
@@ -6824,10 +6824,10 @@ static void red_lossy_send_qxl_draw_inverse(RedWorker *worker,
                                             SpiceMarshaller *base_marshaller,
                                             Drawable *item)
 {
-    red_send_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
+    red_marshall_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
 }
 
-static void red_send_qxl_draw_rop3(RedWorker *worker,
+static void red_marshall_qxl_draw_rop3(RedWorker *worker,
                                    DisplayChannel *display_channel,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
@@ -6880,7 +6880,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_send_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
 
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
@@ -6911,7 +6911,7 @@ static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
     }
 }
 
-static void red_send_qxl_draw_stroke(RedWorker *worker,
+static void red_marshall_qxl_draw_stroke(RedWorker *worker,
                                      DisplayChannel *display_channel,
                                      SpiceMarshaller *base_marshaller,
                                      Drawable *item)
@@ -6966,7 +6966,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_send_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6991,7 +6991,7 @@ static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
 
 }
 
-static void red_send_qxl_draw_text(RedWorker *worker,
+static void red_marshall_qxl_draw_text(RedWorker *worker,
                                    DisplayChannel *display_channel,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
@@ -7056,7 +7056,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_send_qxl_draw_text(worker, display_channel, base_marshaller, item);
+        red_marshall_qxl_draw_text(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -7084,7 +7084,7 @@ static void red_lossy_send_qxl_draw_text(RedWorker *worker,
     }
 }
 
-static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
+static void red_lossy_marshall_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
                                         SpiceMarshaller *base_marshaller, Drawable *item)
 {
     switch (item->red_drawable->type) {
@@ -7130,62 +7130,56 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
     default:
         red_error("invalid type");
     }
-
-    // a message is pending
-    if (red_channel_send_message_pending(&display_channel->common.base)) {
-        display_begin_send_message(display_channel);
-    }
 }
 
-static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
+static inline void red_marshall_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
                                          SpiceMarshaller *m, Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
 
     switch (drawable->type) {
     case QXL_DRAW_FILL:
-        red_send_qxl_draw_fill(worker, display_channel, m, item);
+        red_marshall_qxl_draw_fill(worker, display_channel, m, item);
         break;
     case QXL_DRAW_OPAQUE:
-        red_send_qxl_draw_opaque(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_opaque(worker, display_channel, m, item, FALSE);
         break;
     case QXL_DRAW_COPY:
-        red_send_qxl_draw_copy(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_copy(worker, display_channel, m, item, FALSE);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_send_qxl_draw_transparent(worker, display_channel, m, item);
+        red_marshall_qxl_draw_transparent(worker, display_channel, m, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_send_qxl_draw_alpha_blend(worker, display_channel, m, item, FALSE);
+        red_marshall_qxl_draw_alpha_blend(worker, display_channel, m, item, FALSE);
         break;
     case QXL_COPY_BITS:
-        red_send_qxl_copy_bits(worker, display_channel, m, item);
+        red_marshall_qxl_copy_bits(worker, display_channel, m, item);
         break;
     case QXL_DRAW_BLEND:
-        red_send_qxl_draw_blend(worker, display_channel, m, item);
+        red_marshall_qxl_draw_blend(worker, display_channel, m, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_send_qxl_draw_blackness(worker, display_channel, m, item);
+        red_marshall_qxl_draw_blackness(worker, display_channel, m, item);
         break;
     case QXL_DRAW_WHITENESS:
-        red_send_qxl_draw_whiteness(worker, display_channel, m, item);
+        red_marshall_qxl_draw_whiteness(worker, display_channel, m, item);
         break;
     case QXL_DRAW_INVERS:
-        red_send_qxl_draw_inverse(worker, display_channel, m, item);
+        red_marshall_qxl_draw_inverse(worker, display_channel, m, item);
         break;
     case QXL_DRAW_ROP3:
-        red_send_qxl_draw_rop3(worker, display_channel, m, item);
+        red_marshall_qxl_draw_rop3(worker, display_channel, m, item);
         break;
     case QXL_DRAW_STROKE:
-        red_send_qxl_draw_stroke(worker, display_channel, m, item);
+        red_marshall_qxl_draw_stroke(worker, display_channel, m, item);
         break;
     case QXL_DRAW_TEXT:
-        red_send_qxl_draw_text(worker, display_channel, m, item);
+        red_marshall_qxl_draw_text(worker, display_channel, m, item);
         break;
     default:
         red_error("invalid type");
     }
-    display_begin_send_message(display_channel);
 }
 
 static void inline channel_release_res(RedChannel *channel)
@@ -7554,13 +7548,11 @@ static inline int red_send_stream_data(DisplayChannel *display_channel,
     spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
     spice_marshaller_add_ref(base_marshaller,
                              display_channel->send_data.stream_outbuf, n);
-
-    display_begin_send_message(display_channel);
     agent->lats_send_time = time_now;
     return TRUE;
 }
 
-static inline void send_qxl_drawable(DisplayChannel *display_channel,
+static inline void marshall_qxl_drawable(DisplayChannel *display_channel,
     SpiceMarshaller *m, Drawable *item)
 {
     ASSERT(display_channel);
@@ -7569,9 +7561,9 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel,
         return;
     }
     if (!display_channel->enable_jpeg)
-        red_send_qxl_drawable(display_channel->common.worker, display_channel, m, item);
+        red_marshall_qxl_drawable(display_channel->common.worker, display_channel, m, item);
     else
-        red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, m, item);
+        red_lossy_marshall_qxl_drawable(display_channel->common.worker, display_channel, m, item);
 }
 
 static inline void red_marshall_verb(RedChannel *channel, uint16_t verb)
@@ -7580,18 +7572,10 @@ static inline void red_marshall_verb(RedChannel *channel, uint16_t verb)
     red_channel_init_send_data(channel, verb, NULL);
 }
 
-static inline void red_send_verb(RedChannel *channel, uint16_t verb)
-{
-    ASSERT(channel);
-    red_marshall_verb(channel, verb);
-    red_channel_begin_send_message(channel);
-}
-
-static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
+static inline void display_marshall_verb(DisplayChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
     red_channel_init_send_data(&channel->common.base, verb, NULL);
-    display_begin_send_message(channel);
 }
 
 static inline void red_marshall_inval(RedChannel *channel,
@@ -7605,14 +7589,13 @@ static inline void red_marshall_inval(RedChannel *channel,
     spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
-static void red_display_send_inval(DisplayChannel *display_channel,
+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);
-    display_begin_send_message(display_channel);
 }
 
-static void display_channel_send_migrate(DisplayChannel *display_channel, SpiceMarshaller *base_marshaller)
+static void display_channel_marshall_migrate(DisplayChannel *display_channel, SpiceMarshaller *base_marshaller)
 {
     SpiceMsgMigrate migrate;
 
@@ -7620,10 +7603,9 @@ static void display_channel_send_migrate(DisplayChannel *display_channel, SpiceM
     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
     spice_marshall_msg_migrate(base_marshaller, &migrate);
     display_channel->expect_migrate_mark = TRUE;
-    display_begin_send_message(display_channel);
 }
 
-static void display_channel_send_migrate_data(DisplayChannel *display_channel)
+static void display_channel_marshall_migrate_data(DisplayChannel *display_channel)
 {
     DisplayChannelMigrateData display_data;
 
@@ -7651,19 +7633,16 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel)
 
     spice_marshaller_add_ref(display_channel->common.base.send_data.marshaller,
                              (uint8_t *)&display_data, sizeof(display_data));
-    display_begin_send_message(display_channel);
 }
 
-static void display_channel_pixmap_sync(DisplayChannel *display_channel)
+static void display_channel_marshall_pixmap_sync(DisplayChannel *display_channel)
 {
     SpiceMsgWaitForChannels wait;
     PixmapCache *pixmap_cache;
 
-
     red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
     pixmap_cache = display_channel->pixmap_cache;
 
-
     pthread_mutex_lock(&pixmap_cache->lock);
 
     wait.wait_count = 1;
@@ -7676,11 +7655,9 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel)
     pthread_mutex_unlock(&pixmap_cache->lock);
 
     spice_marshall_msg_wait_for_channels(display_channel->common.base.send_data.marshaller, &wait);
-
-    display_begin_send_message(display_channel);
 }
 
-static void display_channel_reset_cache(DisplayChannel *display_channel)
+static void display_channel_marshall_reset_cache(DisplayChannel *display_channel)
 {
     SpiceMsgWaitForChannels wait;
 
@@ -7689,10 +7666,9 @@ static void display_channel_reset_cache(DisplayChannel *display_channel)
 
     spice_marshall_msg_display_inval_all_pixmaps(display_channel->common.base.send_data.marshaller,
                                                  &wait);
-    display_begin_send_message(display_channel);
 }
 
-static void red_send_image(DisplayChannel *display_channel, SpiceMarshaller *m, ImageItem *item)
+static void red_marshall_image(DisplayChannel *display_channel, SpiceMarshaller *m, ImageItem *item)
 {
     RedChannel *channel;
     SpiceImage red_image;
@@ -7823,12 +7799,10 @@ static void red_send_image(DisplayChannel *display_channel, SpiceMarshaller *m,
                                  bitmap.y * bitmap.stride);
         region_remove(surface_lossy_region, &copy.base.box);
     }
-    display_begin_send_message(display_channel);
-
     spice_chunks_destroy(chunks);
 }
 
-static void red_display_send_upgrade(DisplayChannel *display_channel, SpiceMarshaller *m, UpgradeItem *item)
+static void red_display_marshall_upgrade(DisplayChannel *display_channel, SpiceMarshaller *m, UpgradeItem *item)
 {
     RedChannel *channel;
     RedDrawable *red_drawable;
@@ -7855,11 +7829,9 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, SpiceMarsh
                                          &src_bitmap_out, &mask_bitmap_out);
 
     fill_bits(display_channel, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
-
-    display_begin_send_message(display_channel);
 }
 
-static void red_display_send_stream_start(DisplayChannel *display_channel,
+static void red_display_marshall_stream_start(DisplayChannel *display_channel,
                      SpiceMarshaller *base_marshaller, StreamAgent *agent)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -7893,12 +7865,9 @@ static void red_display_send_stream_start(DisplayChannel *display_channel,
     }
 
     spice_marshall_msg_display_stream_create(base_marshaller, &stream_create);
-
-
-    display_begin_send_message(display_channel);
 }
 
-static void red_display_send_stream_clip(DisplayChannel *display_channel,
+static void red_display_marshall_stream_clip(DisplayChannel *display_channel,
                                          SpiceMarshaller *base_marshaller,
                                          StreamClipItem *item)
 {
@@ -7917,11 +7886,9 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
     stream_clip.clip.rects = item->rects;
 
     spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip);
-
-    display_begin_send_message(display_channel);
 }
 
-static void red_display_send_stream_end(DisplayChannel *display_channel,
+static void red_display_marshall_stream_end(DisplayChannel *display_channel,
                    SpiceMarshaller *base_marshaller, StreamAgent* agent)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -7931,8 +7898,6 @@ static void red_display_send_stream_end(DisplayChannel *display_channel,
     destroy.id = agent - display_channel->stream_agents;
 
     spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
-
-    display_begin_send_message(display_channel);
 }
 
 static void red_cursor_marshall_inval(CursorChannel *channel,
@@ -8050,7 +8015,7 @@ static void red_marshall_cursor(CursorChannel *cursor_channel,
     red_release_cursor(worker, cursor);
 }
 
-static void red_send_surface_create(DisplayChannel *display,
+static void red_marshall_surface_create(DisplayChannel *display,
     SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
 {
     RedChannel *channel;
@@ -8062,11 +8027,9 @@ static void red_send_surface_create(DisplayChannel *display,
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
 
     spice_marshall_msg_display_surface_create(base_marshaller, surface_create);
-
-    red_channel_begin_send_message(channel);
 }
 
-static void red_send_surface_destroy(DisplayChannel *display,
+static void red_marshall_surface_destroy(DisplayChannel *display,
        SpiceMarshaller *base_marshaller, uint32_t surface_id)
 {
     RedChannel *channel;
@@ -8081,8 +8044,6 @@ static void red_send_surface_destroy(DisplayChannel *display,
     surface_destroy.surface_id = surface_id;
 
     spice_marshall_msg_display_surface_destroy(base_marshaller, &surface_destroy);
-
-    red_channel_begin_send_message(channel);
 }
 
 static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
@@ -8095,83 +8056,87 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_DRAW: {
         Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
-        send_qxl_drawable(display_channel, m, drawable);
+        marshall_qxl_drawable(display_channel, m, drawable);
         release_drawable(worker, drawable);
         break;
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_display_send_inval(display_channel, m, (CacheItem *)pipe_item);
+        red_display_marshall_inval(display_channel, 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_send_stream_start(display_channel, m, agent);
+        red_display_marshall_stream_start(display_channel, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_CLIP: {
         StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
-        red_display_send_stream_clip(display_channel, m, clip_item);
+        red_display_marshall_stream_clip(display_channel, 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_send_stream_end(display_channel, m, agent);
+        red_display_marshall_stream_end(display_channel, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_UPGRADE:
-        red_display_send_upgrade(display_channel, m, (UpgradeItem *)pipe_item);
+        red_display_marshall_upgrade(display_channel, m, (UpgradeItem *)pipe_item);
         release_upgrade_item(worker, (UpgradeItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
-        display_send_verb(display_channel, ((VerbItem*)pipe_item)->verb);
+        display_marshall_verb(display_channel, ((VerbItem*)pipe_item)->verb);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        display_channel_send_migrate(display_channel, m);
+        display_channel_marshall_migrate(display_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        display_channel_send_migrate_data(display_channel);
+        display_channel_marshall_migrate_data(display_channel);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_IMAGE:
-        red_send_image(display_channel, m, (ImageItem *)pipe_item);
+        red_marshall_image(display_channel, m, (ImageItem *)pipe_item);
         release_image_item((ImageItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-        display_channel_pixmap_sync(display_channel);
+        display_channel_marshall_pixmap_sync(display_channel);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
-        display_channel_reset_cache(display_channel);
+        display_channel_marshall_reset_cache(display_channel);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
         red_reset_palette_cache(display_channel);
-        red_send_verb((RedChannel *)display_channel, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
+        red_marshall_verb((RedChannel *)display_channel, 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_send_surface_create(display_channel, m, &surface_create->surface_create);
+        red_marshall_surface_create(display_channel, 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_send_surface_destroy(display_channel, m, surface_destroy->surface_destroy.surface_id);
+        red_marshall_surface_destroy(display_channel, m, surface_destroy->surface_destroy.surface_id);
         free(surface_destroy);
         break;
     }
     default:
         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);
+    }
     red_unref_channel(&display_channel->common.base);
 }
 
commit 88db43879be888bfc2841bb5edab85b194bee79b
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 16:42:24 2010 +0200

    server/red_channel: add red_channel_send_message_pending

diff --git a/server/red_channel.c b/server/red_channel.c
index 8476319..f2665a4 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -711,6 +711,11 @@ int red_channel_any_blocked(RedChannel *channel)
     return channel->send_data.blocked;
 }
 
+int red_channel_send_message_pending(RedChannel *channel)
+{
+    return channel->send_data.header->type != 0;
+}
+
 /* accessors for RedChannel */
 SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
 {
diff --git a/server/red_channel.h b/server/red_channel.h
index 96b6095..ce8ef20 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -257,6 +257,9 @@ 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);
 
+/* helper for channels that have complex logic that can possibly ready a send */
+int red_channel_send_message_pending(RedChannel *channel);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
diff --git a/server/red_worker.c b/server/red_worker.c
index e0894d9..41c53c4 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7132,7 +7132,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
     }
 
     // a message is pending
-    if (display_channel->common.base.send_data.header->type != 0) {
+    if (red_channel_send_message_pending(&display_channel->common.base)) {
         display_begin_send_message(display_channel);
     }
 }
commit 7a650e96419df8ac231e57f0e5a22b31b7f8808b
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 15:51:24 2010 +0200

    server/red_channel: add red_channel_all_blocked

diff --git a/server/red_channel.c b/server/red_channel.c
index 22a4cc0..8476319 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -701,6 +701,16 @@ void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
     channel->ack_data.client_window = client_window;
 }
 
+int red_channel_all_blocked(RedChannel *channel)
+{
+    return channel->send_data.blocked;
+}
+
+int red_channel_any_blocked(RedChannel *channel)
+{
+    return channel->send_data.blocked;
+}
+
 /* accessors for RedChannel */
 SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
 {
diff --git a/server/red_channel.h b/server/red_channel.h
index 61aa788..96b6095 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -251,6 +251,12 @@ void red_channel_shutdown(RedChannel *channel);
 
 int red_channel_get_first_socket(RedChannel *channel);
 
+/* return TRUE if all of the connected clients to this channel are blocked */
+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);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
diff --git a/server/red_worker.c b/server/red_worker.c
index fd83f2d..e0894d9 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4289,7 +4289,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
             red_error("bad command type");
         }
         n++;
-        if ((worker->display_channel && worker->display_channel->common.base.send_data.blocked) ||
+        if ((worker->display_channel && red_channel_all_blocked(&worker->display_channel->common.base)) ||
             red_now() - start > 10 * 1000 * 1000) {
             worker->epoll_timeout = 0;
             return n;
@@ -9133,7 +9133,7 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
         red_channel_receive(channel);
     }
 
-    if (channel->send_data.blocked) {
+    if (red_channel_any_blocked(channel)) {
         red_channel_send(channel);
     }
 }
@@ -9410,7 +9410,7 @@ static void red_wait_outgoing_item(RedChannel *channel)
     uint64_t end_time;
     int blocked;
 
-    if (!channel || !channel->send_data.blocked) {
+    if (!channel || !red_channel_all_blocked(channel)) {
         return;
     }
     red_ref_channel(channel);
@@ -9422,7 +9422,7 @@ static void red_wait_outgoing_item(RedChannel *channel)
         usleep(DETACH_SLEEP_DURATION);
         red_channel_receive(channel);
         red_channel_send(channel);
-    } while ((blocked = channel->send_data.blocked) && red_now() < end_time);
+    } while ((blocked = red_channel_all_blocked(channel)) && red_now() < end_time);
 
     if (blocked) {
         red_printf("timeout");
@@ -9448,7 +9448,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
 
     end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
 
-    if (channel->send_data.blocked) {
+    if (red_channel_all_blocked(channel)) {
         red_channel_receive(channel);
         red_channel_send(channel);
     }
commit b7dbc14b1c6bcae4edb6859fc811a53abc0805dc
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 15:19:19 2010 +0200

    server/red_worker: cursor channel: replace _send_ with _marshall_

diff --git a/server/red_worker.c b/server/red_worker.c
index b8e4825..fd83f2d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7574,10 +7574,16 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel,
         red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, m, item);
 }
 
-static inline void red_send_verb(RedChannel *channel, uint16_t verb)
+static inline void red_marshall_verb(RedChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
     red_channel_init_send_data(channel, verb, NULL);
+}
+
+static inline void red_send_verb(RedChannel *channel, uint16_t verb)
+{
+    ASSERT(channel);
+    red_marshall_verb(channel, verb);
     red_channel_begin_send_message(channel);
 }
 
@@ -7588,7 +7594,7 @@ static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
     display_begin_send_message(channel);
 }
 
-static inline void __red_send_inval(RedChannel *channel,
+static inline void red_marshall_inval(RedChannel *channel,
         SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
     SpiceMsgDisplayInvalOne inval_one;
@@ -7599,17 +7605,10 @@ static inline void __red_send_inval(RedChannel *channel,
     spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
-static void red_send_inval(RedChannel *channel,
-            SpiceMarshaller *base_marshaller, CacheItem *cach_item)
-{
-    __red_send_inval(channel, base_marshaller, cach_item);
-    red_channel_begin_send_message(channel);
-}
-
 static void red_display_send_inval(DisplayChannel *display_channel,
                 SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
-    __red_send_inval((RedChannel *)display_channel, base_marshaller, cach_item);
+    red_marshall_inval((RedChannel *)display_channel, base_marshaller, cach_item);
     display_begin_send_message(display_channel);
 }
 
@@ -7936,14 +7935,14 @@ static void red_display_send_stream_end(DisplayChannel *display_channel,
     display_begin_send_message(display_channel);
 }
 
-static void red_cursor_send_inval(CursorChannel *channel,
+static void red_cursor_marshall_inval(CursorChannel *channel,
                 SpiceMarshaller *m, CacheItem *cach_item)
 {
     ASSERT(channel);
-    red_send_inval((RedChannel *)channel, m, cach_item);
+    red_marshall_inval((RedChannel *)channel, m, cach_item);
 }
 
-static void red_send_cursor_init(CursorChannel *channel)
+static void red_marshall_cursor_init(CursorChannel *channel)
 {
     RedWorker *worker;
     SpiceMsgCursorInit msg;
@@ -7962,11 +7961,9 @@ static void red_send_cursor_init(CursorChannel *channel)
     fill_cursor(channel, &msg.cursor, worker->cursor, &info);
     spice_marshall_msg_cursor_init(channel->common.base.send_data.marshaller, &msg);
     add_buf_from_info(&channel->common.base, channel->common.base.send_data.marshaller, &info);
-
-    red_channel_begin_send_message(&channel->common.base);
 }
 
-static void red_send_local_cursor(CursorChannel *cursor_channel,
+static void red_marshall_local_cursor(CursorChannel *cursor_channel,
           SpiceMarshaller *base_marshaller, LocalCursor *cursor)
 {
     RedChannel *channel;
@@ -7984,13 +7981,10 @@ static void red_send_local_cursor(CursorChannel *cursor_channel,
     fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
     spice_marshall_msg_cursor_set(base_marshaller, &cursor_set);
     add_buf_from_info(channel, base_marshaller, &info);
-
-    red_channel_begin_send_message(channel);
-
     red_release_cursor(worker, (CursorItem *)cursor);
 }
 
-static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
+static void cursor_channel_marshall_migrate(CursorChannel *cursor_channel)
 {
     SpiceMsgMigrate migrate;
 
@@ -7998,10 +7992,9 @@ static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
     migrate.flags = 0;
 
     spice_marshall_msg_migrate(cursor_channel->common.base.send_data.marshaller, &migrate);
-    red_channel_begin_send_message((RedChannel*)cursor_channel);
 }
 
-static void red_send_cursor(CursorChannel *cursor_channel,
+static void red_marshall_cursor(CursorChannel *cursor_channel,
                    SpiceMarshaller *m, CursorItem *cursor)
 {
     RedChannel *channel;
@@ -8054,8 +8047,6 @@ static void red_send_cursor(CursorChannel *cursor_channel,
         red_error("bad cursor command %d", cmd->type);
     }
 
-    red_channel_begin_send_message(channel);
-
     red_release_cursor(worker, cursor);
 }
 
@@ -8192,37 +8183,38 @@ static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
     red_ref_channel(channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
-        red_send_cursor(cursor_channel, m, (CursorItem *)pipe_item);
+        red_marshall_cursor(cursor_channel, m, (CursorItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_LOCAL_CURSOR:
-        red_send_local_cursor(cursor_channel, m, (LocalCursor *)pipe_item);
+        red_marshall_local_cursor(cursor_channel, m, (LocalCursor *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_cursor_send_inval(cursor_channel, m, (CacheItem *)pipe_item);
+        red_cursor_marshall_inval(cursor_channel, m, (CacheItem *)pipe_item);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
-        red_send_verb(channel, ((VerbItem*)pipe_item)->verb);
+        red_marshall_verb(channel, ((VerbItem*)pipe_item)->verb);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        cursor_channel_send_migrate(cursor_channel);
+        cursor_channel_marshall_migrate(cursor_channel);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
         red_reset_cursor_cache(cursor_channel);
-        red_send_cursor_init(cursor_channel);
+        red_marshall_cursor_init(cursor_channel);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
         red_reset_cursor_cache(cursor_channel);
-        red_send_verb(channel, SPICE_MSG_CURSOR_INVAL_ALL);
+        red_marshall_verb(channel, 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);
 }
 
commit e9be6ca82c331f00097bc7f56ce2c804d42fbf5f
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 12:13:53 2010 +0200

    server/red_channel (all): add red_channel_get_header
    
    This is useful during the channel specific channel_send_pipe_item_proc
    callback, it allows altering or reader the header being sent.

diff --git a/server/red_channel.c b/server/red_channel.c
index a1bce11..22a4cc0 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -719,3 +719,8 @@ int red_channel_get_first_socket(RedChannel *channel)
     }
     return channel->stream->socket;
 }
+
+SpiceDataHeader *red_channel_get_header(RedChannel *channel)
+{
+    return channel->send_data.header;
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index 9d13dd7..61aa788 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -275,4 +275,11 @@ void red_channel_send(RedChannel *channel);
 SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel);
 RedsStream *red_channel_get_stream(RedChannel *channel);
 
+/* 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
+ * pointer retrieved is not valid except between red_channel_reset_send_data and
+ * 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);
 #endif
commit 17d57613225fe3520b42aaddbab4b5252b9c8b3b
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Nov 11 11:05:01 2010 +0200

    server/red_channel: add red_channel_get_first_socket
    
    Use in main_channel. This is just for backward portability later
    when multiple clients are introduced - needs to be considered (which
    sockets do we want to export from libspiceserver?)

diff --git a/server/main_channel.c b/server/main_channel.c
index 75accac..1f407e2 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -823,22 +823,23 @@ int main_channel_getsockname(Channel *channel, struct sockaddr *sa, socklen_t *s
 {
     MainChannel *main_chan = channel->data;
 
-    return main_chan ? getsockname(main_chan->base.stream->socket, sa, salen) : -1;
+    return main_chan ? getsockname(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
 }
 
 int main_channel_getpeername(Channel *channel, struct sockaddr *sa, socklen_t *salen)
 {
     MainChannel *main_chan = channel->data;
 
-    return main_chan ? getpeername(main_chan->base.stream->socket, sa, salen) : -1;
+    return main_chan ? getpeername(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
 }
 
 void main_channel_close(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
+    int socketfd;
 
-    if (main_chan && main_chan->base.stream) {
-        close(main_chan->base.stream->socket);
+    if (main_chan && (socketfd = red_channel_get_first_socket(&main_chan->base)) != -1) {
+        close(socketfd);
     }
 }
 
diff --git a/server/red_channel.c b/server/red_channel.c
index 1b705d6..a1bce11 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -711,3 +711,11 @@ RedsStream *red_channel_get_stream(RedChannel *channel)
 {
     return channel->stream;
 }
+
+int red_channel_get_first_socket(RedChannel *channel)
+{
+    if (!channel->stream) {
+        return -1;
+    }
+    return channel->stream->socket;
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index d0f7fb7..9d13dd7 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -249,6 +249,8 @@ void red_channel_push_set_ack(RedChannel *channel);
 
 void red_channel_shutdown(RedChannel *channel);
 
+int red_channel_get_first_socket(RedChannel *channel);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
commit 8cd5568c92384490ec20f898d2d8c12009b6bf47
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Nov 10 09:52:28 2010 +0200

    server/red_channel (+): remove red_channel_add_buf

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 5e2681a..d6bcf9d 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -461,7 +461,6 @@ static void inputs_shutdown(Channel *channel)
 
     if (inputs_channel) {
         red_channel_shutdown(&inputs_channel->base);
-        inputs_channel->base.incoming.shut = TRUE;
         channel->data = NULL;
         g_inputs_channel = NULL;
     }
diff --git a/server/red_channel.c b/server/red_channel.c
index f8944c0..1b705d6 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -455,6 +455,7 @@ void red_channel_shutdown(RedChannel *channel)
         red_channel_pipe_clear(channel);
         shutdown(channel->stream->socket, SHUT_RDWR);
         channel->stream->shutdown = TRUE;
+        channel->incoming.shut = TRUE;
     }
 }
 
@@ -531,12 +532,6 @@ static void red_channel_event(int fd, int event, void *data)
     }
 }
 
-void red_channel_add_buf(RedChannel *channel, void *data, uint32_t size)
-{
-    spice_marshaller_add_ref(channel->send_data.marshaller, data, size);
-    channel->send_data.header->size += size;
-}
-
 void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item)
 {
     ASSERT(channel->send_data.item == NULL);
diff --git a/server/red_channel.h b/server/red_channel.h
index f991f2d..d0f7fb7 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -148,10 +148,6 @@ struct RedChannel {
     struct {
         SpiceMarshaller *marshaller;
         SpiceDataHeader *header;
-        union {
-            SpiceMsgSetAck ack;
-            SpiceMsgMigrate migrate;
-        } u;
         uint32_t size;
         PipeItem *item;
         int blocked;
@@ -218,7 +214,6 @@ int red_channel_is_connected(RedChannel *channel);
 
 void red_channel_destroy(RedChannel *channel);
 
-void red_channel_shutdown(RedChannel *channel);
 /* should be called when a new channel is ready to send messages */
 void red_channel_init_outgoing_messages_window(RedChannel *channel);
 
@@ -229,10 +224,8 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
 /* default error handler that disconnects channel */
 void red_channel_default_peer_on_error(RedChannel *channel);
 
-/* when preparing send_data: should call init and then add_buf per buffer that is
-   being sent */
+/* 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_add_buf(RedChannel *channel, void *data, uint32_t size);
 
 uint64_t red_channel_get_message_serial(RedChannel *channel);
 void red_channel_set_message_serial(RedChannel *channel, uint64_t);
@@ -254,6 +247,8 @@ 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);
 
+void red_channel_shutdown(RedChannel *channel);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index b731e10..b27fdee 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -491,6 +491,7 @@ struct TunnelChannel {
 
     int tunnel_error;
 
+    /* TODO: this needs to be RCC specific (or bad things will happen) */
     struct {
         union {
             SpiceMsgTunnelInit init;
@@ -502,6 +503,7 @@ struct TunnelChannel {
             SpiceMsgTunnelSocketData socket_data;
             SpiceMsgTunnelSocketTokens socket_token;
             TunnelMigrateData migrate_data;
+            SpiceMsgMigrate migrate;
         } u;
     } send_data;
 
@@ -2341,14 +2343,16 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
 /* outgoing msgs
 ********************************/
 
-static void tunnel_channel_marshall_migrate(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
+static void tunnel_channel_marshall_migrate(TunnelChannel *tunnel_channel, SpiceMarshaller *m, PipeItem *item)
 {
-    ASSERT(channel);
-    channel->base.send_data.u.migrate.flags = SPICE_MIGRATE_NEED_FLUSH |
-        SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    channel->expect_migrate_mark = TRUE;
-    red_channel_init_send_data(&channel->base, SPICE_MSG_MIGRATE, item);
-    red_channel_add_buf(&channel->base, &channel->base.send_data.u.migrate, sizeof(SpiceMsgMigrate));
+    ASSERT(tunnel_channel);
+    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);
+    spice_marshaller_add_ref(m,
+        (uint8_t*)&tunnel_channel->send_data.u.migrate,
+        sizeof(SpiceMsgMigrate));
 }
 
 static int __tunnel_channel_marshall_process_bufs_migrate_data(TunnelChannel *channel,
@@ -2359,7 +2363,7 @@ static int __tunnel_channel_marshall_process_bufs_migrate_data(TunnelChannel *ch
     int size = 0;
 
     while (buf) {
-        red_channel_add_buf(&channel->base, buf->data + buf_offset, buf->size - buf_offset);
+        spice_marshaller_add_ref(m, (uint8_t*)buf->data + buf_offset, buf->size - buf_offset);
         size += buf->size - buf_offset;
         buf_offset = 0;
         buf = buf->next;
@@ -2376,7 +2380,7 @@ static int __tunnel_channel_marshall_ready_bufs_migrate_data(TunnelChannel *chan
     int size = 0;
 
     while (chunk) {
-        red_channel_add_buf(&channel->base, chunk->data + offset, chunk->size - offset);
+        spice_marshaller_add_ref(m, (uint8_t*)chunk->data + offset, chunk->size - offset);
         size += chunk->size - offset;
         offset = 0;
         chunk = chunk->next;
@@ -2396,12 +2400,12 @@ static int __tunnel_channel_marshall_service_migrate_data(TunnelChannel *channel
 
     if (service->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
         generic_data = &item->u.generic_service;
-        red_channel_add_buf(&channel->base, &item->u.generic_service,
+        spice_marshaller_add_ref(m, (uint8_t*)&item->u.generic_service,
                             sizeof(item->u.generic_service));
         cur_offset += sizeof(item->u.generic_service);
     } else if (service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
         generic_data = &item->u.print_service.base;
-        red_channel_add_buf(&channel->base, &item->u.print_service,
+        spice_marshaller_add_ref(m, (uint8_t*)&item->u.print_service,
                             sizeof(item->u.print_service));
         cur_offset += sizeof(item->u.print_service);
     } else {
@@ -2409,11 +2413,11 @@ static int __tunnel_channel_marshall_service_migrate_data(TunnelChannel *channel
     }
 
     generic_data->name = cur_offset;
-    red_channel_add_buf(&channel->base, service->name, strlen(service->name) + 1);
+    spice_marshaller_add_ref(m, (uint8_t*)service->name, strlen(service->name) + 1);
     cur_offset += strlen(service->name) + 1;
 
     generic_data->description = cur_offset;
-    red_channel_add_buf(&channel->base, service->description, strlen(service->description) + 1);
+    spice_marshaller_add_ref(m, (uint8_t*)service->description, strlen(service->description) + 1);
     cur_offset += strlen(service->description) + 1;
 
     return (cur_offset - offset);
@@ -2426,7 +2430,7 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
     RedSocket *sckt = item->socket;
     TunnelMigrateSocket *mig_sckt = &item->mig_socket;
     int cur_offset = offset;
-    red_channel_add_buf(&channel->base, mig_sckt, sizeof(*mig_sckt));
+    spice_marshaller_add_ref(m, (uint8_t*)mig_sckt, sizeof(*mig_sckt));
     cur_offset += sizeof(*mig_sckt);
 
     if ((sckt->client_status != CLIENT_SCKT_STATUS_CLOSED) &&
@@ -2439,7 +2443,7 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
         cur_offset += mig_sckt->out_data.process_buf_size;
         if (mig_sckt->out_data.process_queue_size) {
             mig_sckt->out_data.process_queue = cur_offset;
-            red_channel_add_buf(&channel->base, item->out_process_queue,
+            spice_marshaller_add_ref(m, (uint8_t*)item->out_process_queue,
                                 mig_sckt->out_data.process_queue_size);
             cur_offset += mig_sckt->out_data.process_queue_size;
         }
@@ -2463,7 +2467,7 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
         cur_offset += mig_sckt->in_data.process_buf_size;
         if (mig_sckt->in_data.process_queue_size) {
             mig_sckt->in_data.process_queue = cur_offset;
-            red_channel_add_buf(&channel->base, item->in_process_queue,
+            spice_marshaller_add_ref(m, (uint8_t*)item->in_process_queue,
                                 mig_sckt->in_data.process_queue_size);
             cur_offset += mig_sckt->in_data.process_queue_size;
         }
@@ -2478,7 +2482,7 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
     }
 
     if (item->slirp_socket_size) { // zero if socket is closed
-        red_channel_add_buf(&channel->base, item->slirp_socket, item->slirp_socket_size);
+        spice_marshaller_add_ref(m, (uint8_t*)item->slirp_socket, item->slirp_socket_size);
         mig_sckt->slirp_sckt = cur_offset;
         cur_offset += item->slirp_socket_size;
     }
@@ -2499,14 +2503,14 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
     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);
-    red_channel_add_buf(&channel->base, migrate_data, sizeof(*migrate_data));
+    spice_marshaller_add_ref(m, (uint8_t*)migrate_data, sizeof(*migrate_data));
 
     migrate_data->slirp_state = data_buf_offset;
-    red_channel_add_buf(&channel->base, migrate_item->slirp_state, migrate_item->slirp_state_size);
+    spice_marshaller_add_ref(m, (uint8_t*)migrate_item->slirp_state, migrate_item->slirp_state_size);
     data_buf_offset += migrate_item->slirp_state_size;
 
     migrate_data->services_list = data_buf_offset;
-    red_channel_add_buf(&channel->base, migrate_item->services_list,
+    spice_marshaller_add_ref(m, (uint8_t*)migrate_item->services_list,
                         migrate_item->services_list_size);
     data_buf_offset += migrate_item->services_list_size;
 
@@ -2519,7 +2523,7 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
 
 
     migrate_data->sockets_list = data_buf_offset;
-    red_channel_add_buf(&channel->base, migrate_item->sockets_list,
+    spice_marshaller_add_ref(m, (uint8_t*)migrate_item->sockets_list,
                         migrate_item->sockets_list_size);
     data_buf_offset += migrate_item->sockets_list_size;
 
@@ -2539,7 +2543,7 @@ static void tunnel_channel_marshall_init(TunnelChannel *channel, SpiceMarshaller
     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_add_buf(&channel->base, &channel->send_data.u.init, sizeof(SpiceMsgTunnelInit));
+    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)
@@ -2550,9 +2554,9 @@ static void tunnel_channel_marshall_service_ip_map(TunnelChannel *channel, Spice
     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);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.service_ip,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.service_ip,
                         sizeof(SpiceMsgTunnelServiceIpMap));
-    red_channel_add_buf(&channel->base, &service->virt_ip.s_addr, sizeof(SpiceTunnelIPv4));
+    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)
@@ -2567,7 +2571,7 @@ static void tunnel_channel_marshall_socket_open(TunnelChannel *channel, SpiceMar
     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);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_open,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_open,
                         sizeof(channel->send_data.u.socket_open));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
@@ -2590,7 +2594,7 @@ static void tunnel_channel_marshall_socket_fin(TunnelChannel *channel, SpiceMars
     channel->send_data.u.socket_fin.connection_id = sckt->connection_id;
 
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_fin,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_fin,
                         sizeof(channel->send_data.u.socket_fin));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
@@ -2619,7 +2623,7 @@ static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMa
     channel->send_data.u.socket_close.connection_id = sckt->connection_id;
 
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_close,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close,
                         sizeof(channel->send_data.u.socket_close));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
@@ -2635,7 +2639,7 @@ static void tunnel_channel_marshall_socket_closed_ack(TunnelChannel *channel, Sp
 
     // pipe item is null because we free the sckt.
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_close_ack,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close_ack,
                         sizeof(channel->send_data.u.socket_close_ack));
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
@@ -2669,7 +2673,7 @@ static void tunnel_channel_marshall_socket_token(TunnelChannel *channel, SpiceMa
     ASSERT(sckt->in_data.client_total_num_tokens <= SOCKET_WINDOW_SIZE);
 
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_token,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_token,
                         sizeof(channel->send_data.u.socket_token));
 }
 
@@ -2697,14 +2701,14 @@ static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, Spic
     channel->send_data.u.socket_data.connection_id = sckt->connection_id;
 
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_DATA, item);
-    red_channel_add_buf(&channel->base, &channel->send_data.u.socket_data,
+    spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_data,
                         sizeof(channel->send_data.u.socket_data));
     pushed_bufs_num++;
 
     // the first chunk is in a valid size
     chunk = sckt->out_data.ready_chunks_queue.head;
     total_push_size = chunk->size - sckt->out_data.ready_chunks_queue.offset;
-    red_channel_add_buf(&channel->base, chunk->data + sckt->out_data.ready_chunks_queue.offset,
+    spice_marshaller_add_ref(m, (uint8_t*)chunk->data + sckt->out_data.ready_chunks_queue.offset,
                         total_push_size);
     pushed_bufs_num++;
     sckt->out_data.push_tail = chunk;
@@ -2714,7 +2718,7 @@ static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, Spic
 
     while (chunk && (total_push_size < MAX_SOCKET_DATA_SIZE) && (pushed_bufs_num < MAX_SEND_BUFS)) {
         uint32_t cur_push_size = MIN(chunk->size, MAX_SOCKET_DATA_SIZE - total_push_size);
-        red_channel_add_buf(&channel->base, chunk->data, cur_push_size);
+        spice_marshaller_add_ref(m, (uint8_t*)chunk->data, cur_push_size);
         pushed_bufs_num++;
 
         sckt->out_data.push_tail = chunk;
diff --git a/server/smartcard.c b/server/smartcard.c
index 4c50dbe..941c632 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -257,20 +257,21 @@ static void smartcard_channel_release_msg_rcv_buf(RedChannel *channel, SpiceData
     free(msg);
 }
 
-static void smartcard_channel_send_data(RedChannel *channel, PipeItem *item, VSCMsgHeader *vheader)
+static void smartcard_channel_send_data(RedChannel *channel, SpiceMarshaller *m,
+                                        PipeItem *item, VSCMsgHeader *vheader)
 {
     ASSERT(channel);
     ASSERT(vheader);
     red_channel_init_send_data(channel, SPICE_MSG_SMARTCARD_DATA, item);
-    red_channel_add_buf(channel, vheader, sizeof(VSCMsgHeader));
+    spice_marshaller_add_ref(m, (uint8_t*)vheader, sizeof(VSCMsgHeader));
     if (vheader->length > 0) {
-        red_channel_add_buf(channel, (uint8_t*)(vheader+1), vheader->length);
+        spice_marshaller_add_ref(m, (uint8_t*)(vheader+1), vheader->length);
     }
     red_channel_begin_send_message(channel);
 }
 
-static void smartcard_channel_send_message(RedChannel *channel, PipeItem *item,
-    uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
+static void smartcard_channel_send_message(RedChannel *channel, SpiceMarshaller *m,
+    PipeItem *item, uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
 {
     VSCMsgHeader mhHeader;
     //SpiceMarshaller* m = msg->marshaller();
@@ -283,38 +284,39 @@ static void smartcard_channel_send_message(RedChannel *channel, PipeItem *item,
     //spice_marshaller_add(m, data, len);
     //marshaller_outgoing_write(msg);
 
-    smartcard_channel_send_data(channel, item, &mhHeader);
+    smartcard_channel_send_data(channel, m, item, &mhHeader);
 }
 
 static void smartcard_channel_send_error(
-    SmartCardChannel *smartcard_channel, PipeItem *item)
+    SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
 {
     ErrorItem* error_item = (ErrorItem*)item;
     VSCMsgError error;
 
     error.code = error_item->error;
-    smartcard_channel_send_message(&smartcard_channel->base, item, error_item->reader_id,
-        VSC_Error, (uint8_t*)&error, sizeof(error));
+    smartcard_channel_send_message(&smartcard_channel->base, m, item,
+        error_item->reader_id, VSC_Error, (uint8_t*)&error, sizeof(error));
 }
 
 static void smartcard_channel_send_msg(
-    SmartCardChannel *smartcard_channel, PipeItem *item)
+    SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
 {
     MsgItem* msg_item = (MsgItem*)item;
 
-    smartcard_channel_send_data(&smartcard_channel->base, item, msg_item->vheader);
+    smartcard_channel_send_data(&smartcard_channel->base, m, item, msg_item->vheader);
 }
 
 static void smartcard_channel_send_item(RedChannel *channel, PipeItem *item)
 {
     SmartCardChannel *smartcard_channel = (SmartCardChannel *)channel;
+    SpiceMarshaller *m = red_channel_get_marshaller(channel);
 
     switch (item->type) {
     case PIPE_ITEM_TYPE_ERROR:
-        smartcard_channel_send_error(smartcard_channel, item);
+        smartcard_channel_send_error(smartcard_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_MSG:
-        smartcard_channel_send_msg(smartcard_channel, item);
+        smartcard_channel_send_msg(smartcard_channel, m, item);
     }
 }
 
commit 16bff20f91c928349dff7329ac63bddcab2444b2
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Nov 10 09:41:53 2010 +0200

    server/tunnel: pass SpiceMarshaller reference from send
    
    Introduce SpiceMarshaller param to all send's that do add_buf
    
    Next patch will use marshaller in all functions that currently don't by
    replacing red_channel_add_buf with marshaller add_ref. Note - currently
    tunnel is broken due to wrong size in messages.

diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index c990bd1..b731e10 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -2341,7 +2341,7 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
 /* outgoing msgs
 ********************************/
 
-static void tunnel_channel_send_migrate(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_migrate(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     ASSERT(channel);
     channel->base.send_data.u.migrate.flags = SPICE_MIGRATE_NEED_FLUSH |
@@ -2349,11 +2349,10 @@ static void tunnel_channel_send_migrate(TunnelChannel *channel, PipeItem *item)
     channel->expect_migrate_mark = TRUE;
     red_channel_init_send_data(&channel->base, SPICE_MSG_MIGRATE, item);
     red_channel_add_buf(&channel->base, &channel->base.send_data.u.migrate, sizeof(SpiceMsgMigrate));
-    red_channel_begin_send_message(&channel->base);
 }
 
-static int __tunnel_channel_send_process_bufs_migrate_data(TunnelChannel *channel,
-                                                           TunneledBufferProcessQueue *queue)
+static int __tunnel_channel_marshall_process_bufs_migrate_data(TunnelChannel *channel,
+                                    SpiceMarshaller *m, TunneledBufferProcessQueue *queue)
 {
     int buf_offset = queue->head_offset;
     RawTunneledBuffer *buf = queue->head;
@@ -2369,8 +2368,8 @@ static int __tunnel_channel_send_process_bufs_migrate_data(TunnelChannel *channe
     return size;
 }
 
-static int __tunnel_channel_send_ready_bufs_migrate_data(TunnelChannel *channel,
-                                                         ReadyTunneledChunkQueue *queue)
+static int __tunnel_channel_marshall_ready_bufs_migrate_data(TunnelChannel *channel,
+                                    SpiceMarshaller *m, ReadyTunneledChunkQueue *queue)
 {
     int offset = queue->offset;
     ReadyTunneledChunk *chunk = queue->head;
@@ -2386,7 +2385,8 @@ static int __tunnel_channel_send_ready_bufs_migrate_data(TunnelChannel *channel,
 }
 
 // returns the size to send
-static int __tunnel_channel_send_service_migrate_data(TunnelChannel *channel,
+static int __tunnel_channel_marshall_service_migrate_data(TunnelChannel *channel,
+                                                      SpiceMarshaller *m,
                                                       TunnelMigrateServiceItem *item,
                                                       int offset)
 {
@@ -2420,8 +2420,8 @@ static int __tunnel_channel_send_service_migrate_data(TunnelChannel *channel,
 }
 
 // returns the size to send
-static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
-                                                     TunnelMigrateSocketItem *item, int offset)
+static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
+                                SpiceMarshaller *m, TunnelMigrateSocketItem *item, int offset)
 {
     RedSocket *sckt = item->socket;
     TunnelMigrateSocket *mig_sckt = &item->mig_socket;
@@ -2434,7 +2434,7 @@ static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
         (sckt->mig_client_status_msg != SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK)) {
         mig_sckt->out_data.process_buf = cur_offset;
         mig_sckt->out_data.process_buf_size =
-            __tunnel_channel_send_process_bufs_migrate_data(channel,
+            __tunnel_channel_marshall_process_bufs_migrate_data(channel, m,
                                                             sckt->out_data.process_queue);
         cur_offset += mig_sckt->out_data.process_buf_size;
         if (mig_sckt->out_data.process_queue_size) {
@@ -2445,7 +2445,7 @@ static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
         }
         mig_sckt->out_data.ready_buf = cur_offset;
         mig_sckt->out_data.ready_buf_size =
-            __tunnel_channel_send_ready_bufs_migrate_data(channel,
+            __tunnel_channel_marshall_ready_bufs_migrate_data(channel, m,
                                                           &sckt->out_data.ready_chunks_queue);
         cur_offset += mig_sckt->out_data.ready_buf_size;
     } else {
@@ -2458,7 +2458,7 @@ static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
         (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) {
         mig_sckt->in_data.process_buf = cur_offset;
         mig_sckt->in_data.process_buf_size =
-            __tunnel_channel_send_process_bufs_migrate_data(channel,
+            __tunnel_channel_marshall_process_bufs_migrate_data(channel, m,
                                                             sckt->in_data.process_queue);
         cur_offset += mig_sckt->in_data.process_buf_size;
         if (mig_sckt->in_data.process_queue_size) {
@@ -2469,7 +2469,7 @@ static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
         }
         mig_sckt->in_data.ready_buf = cur_offset;
         mig_sckt->in_data.ready_buf_size =
-            __tunnel_channel_send_ready_bufs_migrate_data(channel,
+            __tunnel_channel_marshall_ready_bufs_migrate_data(channel, m,
                                                           &sckt->in_data.ready_chunks_queue);
         cur_offset += mig_sckt->in_data.ready_buf_size;
     } else {
@@ -2485,7 +2485,8 @@ static int __tunnel_channel_send_socket_migrate_data(TunnelChannel *channel,
     return (cur_offset - offset);
 }
 
-static void tunnel_channel_send_migrate_data(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
+                                        SpiceMarshaller *m, PipeItem *item)
 {
     TunnelMigrateData *migrate_data = &channel->send_data.u.migrate_data;
     TunnelMigrateItem *migrate_item = (TunnelMigrateItem *)item;
@@ -2511,7 +2512,7 @@ static void tunnel_channel_send_migrate_data(TunnelChannel *channel, PipeItem *i
 
     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_send_service_migrate_data(channel,
+        data_buf_offset += __tunnel_channel_marshall_service_migrate_data(channel, m,
                                                                       migrate_item->services + i,
                                                                       data_buf_offset);
     }
@@ -2524,15 +2525,13 @@ static void tunnel_channel_send_migrate_data(TunnelChannel *channel, PipeItem *i
 
     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_send_socket_migrate_data(channel,
+        data_buf_offset += __tunnel_channel_marshall_socket_migrate_data(channel, m,
                                                                      migrate_item->sockets_data + i,
                                                                      data_buf_offset);
     }
-
-    red_channel_begin_send_message(&channel->base);
 }
 
-static void tunnel_channel_send_init(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_init(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     ASSERT(channel);
 
@@ -2541,11 +2540,9 @@ static void tunnel_channel_send_init(TunnelChannel *channel, PipeItem *item)
 
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_INIT, item);
     red_channel_add_buf(&channel->base, &channel->send_data.u.init, sizeof(SpiceMsgTunnelInit));
-
-    red_channel_begin_send_message(&channel->base);
 }
 
-static void tunnel_channel_send_service_ip_map(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_service_ip_map(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     TunnelService *service = SPICE_CONTAINEROF(item, TunnelService, pipe_item);
 
@@ -2556,10 +2553,9 @@ static void tunnel_channel_send_service_ip_map(TunnelChannel *channel, PipeItem
     red_channel_add_buf(&channel->base, &channel->send_data.u.service_ip,
                         sizeof(SpiceMsgTunnelServiceIpMap));
     red_channel_add_buf(&channel->base, &service->virt_ip.s_addr, sizeof(SpiceTunnelIPv4));
-    red_channel_begin_send_message(&channel->base);
 }
 
-static void tunnel_channel_send_socket_open(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_open(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2573,14 +2569,12 @@ static void tunnel_channel_send_socket_open(TunnelChannel *channel, PipeItem *it
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_OPEN, item);
     red_channel_add_buf(&channel->base, &channel->send_data.u.socket_open,
                         sizeof(channel->send_data.u.socket_open));
-
-    red_channel_begin_send_message(&channel->base);
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_send_socket_fin(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_fin(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2598,15 +2592,12 @@ static void tunnel_channel_send_socket_fin(TunnelChannel *channel, PipeItem *ite
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
     red_channel_add_buf(&channel->base, &channel->send_data.u.socket_fin,
                         sizeof(channel->send_data.u.socket_fin));
-
-    red_channel_begin_send_message(&channel->base);
-
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_send_socket_close(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2630,15 +2621,12 @@ static void tunnel_channel_send_socket_close(TunnelChannel *channel, PipeItem *i
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
     red_channel_add_buf(&channel->base, &channel->send_data.u.socket_close,
                         sizeof(channel->send_data.u.socket_close));
-
-    red_channel_begin_send_message(&channel->base);
-
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
 }
 
-static void tunnel_channel_send_socket_closed_ack(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_closed_ack(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2649,9 +2637,6 @@ static void tunnel_channel_send_socket_closed_ack(TunnelChannel *channel, PipeIt
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
     red_channel_add_buf(&channel->base, &channel->send_data.u.socket_close_ack,
                         sizeof(channel->send_data.u.socket_close_ack));
-
-    red_channel_begin_send_message(&channel->base);
-
 #ifdef DEBUG_NETWORK
     PRINT_SCKT(sckt);
 #endif
@@ -2663,7 +2648,7 @@ static void tunnel_channel_send_socket_closed_ack(TunnelChannel *channel, PipeIt
     }
 }
 
-static void tunnel_channel_send_socket_token(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_token(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, token_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2686,11 +2671,9 @@ static void tunnel_channel_send_socket_token(TunnelChannel *channel, PipeItem *i
     red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
     red_channel_add_buf(&channel->base, &channel->send_data.u.socket_token,
                         sizeof(channel->send_data.u.socket_token));
-
-    red_channel_begin_send_message(&channel->base);
 }
 
-static void tunnel_channel_send_socket_out_data(TunnelChannel *channel, PipeItem *item)
+static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
 {
     RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, data_pipe_item);
     RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
@@ -2742,8 +2725,6 @@ static void tunnel_channel_send_socket_out_data(TunnelChannel *channel, PipeItem
     }
 
     sckt->out_data.num_tokens--;
-
-    red_channel_begin_send_message(&channel->base);
 }
 
 static void tunnel_worker_release_socket_out_data(TunnelWorker *worker, PipeItem *item)
@@ -2805,41 +2786,43 @@ static void tunnel_worker_release_socket_out_data(TunnelWorker *worker, PipeItem
 static void tunnel_channel_send_item(RedChannel *channel, PipeItem *item)
 {
     TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
+    SpiceMarshaller *m = red_channel_get_marshaller(channel);
 
     switch (item->type) {
     case PIPE_ITEM_TYPE_TUNNEL_INIT:
-        tunnel_channel_send_init(tunnel_channel, item);
+        tunnel_channel_marshall_init(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SERVICE_IP_MAP:
-        tunnel_channel_send_service_ip_map(tunnel_channel, item);
+        tunnel_channel_marshall_service_ip_map(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_OPEN:
-        tunnel_channel_send_socket_open(tunnel_channel, item);
+        tunnel_channel_marshall_socket_open(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_DATA:
-        tunnel_channel_send_socket_out_data(tunnel_channel, item);
+        tunnel_channel_marshall_socket_out_data(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_FIN:
-        tunnel_channel_send_socket_fin(tunnel_channel, item);
+        tunnel_channel_marshall_socket_fin(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_CLOSE:
-        tunnel_channel_send_socket_close(tunnel_channel, item);
+        tunnel_channel_marshall_socket_close(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK:
-        tunnel_channel_send_socket_closed_ack(tunnel_channel, item);
+        tunnel_channel_marshall_socket_closed_ack(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_SOCKET_TOKEN:
-        tunnel_channel_send_socket_token(tunnel_channel, item);
+        tunnel_channel_marshall_socket_token(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
-        tunnel_channel_send_migrate(tunnel_channel, item);
+        tunnel_channel_marshall_migrate(tunnel_channel, m, item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        tunnel_channel_send_migrate_data(tunnel_channel, item);
+        tunnel_channel_marshall_migrate_data(tunnel_channel, m, item);
         break;
     default:
         red_error("invalid pipe item type");
     }
+    red_channel_begin_send_message(channel);
 }
 
 /* param item_pushed: distinguishes between a pipe item that was pushed for sending, and
commit a05628bf061f5c0bcbd1221f8a990487210060de
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Nov 10 09:28:39 2010 +0200

    server/red_channel (all): add red_channel_get_stream
    
    use in config_socket, this makes the stream internal to the RedChannel
    implementation that will change later for multiple client support.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 8140c04..5e2681a 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -491,15 +491,16 @@ static int inputs_channel_config_socket(RedChannel *channel)
 {
     int flags;
     int delay_val = 1;
+    RedsStream *stream = red_channel_get_stream(channel);
 
-    if (setsockopt(channel->stream->socket, IPPROTO_TCP, TCP_NODELAY,
+    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
             &delay_val, sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
         return FALSE;
     }
 
-    if ((flags = fcntl(channel->stream->socket, F_GETFL)) == -1 ||
-                 fcntl(channel->stream->socket, F_SETFL, flags | O_ASYNC) == -1) {
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1 ||
+                 fcntl(stream->socket, F_SETFL, flags | O_ASYNC) == -1) {
         red_printf("fcntl failed, %s", strerror(errno));
         return FALSE;
     }
diff --git a/server/red_channel.c b/server/red_channel.c
index 5749dc3..f8944c0 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -706,7 +706,13 @@ void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
     channel->ack_data.client_window = client_window;
 }
 
+/* accessors for RedChannel */
 SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
 {
     return channel->send_data.marshaller;
 }
+
+RedsStream *red_channel_get_stream(RedChannel *channel)
+{
+    return channel->stream;
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index 1841de4..f991f2d 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -272,6 +272,10 @@ void red_channel_pipe_clear(RedChannel *channel);
 //  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_send(RedChannel *channel);
+
+/* accessors for RedChannel */
+/* 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);
 
 #endif
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 0366290..c990bd1 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -3335,20 +3335,21 @@ static int tunnel_channel_config_socket(RedChannel *channel)
 {
     int flags;
     int delay_val;
+    RedsStream *stream = red_channel_get_stream(channel);
 
-    if ((flags = fcntl(channel->stream->socket, F_GETFL)) == -1) {
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno)); // can't we just use red_error?
         return FALSE;
     }
 
-    if (fcntl(channel->stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+    if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         return FALSE;
     }
 
     delay_val = 1;
 
-    if (setsockopt(channel->stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
+    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
                    sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
diff --git a/server/red_worker.c b/server/red_worker.c
index dd89e3f..b8e4825 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9026,7 +9026,7 @@ int common_channel_config_socket(RedChannel *channel)
 {
     int flags;
     int delay_val;
-    RedsStream *stream = channel->stream;
+    RedsStream *stream = red_channel_get_stream(channel);
 
     if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno));
commit 6b862596460802aff0604f16bb3e77c524512e84
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 23:01:39 2010 +0200

    ring: add RING_FOREACH{,_SAFE,_REVERSED}

diff --git a/common/ring.h b/common/ring.h
index defa1ed..a013a2f 100644
--- a/common/ring.h
+++ b/common/ring.h
@@ -19,6 +19,8 @@
 #ifndef _H_RING2
 #define _H_RING2
 
+#include "spice_common.h"
+
 typedef struct Ring RingItem;
 typedef struct Ring {
     RingItem *prev;
@@ -129,5 +131,24 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
     return (ret == ring) ? NULL : ret;
 }
 
+#define RING_FOREACH_SAFE(var, next, ring)                    \
+    for ((var) = ring_get_head(ring),                         \
+         (next) = (var) ? ring_next(ring, (var)) : NULL;      \
+            (var);                                            \
+            (var) = (next),                                   \
+            (next) = (var) ? ring_next(ring, (var)) : NULL)
+
+
+#define RING_FOREACH(var, ring)                 \
+    for ((var) = ring_get_head(ring);           \
+            (var);                              \
+            (var) = ring_next(ring, var))
+
+#define RING_FOREACH_REVERSED(var, ring)        \
+    for ((var) = ring_get_tail(ring);           \
+            (var);                              \
+            (var) = ring_prev(ring, var))
+
+
 #endif
 
commit 38e13ef1a87d1cd035d36f5ef0eb5f8f1359407f
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Feb 28 18:56:16 2011 +0200

    server/common: introduce common/spice_common.h
    
    move all the ASSERT/PANIC/PANIC_ON/red_error/red_printf* macros
    to a common file to be used with ring.h that is going to be used externally
    (by spice-gtk).

diff --git a/common/spice_common.h b/common/spice_common.h
new file mode 100644
index 0000000..bacd24a
--- /dev/null
+++ b/common/spice_common.h
@@ -0,0 +1,70 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef H_SPICE_COMMON
+#define H_SPICE_COMMON
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+
+#define ASSERT(x) if (!(x)) {                               \
+    printf("%s: ASSERT %s failed\n", __FUNCTION__, #x);     \
+    abort();                                                \
+}
+
+#define PANIC(format, ...) {                              \
+    printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ );   \
+    abort();                                        \
+}
+
+#define PANIC_ON(x) if ((x)) {                             \
+    printf("%s: panic %s\n", __FUNCTION__, #x);             \
+    abort();                                                \
+}
+
+#define red_error(format, ...) {                                 \
+    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );   \
+    abort();                                                     \
+}
+
+#define red_printf(format, ...) \
+    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
+
+#define red_printf_once(format, ...) {                              \
+    static int do_print = TRUE;                                     \
+    if (do_print) {                                                 \
+        do_print = FALSE;                                           \
+        printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );  \
+    }                                                               \
+}
+
+#define red_printf_some(every, format, ...) {                       \
+    static int count = 0;                                           \
+    if (count++ % (every) == 0) {                                   \
+        printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );  \
+    }                                                               \
+}
+
+static inline uint64_t get_time_stamp()
+{
+    struct timespec time_space;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    return time_space.tv_sec * 1000 * 1000 * 1000 + time_space.tv_nsec;
+}
+
+#endif
diff --git a/server/red_common.h b/server/red_common.h
index c863922..494ffed 100644
--- a/server/red_common.h
+++ b/server/red_common.h
@@ -23,47 +23,10 @@
 
 #include "spice.h"
 #include "mem.h"
+#include "spice_common.h"
 #include <messages.h>
 #include <spice/macros.h>
 
-#define ASSERT(x) if (!(x)) {                               \
-    printf("%s: ASSERT %s failed\n", __FUNCTION__, #x);     \
-    abort();                                                \
-}
-
-#define PANIC(format, ...) {                              \
-    printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ );   \
-    abort();                                        \
-}
-
-#define PANIC_ON(x) if ((x)) {                             \
-    printf("%s: panic %s\n", __FUNCTION__, #x);             \
-    abort();                                                \
-}
-
-#define red_error(format, ...) {                                 \
-    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );   \
-    abort();                                                     \
-}
-
-#define red_printf(format, ...) \
-    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
-
-#define red_printf_once(format, ...) {                              \
-    static int do_print = TRUE;                                     \
-    if (do_print) {                                                 \
-        do_print = FALSE;                                           \
-        printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );  \
-    }                                                               \
-}
-
-#define red_printf_some(every, format, ...) {                       \
-    static int count = 0;                                           \
-    if (count++ % (every) == 0) {                                   \
-        printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );  \
-    }                                                               \
-}
-
 enum {
     STREAM_VIDEO_INVALID,
     STREAM_VIDEO_OFF,
@@ -71,12 +34,5 @@ enum {
     STREAM_VIDEO_FILTER
 };
 
-static inline uint64_t get_time_stamp()
-{
-    struct timespec time_space;
-    clock_gettime(CLOCK_MONOTONIC, &time_space);
-    return time_space.tv_sec * 1000 * 1000 * 1000 + time_space.tv_nsec;
-}
-
 #endif
 
commit ce03dcfbb55d38d06e3014a6c489ea82131472fc
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 22:56:56 2010 +0200

    server/red_channel (all): handle MIGRATE_DATA and MIGRATE_FLUSH_DATA
    
    Handling done in red_channel instead of per channel, using call backs
    for the channel specific part.
    Intended to reduce furthur reliance of channels on RedChannel struct.
    
    The commit makes the code harder to understand because of the artificial
    get_serial stuff, should later be fixed by having a joint migration
    header with the serial (since all channels pass it).

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 9ebf050..8140c04 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -529,7 +529,10 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
         ,inputs_channel_send_item
         ,inputs_channel_release_pipe_item
         ,inputs_channel_on_incoming_error
-        ,inputs_channel_on_outgoing_error);
+        ,inputs_channel_on_outgoing_error
+        ,NULL
+        ,NULL
+        ,NULL);
     ASSERT(inputs_channel);
     channel->data = inputs_channel;
     inputs_pipe_add_init(inputs_channel);
diff --git a/server/main_channel.c b/server/main_channel.c
index 6acb134..75accac 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -418,11 +418,31 @@ static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int seri
     data->ping_id = ping_id;
 }
 
-static void main_channel_receive_migrate_data(MainChannel *main_chan,
-                                  MainMigrateData *data, uint8_t *end)
+static uint64_t main_channel_handle_migrate_data_get_serial(RedChannel *base,
+    uint32_t size, void *message)
 {
-    red_channel_set_message_serial(&main_chan->base, data->serial);
+    MainMigrateData *data = message;
+
+    if (size < sizeof(*data)) {
+        red_printf("bad message size");
+        return 0;
+    }
+    return data->serial;
+}
+
+static uint64_t main_channel_handle_migrate_data(RedChannel *base,
+    uint32_t size, void *message)
+{
+    MainChannel *main_chan = SPICE_CONTAINEROF(base, MainChannel, base);
+    MainMigrateData *data = message;
+
+    if (size < sizeof(*data)) {
+        red_printf("bad message size");
+        return FALSE;
+    }
     main_chan->ping_id = data->ping_id;
+    reds_on_main_receive_migrate_data(data, ((uint8_t*)message) + size);
+    return TRUE;
 }
 
 void main_channel_push_init(Channel *channel, int connection_id,
@@ -729,15 +749,9 @@ static int main_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16
         break;
     }
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        main_channel_push_migrate_data_item(main_chan);
         break;
     case SPICE_MSGC_MIGRATE_DATA: {
-            MainMigrateData *data = (MainMigrateData *)message;
-            uint8_t *end = ((uint8_t *)message) + size;
-            main_channel_receive_migrate_data(main_chan, data, end);
-            reds_on_main_receive_migrate_data(data, end);
-            break;
-        }
+                }
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
@@ -772,6 +786,12 @@ static void main_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
 }
 
+static int main_channel_handle_migrate_flush_mark(RedChannel *base)
+{
+    main_channel_push_migrate_data_item(SPICE_CONTAINEROF(base, MainChannel, base));
+    return TRUE;
+}
+
 static void main_channel_link(Channel *channel, RedsStream *stream, int migration,
                         int num_common_caps, uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
@@ -791,7 +811,10 @@ static void main_channel_link(Channel *channel, RedsStream *stream, int migratio
         ,main_channel_send_item
         ,main_channel_release_pipe_item
         ,main_channel_on_error
-        ,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;
 }
diff --git a/server/red_channel.c b/server/red_channel.c
index 9028943..5749dc3 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -322,7 +322,10 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
                                channel_release_msg_recv_buf_proc release_recv_buf,
                                channel_hold_pipe_item_proc hold_item,
                                channel_send_pipe_item_proc send_item,
-                               channel_release_pipe_item_proc release_item)
+                               channel_release_pipe_item_proc release_item,
+                               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)
 {
     RedChannel *channel;
 
@@ -336,6 +339,9 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
     channel->send_item = send_item;
     channel->release_item = release_item;
     channel->hold_item = hold_item;
+    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->stream = stream;
     channel->core = core;
@@ -406,12 +412,16 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                channel_send_pipe_item_proc send_item,
                                channel_release_pipe_item_proc release_item,
                                channel_on_incoming_error_proc incoming_error,
-                               channel_on_outgoing_error_proc outgoing_error)
+                               channel_on_outgoing_error_proc outgoing_error,
+                               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)
 {
     RedChannel *channel = red_channel_create(size, stream,
         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);
+        send_item, release_item, handle_migrate_flush_mark, handle_migrate_data,
+        handle_migrate_data_get_serial);
 
     if (channel == NULL) {
         return NULL;
@@ -454,6 +464,24 @@ void red_channel_init_outgoing_messages_window(RedChannel *channel)
     red_channel_push(channel);
 }
 
+void red_channel_handle_migrate_flush_mark(RedChannel *channel)
+{
+    if (channel->handle_migrate_flush_mark) {
+        channel->handle_migrate_flush_mark(channel);
+    }
+}
+
+void red_channel_handle_migrate_data(RedChannel *channel, uint32_t size, void *message)
+{
+    if (!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);
+}
+
 int red_channel_handle_message(RedChannel *channel, uint32_t size,
                                uint16_t type, void *message)
 {
@@ -473,6 +501,12 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
         break;
     case SPICE_MSGC_DISCONNECTING:
         break;
+    case SPICE_MSGC_MIGRATE_FLUSH_MARK:
+        red_channel_handle_migrate_flush_mark(channel);
+        break;
+    case SPICE_MSGC_MIGRATE_DATA:
+        red_channel_handle_migrate_data(channel, size, message);
+        break;
     default:
         red_printf("invalid message type %u", type);
         return FALSE;
diff --git a/server/red_channel.h b/server/red_channel.h
index 50e6789..1841de4 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -123,6 +123,12 @@ typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
 typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
 typedef void (*channel_on_outgoing_error_proc)(RedChannel *channel);
 
+typedef int (*channel_handle_migrate_flush_mark)(RedChannel *channel);
+typedef uint64_t (*channel_handle_migrate_data)(RedChannel *channel,
+                                                uint32_t size, void *message);
+typedef uint64_t (*channel_handle_migrate_data_get_serial)(RedChannel *channel,
+                                            uint32_t size, void *message);
+
 struct RedChannel {
     RedsStream *stream;
     SpiceCoreInterface *core;
@@ -166,6 +172,10 @@ struct RedChannel {
     channel_on_incoming_error_proc on_incoming_error; /* alternative to disconnect */
     channel_on_outgoing_error_proc on_outgoing_error;
     int shut; /* signal channel is to be closed */
+
+    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;
 };
 
 /* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
@@ -180,7 +190,10 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
                                channel_release_msg_recv_buf_proc release_recv_buf,
                                channel_hold_pipe_item_proc hold_item,
                                channel_send_pipe_item_proc send_item,
-                               channel_release_pipe_item_proc release_item);
+                               channel_release_pipe_item_proc release_item,
+                               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);
 
 /* alternative constructor, meant for marshaller based (inputs,main) channels,
  * will become default eventually */
@@ -196,7 +209,10 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                channel_send_pipe_item_proc send_item,
                                channel_release_pipe_item_proc release_item,
                                channel_on_incoming_error_proc incoming_error,
-                               channel_on_outgoing_error_proc outgoing_error);
+                               channel_on_outgoing_error_proc outgoing_error,
+                               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);
 
 int red_channel_is_connected(RedChannel *channel);
 
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index a85a1ad..0366290 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -1739,8 +1739,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(TunnelChannel *channel)
+static int tunnel_channel_handle_migrate_mark(RedChannel *base)
 {
+    TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
     TunnelMigrateItem *migrate_item = NULL;
     TunnelService *service;
     TunnelMigrateServiceItem *mig_service;
@@ -2153,13 +2154,32 @@ static inline void tunnel_channel_activate_migrated_sockets(TunnelChannel *chann
     }
 }
 
-static int tunnel_channel_handle_migrate_data(TunnelChannel *channel,
-                                              TunnelMigrateData *migrate_data)
+static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannel *base,
+                                              uint32_t size, void *msg)
 {
+    TunnelMigrateData *migrate_data = msg;
+
+    if (size < sizeof(TunnelMigrateData)
+        || migrate_data->magic != TUNNEL_MIGRATE_DATA_MAGIC
+        || migrate_data->version != TUNNEL_MIGRATE_DATA_VERSION) {
+        return 0;
+    }
+    return migrate_data->message_serial;
+}
+
+static uint64_t tunnel_channel_handle_migrate_data(RedChannel *base,
+                                              uint32_t size, void *msg)
+{
+    TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
     TunnelMigrateSocketList *sockets_list;
     TunnelMigrateServicesList *services_list;
+    TunnelMigrateData *migrate_data = msg;
     int i;
 
+    if (size < sizeof(TunnelMigrateData)) {
+        red_printf("bad message size");
+        goto error;
+    }
     if (!channel->expect_migrate_data) {
         red_printf("unexpected");
         goto error;
@@ -2172,9 +2192,6 @@ static int tunnel_channel_handle_migrate_data(TunnelChannel *channel,
         goto error;
     }
 
-    ASSERT(red_channel_get_message_serial(&channel->base) == 0);
-    red_channel_set_message_serial(&channel->base, migrate_data->message_serial);
-
     net_slirp_state_restore(migrate_data->data + migrate_data->slirp_state);
 
     services_list = (TunnelMigrateServicesList *)(migrate_data->data +
@@ -2314,15 +2331,6 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
 
         return tunnel_channel_handle_socket_token(tunnel_channel, sckt,
                                                   (SpiceMsgcTunnelSocketTokens *)msg);
-    case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        return tunnel_channel_handle_migrate_mark(tunnel_channel);
-    case SPICE_MSGC_MIGRATE_DATA:
-        if (header->size < sizeof(TunnelMigrateData)) {
-            red_printf("bad message size");
-            free(msg);
-            return FALSE;
-        }
-        return tunnel_channel_handle_migrate_data(tunnel_channel, (TunnelMigrateData *)msg);
     default:
         return red_channel_handle_message(channel, header->size, header->type, msg);
     }
@@ -3425,7 +3433,10 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int
                                             tunnel_channel_release_msg_rcv_buf,
                                             tunnel_channel_hold_pipe_item,
                                             tunnel_channel_send_item,
-                                            tunnel_channel_release_pipe_item);
+                                            tunnel_channel_release_pipe_item,
+                                            tunnel_channel_handle_migrate_mark,
+                                            tunnel_channel_handle_migrate_data,
+                                            tunnel_channel_handle_migrate_data_get_serial);
 
     if (!tunnel_channel) {
         return;
diff --git a/server/red_worker.c b/server/red_worker.c
index 86e512e..dd89e3f 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8926,8 +8926,10 @@ static int display_channel_handle_migrate_glz_dictionary(DisplayChannel *channel
                                                              &migrate_info->glz_dict_restore_data));
 }
 
-static int display_channel_handle_migrate_mark(DisplayChannel *channel)
+static int display_channel_handle_migrate_mark(RedChannel *base)
 {
+    DisplayChannel *channel = SPICE_CONTAINEROF(base, DisplayChannel, common.base);
+
     if (!channel->expect_migrate_mark) {
         red_printf("unexpected");
         return FALSE;
@@ -8937,28 +8939,44 @@ static int display_channel_handle_migrate_mark(DisplayChannel *channel)
     return TRUE;
 }
 
-static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t size, void *message)
+static uint64_t display_channel_handle_migrate_data_get_serial(
+                RedChannel *base, uint32_t size, void *message)
+{
+    DisplayChannelMigrateData *migrate_data = message;
+
+    if (size < sizeof(*migrate_data)) {
+        red_printf("bad message size");
+        return 0;
+    }
+    if (migrate_data->magic != DISPLAY_MIGRATE_DATA_MAGIC ||
+        migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
+        red_printf("invalid content");
+        return 0;
+    }
+    return migrate_data->message_serial;
+}
+
+static uint64_t display_channel_handle_migrate_data(RedChannel *base, uint32_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data;
     int i;
+    DisplayChannel *channel = SPICE_CONTAINEROF(base, DisplayChannel, common.base);
 
-    if (!channel->expect_migrate_data) {
-        red_printf("unexpected");
-        return FALSE;
-    }
-    channel->expect_migrate_data = FALSE;
     if (size < sizeof(*migrate_data)) {
         red_printf("bad message size");
         return FALSE;
     }
     migrate_data = (DisplayChannelMigrateData *)message;
     if (migrate_data->magic != DISPLAY_MIGRATE_DATA_MAGIC ||
-                                            migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
+        migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
         red_printf("invalid content");
         return FALSE;
     }
-    ASSERT(channel->common.base.send_data.serial == 0);
-    channel->common.base.send_data.serial = migrate_data->message_serial;
+    if (!channel->expect_migrate_data) {
+        red_printf("unexpected");
+        return FALSE;
+    }
+    channel->expect_migrate_data = FALSE;
     if (!(channel->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
         return FALSE;
     }
@@ -8999,10 +9017,6 @@ static int display_channel_handle_message(RedChannel *channel, uint32_t size, ui
         }
         ((DisplayChannel *)channel)->expect_init = FALSE;
         return display_channel_init((DisplayChannel *)channel, (SpiceMsgcDisplayInit *)message);
-    case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        return display_channel_handle_migrate_mark((DisplayChannel *)channel);
-    case SPICE_MSGC_MIGRATE_DATA:
-        return display_channel_handle_migrate_data((DisplayChannel *)channel, size, message);
     default:
         return red_channel_handle_message(channel, size, type, message);
     }
@@ -9064,7 +9078,10 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
                                  channel_send_pipe_item_proc send_item,
                                  channel_hold_pipe_item_proc hold_item,
                                  channel_release_pipe_item_proc release_item,
-                                 channel_handle_parsed_proc handle_parsed)
+                                 channel_handle_parsed_proc handle_parsed,
+                                 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)
 {
     struct epoll_event event;
     RedChannel *channel;
@@ -9081,7 +9098,10 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
                                         send_item,
                                         release_item,
                                         red_channel_default_peer_on_error,
-                                        red_channel_default_peer_on_error);
+                                        red_channel_default_peer_on_error,
+                                        handle_migrate_flush_mark,
+                                        handle_migrate_data,
+                                        handle_migrate_data_get_serial);
     common = (CommonChannel *)channel;
     if (!channel) {
         goto error;
@@ -9186,7 +9206,11 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, in
                                                             display_channel_send_item,
                                                             display_channel_hold_pipe_item,
                                                             display_channel_release_item,
-                                                            display_channel_handle_message))) {
+                                                            display_channel_handle_message,
+                                                            display_channel_handle_migrate_mark,
+                                                            display_channel_handle_migrate_data,
+                                                            display_channel_handle_migrate_data_get_serial
+                                                            ))) {
         return;
     }
 #ifdef RED_STATISTICS
@@ -9318,7 +9342,10 @@ static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrat
                                                    cursor_channel_send_item,
                                                    cursor_channel_hold_pipe_item,
                                                    cursor_channel_release_item,
-                                                   red_channel_handle_message))) {
+                                                   red_channel_handle_message,
+                                                   NULL,
+                                                   NULL,
+                                                   NULL))) {
         return;
     }
 #ifdef RED_STATISTICS
diff --git a/server/smartcard.c b/server/smartcard.c
index 3675cc1..4c50dbe 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -487,7 +487,10 @@ static void smartcard_link(Channel *channel, RedsStream *stream,
                                         smartcard_channel_release_msg_rcv_buf,
                                         smartcard_channel_hold_pipe_item,
                                         smartcard_channel_send_item,
-                                        smartcard_channel_release_pipe_item);
+                                        smartcard_channel_release_pipe_item,
+                                        NULL,
+                                        NULL,
+                                        NULL);
     if (!g_smartcard_channel) {
         return;
     }
commit 8002a30f9ce4b8cbd00f5ff8ded6f72a297a2240
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 16:00:49 2010 +0200

    server/red_channel (all): add red_channel_get_marshaller
    
    For ussage in the send_item callback. It's only valid during this
    time anyway (should make it return NULL in other occasions?)
    
    No more direct usage of RedChannel.send_data.marshaller by channels.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index c8022b2..9ebf050 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -254,8 +254,7 @@ static void inputs_channel_release_pipe_item(RedChannel *channel,
 
 static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
 {
-    InputsChannel *inputs_channel = (InputsChannel *)channel;
-    SpiceMarshaller *m = inputs_channel->base.send_data.marshaller;
+    SpiceMarshaller *m = red_channel_get_marshaller(channel);
 
     red_channel_init_send_data(channel, base->type, base);
     switch (base->type) {
diff --git a/server/main_channel.c b/server/main_channel.c
index ca77b98..6acb134 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -280,15 +280,14 @@ static void main_channel_push_channels(MainChannel *main_chan)
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_channels(MainChannel *main_chan)
+static void main_channel_marshall_channels(SpiceMarshaller *m)
 {
     SpiceMsgChannels* channels_info;
 
     channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels)
                             + reds_num_of_channels() * sizeof(SpiceChannelId));
     reds_fill_channels(channels_info);
-    spice_marshall_msg_main_channels_list(
-        main_chan->base.send_data.marshaller, channels_info);
+    spice_marshall_msg_main_channels_list(m, channels_info);
     free(channels_info);
 }
 
@@ -305,13 +304,12 @@ int main_channel_push_ping(Channel *channel, int size)
     return TRUE;
 }
 
-static void main_channel_marshall_ping(MainChannel *main_chan, int size)
+static void main_channel_marshall_ping(SpiceMarshaller *m, int size, int ping_id)
 {
     struct timespec time_space;
     SpiceMsgPing ping;
-    SpiceMarshaller *m = main_chan->base.send_data.marshaller;
 
-    ping.id = ++main_chan->ping_id;
+    ping.id = ping_id;
     clock_gettime(CLOCK_MONOTONIC, &time_space);
     ping.timestamp = time_space.tv_sec * 1000000LL + time_space.tv_nsec / 1000LL;
     spice_marshall_msg_ping(m, &ping);
@@ -334,7 +332,7 @@ void main_channel_push_mouse_mode(Channel *channel, int current_mode,
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_mouse_mode(MainChannel *main_chan, int current_mode, int is_client_mouse_allowed)
+static void main_channel_marshall_mouse_mode(SpiceMarshaller *m, int current_mode, int is_client_mouse_allowed)
 {
     SpiceMsgMainMouseMode mouse_mode;
     mouse_mode.supported_modes = SPICE_MOUSE_MODE_SERVER;
@@ -342,8 +340,7 @@ static void main_channel_marshall_mouse_mode(MainChannel *main_chan, int current
         mouse_mode.supported_modes |= SPICE_MOUSE_MODE_CLIENT;
     }
     mouse_mode.current_mode = current_mode;
-    spice_marshall_msg_main_mouse_mode(main_chan->base.send_data.marshaller,
-                                       &mouse_mode);
+    spice_marshall_msg_main_mouse_mode(m, &mouse_mode);
 }
 
 void main_channel_push_agent_connected(Channel *channel)
@@ -364,13 +361,12 @@ void main_channel_push_agent_disconnected(Channel *channel)
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_agent_disconnected(MainChannel *main_chan)
+static void main_channel_marshall_agent_disconnected(SpiceMarshaller *m)
 {
     SpiceMsgMainAgentDisconnect disconnect;
 
     disconnect.error_code = SPICE_LINK_ERR_OK;
-    spice_marshall_msg_main_agent_disconnected(
-        main_chan->base.send_data.marshaller, &disconnect);
+    spice_marshall_msg_main_agent_disconnected(m, &disconnect);
 }
 
 void main_channel_push_tokens(Channel *channel, uint32_t num_tokens)
@@ -381,13 +377,12 @@ void main_channel_push_tokens(Channel *channel, uint32_t num_tokens)
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_tokens(MainChannel *main_chan, uint32_t num_tokens)
+static void main_channel_marshall_tokens(SpiceMarshaller *m, uint32_t num_tokens)
 {
     SpiceMsgMainAgentTokens tokens;
 
     tokens.num_tokens = num_tokens;
-    spice_marshall_msg_main_agent_token(
-        main_chan->base.send_data.marshaller, &tokens);
+    spice_marshall_msg_main_agent_token(m, &tokens);
 }
 
 void main_channel_push_agent_data(Channel *channel, uint8_t* data, size_t len,
@@ -400,10 +395,10 @@ void main_channel_push_agent_data(Channel *channel, uint8_t* data, size_t len,
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_agent_data(MainChannel *main_chan,
+static void main_channel_marshall_agent_data(SpiceMarshaller *m,
                                   AgentDataPipeItem *item)
 {
-    spice_marshaller_add_ref_full(main_chan->base.send_data.marshaller,
+    spice_marshaller_add_ref_full(m,
         item->data, item->len, item->free_data, item->opaque);
 }
 
@@ -414,14 +409,13 @@ static void main_channel_push_migrate_data_item(MainChannel *main_chan)
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_migrate_data_item(MainChannel *main_chan)
+static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int serial, int ping_id)
 {
-    SpiceMarshaller *m = main_chan->base.send_data.marshaller;
     MainMigrateData *data = (MainMigrateData *)spice_marshaller_reserve_space(m, sizeof(MainMigrateData));
 
     reds_marshall_migrate_data_item(m, data); // TODO: from reds split. ugly separation.
-    data->serial = red_channel_get_message_serial(&main_chan->base);
-    data->ping_id = main_chan->ping_id;
+    data->serial = serial;
+    data->ping_id = ping_id;
 }
 
 static void main_channel_receive_migrate_data(MainChannel *main_chan,
@@ -445,7 +439,7 @@ void main_channel_push_init(Channel *channel, int connection_id,
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_init(MainChannel *main_chan,
+static void main_channel_marshall_init(SpiceMarshaller *m,
                                        InitPipeItem *item)
 {
     SpiceMsgMainInit init;
@@ -461,7 +455,7 @@ static void main_channel_marshall_init(MainChannel *main_chan,
     init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
     init.multi_media_time = item->multi_media_time;
     init.ram_hint = item->ram_hint;
-    spice_marshall_msg_main_init(main_chan->base.send_data.marshaller, &init);
+    spice_marshall_msg_main_init(m, &init);
 }
 
 void main_channel_push_notify(Channel *channel, uint8_t *mess, const int mess_len)
@@ -472,10 +466,9 @@ void main_channel_push_notify(Channel *channel, uint8_t *mess, const int mess_le
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_notify(MainChannel *main_chan, NotifyPipeItem *item)
+static void main_channel_marshall_notify(SpiceMarshaller *m, NotifyPipeItem *item)
 {
     SpiceMsgNotify notify;
-    SpiceMarshaller *m = main_chan->base.send_data.marshaller;
 
     notify.time_stamp = get_time_stamp(); // TODO - move to main_new_notify_item
     notify.severity = SPICE_NOTIFY_SEVERITY_WARN;
@@ -497,7 +490,7 @@ void main_channel_push_migrate_begin(Channel *channel, int port, int sport,
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_migrate_begin(MainChannel *main_chan,
+static void main_channel_marshall_migrate_begin(SpiceMarshaller *m,
     MigrateBeginPipeItem *item)
 {
     SpiceMsgMainMigrationBegin migrate;
@@ -509,8 +502,7 @@ static void main_channel_marshall_migrate_begin(MainChannel *main_chan,
     migrate.pub_key_type = item->cert_pub_key_type;
     migrate.pub_key_size = item->cert_pub_key_len;
     migrate.pub_key_data = item->cert_pub_key;
-    spice_marshall_msg_main_migrate_begin(main_chan->base.send_data.marshaller,
-                                          &migrate);
+    spice_marshall_msg_main_migrate_begin(m, &migrate);
 }
 
 void main_channel_push_migrate(Channel *channel)
@@ -521,12 +513,12 @@ void main_channel_push_migrate(Channel *channel)
     red_channel_pipe_add_push(&main_chan->base, &item->base);
 }
 
-static void main_channel_marshall_migrate(MainChannel *main_chan)
+static void main_channel_marshall_migrate(SpiceMarshaller *m)
 {
     SpiceMsgMigrate migrate;
 
     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    spice_marshall_msg_migrate(main_chan->base.send_data.marshaller, &migrate);
+    spice_marshall_msg_migrate(m, &migrate);
 }
 
 void main_channel_push_migrate_cancel(Channel *channel)
@@ -564,85 +556,86 @@ void main_channel_push_migrate_switch(Channel *channel)
         main_migrate_switch_item_new(main_chan));
 }
 
-static void main_channel_marshall_migrate_switch(MainChannel *main_chan)
+static void main_channel_marshall_migrate_switch(SpiceMarshaller *m)
 {
     SpiceMsgMainMigrationSwitchHost migrate;
 
     red_printf("");
 
     reds_fill_mig_switch(&migrate);
-    spice_marshall_msg_main_migrate_switch_host(
-        main_chan->base.send_data.marshaller, &migrate);
+    spice_marshall_msg_main_migrate_switch_host(m, &migrate);
 
     reds_mig_release();
 }
 
-static void main_channel_marshall_multi_media_time(MainChannel *main_chan,
+static void main_channel_marshall_multi_media_time(SpiceMarshaller *m,
     MultiMediaTimePipeItem *item)
 {
     SpiceMsgMainMultiMediaTime time_mes;
 
     time_mes.time = item->time;
-    spice_marshall_msg_main_multi_media_time(
-        main_chan->base.send_data.marshaller, &time_mes);
+    spice_marshall_msg_main_multi_media_time(m, &time_mes);
 }
 
 static void main_channel_send_item(RedChannel *channel, PipeItem *base)
 {
+    SpiceMarshaller *m = red_channel_get_marshaller(channel);
     MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
 
     red_channel_init_send_data(channel, base->type, base);
     switch (base->type) {
         case SPICE_MSG_MAIN_CHANNELS_LIST:
-            main_channel_marshall_channels(main_chan);
+            main_channel_marshall_channels(m);
             break;
         case SPICE_MSG_PING:
-            main_channel_marshall_ping(main_chan,
-                SPICE_CONTAINEROF(base, PingPipeItem, base)->size);
+            main_channel_marshall_ping(m,
+                SPICE_CONTAINEROF(base, PingPipeItem, base)->size, ++main_chan->ping_id);
             break;
         case SPICE_MSG_MAIN_MOUSE_MODE:
             {
                 MouseModePipeItem *item =
                     SPICE_CONTAINEROF(base, MouseModePipeItem, base);
-                main_channel_marshall_mouse_mode(main_chan,
+                main_channel_marshall_mouse_mode(m,
                     item->current_mode, item->is_client_mouse_allowed);
                 break;
             }
         case SPICE_MSG_MAIN_AGENT_DISCONNECTED:
-            main_channel_marshall_agent_disconnected(main_chan);
+            main_channel_marshall_agent_disconnected(m);
             break;
         case SPICE_MSG_MAIN_AGENT_TOKEN:
-            main_channel_marshall_tokens(main_chan,
+            main_channel_marshall_tokens(m,
                 SPICE_CONTAINEROF(base, TokensPipeItem, base)->tokens);
             break;
         case SPICE_MSG_MAIN_AGENT_DATA:
-            main_channel_marshall_agent_data(main_chan,
+            main_channel_marshall_agent_data(m,
                 SPICE_CONTAINEROF(base, AgentDataPipeItem, base));
             break;
         case SPICE_MSG_MIGRATE_DATA:
-            main_channel_marshall_migrate_data_item(main_chan);
+            main_channel_marshall_migrate_data_item(m,
+                red_channel_get_message_serial(&main_chan->base),
+                main_chan->ping_id);
             break;
         case SPICE_MSG_MAIN_INIT:
-            main_channel_marshall_init(main_chan,
+            main_channel_marshall_init(m,
                 SPICE_CONTAINEROF(base, InitPipeItem, base));
             break;
         case SPICE_MSG_NOTIFY:
-            main_channel_marshall_notify(main_chan,
+            main_channel_marshall_notify(m,
                 SPICE_CONTAINEROF(base, NotifyPipeItem, base));
             break;
         case SPICE_MSG_MIGRATE:
-            main_channel_marshall_migrate(main_chan);
+            main_channel_marshall_migrate(m);
             break;
         case SPICE_MSG_MAIN_MIGRATE_BEGIN:
-            main_channel_marshall_migrate_begin(main_chan,
+            main_channel_marshall_migrate_begin(m,
                 SPICE_CONTAINEROF(base, MigrateBeginPipeItem, base));
             break;
         case SPICE_MSG_MAIN_MULTI_MEDIA_TIME:
-            main_channel_marshall_multi_media_time(main_chan,
+            main_channel_marshall_multi_media_time(m,
                 SPICE_CONTAINEROF(base, MultiMediaTimePipeItem, base));
             break;
         case SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST:
-            main_channel_marshall_migrate_switch(main_chan);
+            main_channel_marshall_migrate_switch(m);
             break;
     };
     red_channel_begin_send_message(channel);
diff --git a/server/red_channel.c b/server/red_channel.c
index 5201da7..9028943 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -672,3 +672,7 @@ void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
     channel->ack_data.client_window = client_window;
 }
 
+SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
+{
+    return channel->send_data.marshaller;
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index 8e01c7a..50e6789 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -256,5 +256,6 @@ void red_channel_pipe_clear(RedChannel *channel);
 //  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_send(RedChannel *channel);
+SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel);
 
 #endif
diff --git a/server/red_worker.c b/server/red_worker.c
index ad5727d..86e512e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4454,16 +4454,15 @@ static inline void fill_rects_clip(SpiceMarshaller *m, SpiceClipRects *data)
     }
 }
 
-static void fill_base(DisplayChannel *display_channel, Drawable *drawable)
+static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
-    RedChannel *channel = &display_channel->common.base;
     SpiceMsgDisplayBase base;
 
     base.surface_id = drawable->surface_id;
     base.box = drawable->red_drawable->bbox;
     base.clip = drawable->red_drawable->clip;
 
-    spice_marshall_DisplayBase(channel->send_data.marshaller, &base);
+    spice_marshall_DisplayBase(base_marshaller, &base);
 }
 
 static inline void fill_palette(DisplayChannel *display_channel,
@@ -6293,6 +6292,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
 
 static void red_send_qxl_draw_fill(RedWorker *worker,
                                    DisplayChannel *display_channel,
+                                   SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6302,9 +6302,9 @@ static void red_send_qxl_draw_fill(RedWorker *worker,
     SpiceFill fill;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_FILL, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     fill = drawable->u.fill;
-    spice_marshall_Fill(channel->send_data.marshaller,
+    spice_marshall_Fill(base_marshaller,
                         &fill,
                         &brush_pat_out,
                         &mask_bitmap_out);
@@ -6319,6 +6319,7 @@ static void red_send_qxl_draw_fill(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
                                          DisplayChannel *display_channel,
+                                         SpiceMarshaller *m,
                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6347,7 +6348,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_send_qxl_draw_fill(worker, display_channel, item);
+        red_send_qxl_draw_fill(worker, display_channel, 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);
@@ -6375,6 +6376,7 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
 
 static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
                                              DisplayChannel *display_channel,
+                                             SpiceMarshaller *base_marshaller,
                                              Drawable *item, int src_allowed_lossy)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6386,9 +6388,9 @@ static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
     FillBitsType src_send_type;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     opaque = drawable->u.opaque;
-    spice_marshall_Opaque(channel->send_data.marshaller,
+    spice_marshall_Opaque(base_marshaller,
                           &opaque,
                           &src_bitmap_out,
                           &brush_pat_out,
@@ -6407,6 +6409,7 @@ static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
                                            DisplayChannel *display_channel,
+                                           SpiceMarshaller *m,
                                            Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6438,7 +6441,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_send_qxl_draw_opaque(worker, display_channel, item, src_allowed_lossy);
+        src_send_type = red_send_qxl_draw_opaque(worker, display_channel, m, item, src_allowed_lossy);
 
         if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
             src_is_lossy = TRUE;
@@ -6471,6 +6474,7 @@ static void red_lossy_send_qxl_draw_opaque(RedWorker *worker,
 
 static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
                                            DisplayChannel *display_channel,
+                                           SpiceMarshaller *base_marshaller,
                                            Drawable *item, int src_allowed_lossy)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6481,9 +6485,9 @@ static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
     FillBitsType src_send_type;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     copy = drawable->u.copy;
-    spice_marshall_Copy(channel->send_data.marshaller,
+    spice_marshall_Copy(base_marshaller,
                         &copy,
                         &src_bitmap_out,
                         &mask_bitmap_out);
@@ -6496,6 +6500,7 @@ static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
                                          DisplayChannel *display_channel,
+                                         SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6507,7 +6512,7 @@ static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.copy.src_bitmap,
                                    &drawable->u.copy.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_send_qxl_draw_copy(worker, display_channel, item, TRUE);
+    src_send_type = red_send_qxl_draw_copy(worker, display_channel, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6521,6 +6526,7 @@ static void red_lossy_send_qxl_draw_copy(RedWorker *worker,
 
 static void red_send_qxl_draw_transparent(RedWorker *worker,
                                           DisplayChannel *display_channel,
+                                          SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6529,9 +6535,9 @@ static void red_send_qxl_draw_transparent(RedWorker *worker,
     SpiceTransparent transparent;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     transparent = drawable->u.transparent;
-    spice_marshall_Transparent(channel->send_data.marshaller,
+    spice_marshall_Transparent(base_marshaller,
                                &transparent,
                                &src_bitmap_out);
     fill_bits(display_channel, src_bitmap_out, transparent.src_bitmap, item, FALSE);
@@ -6539,6 +6545,7 @@ static void red_send_qxl_draw_transparent(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
                                                 DisplayChannel *display_channel,
+                                                SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6549,7 +6556,7 @@ static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
                                    &drawable->u.transparent.src_area, item, &src_bitmap_data);
 
     if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
-        red_send_qxl_draw_transparent(worker, display_channel, item);
+        red_send_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
 
         // don't update surface lossy region since transperent areas might be lossy
     } else {
@@ -6566,6 +6573,7 @@ static void red_lossy_send_qxl_draw_transparent(RedWorker *worker,
 
 static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
                                                   DisplayChannel *display_channel,
+                                                  SpiceMarshaller *base_marshaller,
                                                   Drawable *item,
                                                   int src_allowed_lossy)
 {
@@ -6576,9 +6584,9 @@ static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
     FillBitsType src_send_type;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     alpha_blend = drawable->u.alpha_blend;
-    spice_marshall_AlphaBlend(channel->send_data.marshaller,
+    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);
@@ -6588,6 +6596,7 @@ static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
                                                 DisplayChannel *display_channel,
+                                                SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6598,7 +6607,7 @@ static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(display_channel, drawable->u.alpha_blend.src_bitmap,
                                    &drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_send_qxl_draw_alpha_blend(worker, display_channel, item, TRUE);
+    src_send_type = red_send_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -6613,6 +6622,7 @@ static void red_lossy_send_qxl_draw_alpha_blend(RedWorker *worker,
 
 static void red_send_qxl_copy_bits(RedWorker *worker,
                                    DisplayChannel *display_channel,
+                                   SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6620,14 +6630,15 @@ static void red_send_qxl_copy_bits(RedWorker *worker,
     SpicePoint copy_bits;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_COPY_BITS, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     copy_bits = drawable->u.copy_bits.src_pos;
-    spice_marshall_Point(channel->send_data.marshaller,
+    spice_marshall_Point(base_marshaller,
                          &copy_bits);
 }
 
 static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
                                          DisplayChannel *display_channel,
+                                         SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6637,7 +6648,7 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
     int src_is_lossy;
     SpiceRect src_lossy_area;
 
-    red_send_qxl_copy_bits(worker, display_channel, item);
+    red_send_qxl_copy_bits(worker, display_channel, 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;
@@ -6656,6 +6667,7 @@ static void red_lossy_send_qxl_copy_bits(RedWorker *worker,
 
 static void red_send_qxl_draw_blend(RedWorker *worker,
                                     DisplayChannel *display_channel,
+                                    SpiceMarshaller *base_marshaller,
                                     Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6665,9 +6677,9 @@ static void red_send_qxl_draw_blend(RedWorker *worker,
     SpiceBlend blend;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLEND, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     blend = drawable->u.blend;
-    spice_marshall_Blend(channel->send_data.marshaller,
+    spice_marshall_Blend(base_marshaller,
                          &blend,
                          &src_bitmap_out,
                          &mask_bitmap_out);
@@ -6679,6 +6691,7 @@ static void red_send_qxl_draw_blend(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
                                           DisplayChannel *display_channel,
+                                          SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6694,7 +6707,7 @@ static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
 
     if (!dest_is_lossy &&
         (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_send_qxl_draw_blend(worker, display_channel, item);
+        red_send_qxl_draw_blend(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6719,6 +6732,7 @@ static void red_lossy_send_qxl_draw_blend(RedWorker *worker,
 
 static void red_send_qxl_draw_blackness(RedWorker *worker,
                                         DisplayChannel *display_channel,
+                                        SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6727,10 +6741,10 @@ static void red_send_qxl_draw_blackness(RedWorker *worker,
     SpiceBlackness blackness;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     blackness = drawable->u.blackness;
 
-    spice_marshall_Blackness(channel->send_data.marshaller,
+    spice_marshall_Blackness(base_marshaller,
                              &blackness,
                              &mask_bitmap_out);
 
@@ -6739,18 +6753,20 @@ static void red_send_qxl_draw_blackness(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_blackness(RedWorker *worker,
                                               DisplayChannel *display_channel,
+                                              SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
-    red_send_qxl_draw_blackness(worker, display_channel, item);
+    red_send_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
 static void red_send_qxl_draw_whiteness(RedWorker *worker,
                                         DisplayChannel *display_channel,
+                                        SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -6759,10 +6775,10 @@ static void red_send_qxl_draw_whiteness(RedWorker *worker,
     SpiceWhiteness whiteness;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     whiteness = drawable->u.whiteness;
 
-    spice_marshall_Whiteness(channel->send_data.marshaller,
+    spice_marshall_Whiteness(base_marshaller,
                              &whiteness,
                              &mask_bitmap_out);
 
@@ -6771,18 +6787,20 @@ static void red_send_qxl_draw_whiteness(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_whiteness(RedWorker *worker,
                                               DisplayChannel *display_channel,
+                                              SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
-    red_send_qxl_draw_whiteness(worker, display_channel, item);
+    red_send_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
 
     surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
 }
 
 static void red_send_qxl_draw_inverse(RedWorker *worker,
                                         DisplayChannel *display_channel,
+                                        SpiceMarshaller *base_marshaller,
                                         Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6791,10 +6809,10 @@ static void red_send_qxl_draw_inverse(RedWorker *worker,
     SpiceInvers inverse;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     inverse = drawable->u.invers;
 
-    spice_marshall_Invers(channel->send_data.marshaller,
+    spice_marshall_Invers(base_marshaller,
                           &inverse,
                           &mask_bitmap_out);
 
@@ -6803,13 +6821,15 @@ static void red_send_qxl_draw_inverse(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_inverse(RedWorker *worker,
                                             DisplayChannel *display_channel,
+                                            SpiceMarshaller *base_marshaller,
                                             Drawable *item)
 {
-    red_send_qxl_draw_inverse(worker, display_channel, item);
+    red_send_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
 }
 
 static void red_send_qxl_draw_rop3(RedWorker *worker,
                                    DisplayChannel *display_channel,
+                                   SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6820,9 +6840,9 @@ static void red_send_qxl_draw_rop3(RedWorker *worker,
     SpiceMarshaller *mask_bitmap_out;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ROP3, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     rop3 = drawable->u.rop3;
-    spice_marshall_Rop3(channel->send_data.marshaller,
+    spice_marshall_Rop3(base_marshaller,
                         &rop3,
                         &src_bitmap_out,
                         &brush_pat_out,
@@ -6838,6 +6858,7 @@ static void red_send_qxl_draw_rop3(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
                                          DisplayChannel *display_channel,
+                                         SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6859,7 +6880,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_send_qxl_draw_rop3(worker, display_channel, item);
+        red_send_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
 
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
@@ -6892,6 +6913,7 @@ static void red_lossy_send_qxl_draw_rop3(RedWorker *worker,
 
 static void red_send_qxl_draw_stroke(RedWorker *worker,
                                      DisplayChannel *display_channel,
+                                     SpiceMarshaller *base_marshaller,
                                      Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6901,9 +6923,9 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
     SpiceMarshaller *style_out;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_STROKE, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     stroke = drawable->u.stroke;
-    spice_marshall_Stroke(channel->send_data.marshaller,
+    spice_marshall_Stroke(base_marshaller,
                           &stroke,
                           &style_out,
                           &brush_pat_out);
@@ -6916,6 +6938,7 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
                                            DisplayChannel *display_channel,
+                                           SpiceMarshaller *base_marshaller,
                                            Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6943,7 +6966,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_send_qxl_draw_stroke(worker, display_channel, item);
+        red_send_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6970,6 +6993,7 @@ static void red_lossy_send_qxl_draw_stroke(RedWorker *worker,
 
 static void red_send_qxl_draw_text(RedWorker *worker,
                                    DisplayChannel *display_channel,
+                                   SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -6979,9 +7003,9 @@ static void red_send_qxl_draw_text(RedWorker *worker,
     SpiceMarshaller *back_brush_pat_out;
 
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TEXT, &item->pipe_item);
-    fill_base(display_channel, item);
+    fill_base(base_marshaller, item);
     text = drawable->u.text;
-    spice_marshall_Text(channel->send_data.marshaller,
+    spice_marshall_Text(base_marshaller,
                         &text,
                         &brush_pat_out,
                         &back_brush_pat_out);
@@ -6996,6 +7020,7 @@ static void red_send_qxl_draw_text(RedWorker *worker,
 
 static void red_lossy_send_qxl_draw_text(RedWorker *worker,
                                          DisplayChannel *display_channel,
+                                         SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
@@ -7031,7 +7056,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_send_qxl_draw_text(worker, display_channel, item);
+        red_send_qxl_draw_text(worker, display_channel, base_marshaller, item);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -7060,47 +7085,47 @@ static void red_lossy_send_qxl_draw_text(RedWorker *worker,
 }
 
 static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
-                                   Drawable *item)
+                                        SpiceMarshaller *base_marshaller, Drawable *item)
 {
     switch (item->red_drawable->type) {
     case QXL_DRAW_FILL:
-        red_lossy_send_qxl_draw_fill(worker, display_channel, item);
+        red_lossy_send_qxl_draw_fill(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_OPAQUE:
-        red_lossy_send_qxl_draw_opaque(worker, display_channel, item);
+        red_lossy_send_qxl_draw_opaque(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_COPY:
-        red_lossy_send_qxl_draw_copy(worker, display_channel, item);
+        red_lossy_send_qxl_draw_copy(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_lossy_send_qxl_draw_transparent(worker, display_channel, item);
+        red_lossy_send_qxl_draw_transparent(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_lossy_send_qxl_draw_alpha_blend(worker, display_channel, item);
+        red_lossy_send_qxl_draw_alpha_blend(worker, display_channel, base_marshaller, item);
         break;
     case QXL_COPY_BITS:
-        red_lossy_send_qxl_copy_bits(worker, display_channel, item);
+        red_lossy_send_qxl_copy_bits(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_BLEND:
-        red_lossy_send_qxl_draw_blend(worker, display_channel, item);
+        red_lossy_send_qxl_draw_blend(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_lossy_send_qxl_draw_blackness(worker, display_channel, item);
+        red_lossy_send_qxl_draw_blackness(worker, display_channel, base_marshaller, item);
         break;
      case QXL_DRAW_WHITENESS:
-        red_lossy_send_qxl_draw_whiteness(worker, display_channel, item);
+        red_lossy_send_qxl_draw_whiteness(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_INVERS:
-        red_lossy_send_qxl_draw_inverse(worker, display_channel, item);
+        red_lossy_send_qxl_draw_inverse(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_ROP3:
-        red_lossy_send_qxl_draw_rop3(worker, display_channel, item);
+        red_lossy_send_qxl_draw_rop3(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_STROKE:
-        red_lossy_send_qxl_draw_stroke(worker, display_channel, item);
+        red_lossy_send_qxl_draw_stroke(worker, display_channel, base_marshaller, item);
         break;
     case QXL_DRAW_TEXT:
-        red_lossy_send_qxl_draw_text(worker, display_channel, item);
+        red_lossy_send_qxl_draw_text(worker, display_channel, base_marshaller, item);
         break;
     default:
         red_error("invalid type");
@@ -7113,49 +7138,49 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
 }
 
 static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel,
-                                         Drawable *item)
+                                         SpiceMarshaller *m, Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
 
     switch (drawable->type) {
     case QXL_DRAW_FILL:
-        red_send_qxl_draw_fill(worker, display_channel, item);
+        red_send_qxl_draw_fill(worker, display_channel, m, item);
         break;
     case QXL_DRAW_OPAQUE:
-        red_send_qxl_draw_opaque(worker, display_channel, item, FALSE);
+        red_send_qxl_draw_opaque(worker, display_channel, m, item, FALSE);
         break;
     case QXL_DRAW_COPY:
-        red_send_qxl_draw_copy(worker, display_channel, item, FALSE);
+        red_send_qxl_draw_copy(worker, display_channel, m, item, FALSE);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_send_qxl_draw_transparent(worker, display_channel, item);
+        red_send_qxl_draw_transparent(worker, display_channel, m, item);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_send_qxl_draw_alpha_blend(worker, display_channel, item, FALSE);
+        red_send_qxl_draw_alpha_blend(worker, display_channel, m, item, FALSE);
         break;
     case QXL_COPY_BITS:
-        red_send_qxl_copy_bits(worker, display_channel, item);
+        red_send_qxl_copy_bits(worker, display_channel, m, item);
         break;
     case QXL_DRAW_BLEND:
-        red_send_qxl_draw_blend(worker, display_channel, item);
+        red_send_qxl_draw_blend(worker, display_channel, m, item);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_send_qxl_draw_blackness(worker, display_channel, item);
+        red_send_qxl_draw_blackness(worker, display_channel, m, item);
         break;
     case QXL_DRAW_WHITENESS:
-        red_send_qxl_draw_whiteness(worker, display_channel, item);
+        red_send_qxl_draw_whiteness(worker, display_channel, m, item);
         break;
     case QXL_DRAW_INVERS:
-        red_send_qxl_draw_inverse(worker, display_channel, item);
+        red_send_qxl_draw_inverse(worker, display_channel, m, item);
         break;
     case QXL_DRAW_ROP3:
-        red_send_qxl_draw_rop3(worker, display_channel, item);
+        red_send_qxl_draw_rop3(worker, display_channel, m, item);
         break;
     case QXL_DRAW_STROKE:
-        red_send_qxl_draw_stroke(worker, display_channel, item);
+        red_send_qxl_draw_stroke(worker, display_channel, m, item);
         break;
     case QXL_DRAW_TEXT:
-        red_send_qxl_draw_text(worker, display_channel, item);
+        red_send_qxl_draw_text(worker, display_channel, m, item);
         break;
     default:
         red_error("invalid type");
@@ -7444,7 +7469,8 @@ static int red_rgb16bpp_to_24 (RedWorker *worker, const SpiceRect *src,
     return TRUE;
 }
 
-static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable *drawable)
+static inline int red_send_stream_data(DisplayChannel *display_channel,
+                  SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
     Stream *stream = drawable->stream;
     SpiceImage *image;
@@ -7525,8 +7551,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     stream_data.id = stream - worker->streams_buf;
     stream_data.multi_media_time = drawable->red_drawable->mm_time;
     stream_data.data_size = n;
-    spice_marshall_msg_display_stream_data(channel->send_data.marshaller, &stream_data);
-    spice_marshaller_add_ref(channel->send_data.marshaller,
+    spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
+    spice_marshaller_add_ref(base_marshaller,
                              display_channel->send_data.stream_outbuf, n);
 
     display_begin_send_message(display_channel);
@@ -7534,16 +7560,18 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     return TRUE;
 }
 
-static inline void send_qxl_drawable(DisplayChannel *display_channel, Drawable *item)
+static inline void send_qxl_drawable(DisplayChannel *display_channel,
+    SpiceMarshaller *m, Drawable *item)
 {
     ASSERT(display_channel);
-    if (item->stream && red_send_stream_data(display_channel, item)) {
+
+    if (item->stream && red_send_stream_data(display_channel, m, item)) {
         return;
     }
     if (!display_channel->enable_jpeg)
-        red_send_qxl_drawable(display_channel->common.worker, display_channel, item);
+        red_send_qxl_drawable(display_channel->common.worker, display_channel, m, item);
     else
-        red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, item);
+        red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, m, item);
 }
 
 static inline void red_send_verb(RedChannel *channel, uint16_t verb)
@@ -7560,35 +7588,38 @@ static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
     display_begin_send_message(channel);
 }
 
-static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item)
+static inline void __red_send_inval(RedChannel *channel,
+        SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
     SpiceMsgDisplayInvalOne inval_one;
 
     red_channel_init_send_data(channel, cach_item->inval_type, NULL);
     inval_one.id = *(uint64_t *)&cach_item->id;
 
-    spice_marshall_msg_cursor_inval_one(channel->send_data.marshaller, &inval_one);
+    spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
-static void red_send_inval(RedChannel *channel, CacheItem *cach_item)
+static void red_send_inval(RedChannel *channel,
+            SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
-    __red_send_inval(channel, cach_item);
+    __red_send_inval(channel, base_marshaller, cach_item);
     red_channel_begin_send_message(channel);
 }
 
-static void red_display_send_inval(DisplayChannel *display_channel, CacheItem *cach_item)
+static void red_display_send_inval(DisplayChannel *display_channel,
+                SpiceMarshaller *base_marshaller, CacheItem *cach_item)
 {
-    __red_send_inval((RedChannel *)display_channel, cach_item);
+    __red_send_inval((RedChannel *)display_channel, base_marshaller, cach_item);
     display_begin_send_message(display_channel);
 }
 
-static void display_channel_send_migrate(DisplayChannel *display_channel)
+static void display_channel_send_migrate(DisplayChannel *display_channel, SpiceMarshaller *base_marshaller)
 {
     SpiceMsgMigrate migrate;
 
     red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    spice_marshall_msg_migrate(display_channel->common.base.send_data.marshaller, &migrate);
+    spice_marshall_msg_migrate(base_marshaller, &migrate);
     display_channel->expect_migrate_mark = TRUE;
     display_begin_send_message(display_channel);
 }
@@ -7662,7 +7693,7 @@ static void display_channel_reset_cache(DisplayChannel *display_channel)
     display_begin_send_message(display_channel);
 }
 
-static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
+static void red_send_image(DisplayChannel *display_channel, SpiceMarshaller *m, ImageItem *item)
 {
     RedChannel *channel;
     SpiceImage red_image;
@@ -7723,8 +7754,6 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     copy.data.mask.pos.y = 0;
     copy.data.mask.bitmap = 0;
 
-    SpiceMarshaller *m = channel->send_data.marshaller;
-
     spice_marshall_msg_display_draw_copy(m, &copy,
                                          &src_bitmap_out, &mask_bitmap_out);
 
@@ -7800,7 +7829,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     spice_chunks_destroy(chunks);
 }
 
-static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeItem *item)
+static void red_display_send_upgrade(DisplayChannel *display_channel, SpiceMarshaller *m, UpgradeItem *item)
 {
     RedChannel *channel;
     RedDrawable *red_drawable;
@@ -7823,8 +7852,6 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     copy.base.clip.rects = item->rects;
     copy.data = red_drawable->u.copy;
 
-    SpiceMarshaller *m = channel->send_data.marshaller;
-
     spice_marshall_msg_display_draw_copy(m, &copy,
                                          &src_bitmap_out, &mask_bitmap_out);
 
@@ -7833,7 +7860,8 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     display_begin_send_message(display_channel);
 }
 
-static void red_display_send_stream_start(DisplayChannel *display_channel, StreamAgent *agent)
+static void red_display_send_stream_start(DisplayChannel *display_channel,
+                     SpiceMarshaller *base_marshaller, StreamAgent *agent)
 {
     RedChannel *channel = &display_channel->common.base;
     Stream *stream = agent->stream;
@@ -7865,13 +7893,14 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
         stream_create.clip.rects = &clip_rects;
     }
 
-    spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create);
+    spice_marshall_msg_display_stream_create(base_marshaller, &stream_create);
 
 
     display_begin_send_message(display_channel);
 }
 
 static void red_display_send_stream_clip(DisplayChannel *display_channel,
+                                         SpiceMarshaller *base_marshaller,
                                          StreamClipItem *item)
 {
     RedChannel *channel = &display_channel->common.base;
@@ -7888,12 +7917,13 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
     stream_clip.clip.type = item->clip_type;
     stream_clip.clip.rects = item->rects;
 
-    spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip);
+    spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip);
 
     display_begin_send_message(display_channel);
 }
 
-static void red_display_send_stream_end(DisplayChannel *display_channel, StreamAgent* agent)
+static void red_display_send_stream_end(DisplayChannel *display_channel,
+                   SpiceMarshaller *base_marshaller, StreamAgent* agent)
 {
     RedChannel *channel = &display_channel->common.base;
     SpiceMsgDisplayStreamDestroy destroy;
@@ -7901,15 +7931,16 @@ static void red_display_send_stream_end(DisplayChannel *display_channel, StreamA
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
     destroy.id = agent - display_channel->stream_agents;
 
-    spice_marshall_msg_display_stream_destroy(channel->send_data.marshaller, &destroy);
+    spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
 
     display_begin_send_message(display_channel);
 }
 
-static void red_cursor_send_inval(CursorChannel *channel, CacheItem *cach_item)
+static void red_cursor_send_inval(CursorChannel *channel,
+                SpiceMarshaller *m, CacheItem *cach_item)
 {
     ASSERT(channel);
-    red_send_inval((RedChannel *)channel, cach_item);
+    red_send_inval((RedChannel *)channel, m, cach_item);
 }
 
 static void red_send_cursor_init(CursorChannel *channel)
@@ -7935,7 +7966,8 @@ static void red_send_cursor_init(CursorChannel *channel)
     red_channel_begin_send_message(&channel->common.base);
 }
 
-static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
+static void red_send_local_cursor(CursorChannel *cursor_channel,
+          SpiceMarshaller *base_marshaller, LocalCursor *cursor)
 {
     RedChannel *channel;
     SpiceMsgCursorSet cursor_set;
@@ -7950,8 +7982,8 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
     cursor_set.visible = worker->cursor_visible;
 
     fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
-    spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
-    add_buf_from_info(channel, channel->send_data.marshaller, &info);
+    spice_marshall_msg_cursor_set(base_marshaller, &cursor_set);
+    add_buf_from_info(channel, base_marshaller, &info);
 
     red_channel_begin_send_message(channel);
 
@@ -7969,18 +8001,17 @@ static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
     red_channel_begin_send_message((RedChannel*)cursor_channel);
 }
 
-static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
+static void red_send_cursor(CursorChannel *cursor_channel,
+                   SpiceMarshaller *m, CursorItem *cursor)
 {
     RedChannel *channel;
     RedCursorCmd *cmd;
-    SpiceMarshaller *m;
     RedWorker *worker;
 
     ASSERT(cursor_channel);
 
     channel = &cursor_channel->common.base;
     worker = cursor_channel->common.worker;
-    m = channel->send_data.marshaller;
 
     cmd = cursor->red_cursor;
     switch (cmd->type) {
@@ -8028,7 +8059,8 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
     red_release_cursor(worker, cursor);
 }
 
-static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCreate *surface_create)
+static void red_send_surface_create(DisplayChannel *display,
+    SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
 {
     RedChannel *channel;
 
@@ -8038,12 +8070,13 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
     region_init(&display->surface_client_lossy_region[surface_create->surface_id]);
     red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
 
-    spice_marshall_msg_display_surface_create(channel->send_data.marshaller, surface_create);
+    spice_marshall_msg_display_surface_create(base_marshaller, surface_create);
 
     red_channel_begin_send_message(channel);
 }
 
-static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_id)
+static void red_send_surface_destroy(DisplayChannel *display,
+       SpiceMarshaller *base_marshaller, uint32_t surface_id)
 {
     RedChannel *channel;
     SpiceMsgSurfaceDestroy surface_destroy;
@@ -8056,13 +8089,14 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
 
     surface_destroy.surface_id = surface_id;
 
-    spice_marshall_msg_display_surface_destroy(channel->send_data.marshaller, &surface_destroy);
+    spice_marshall_msg_display_surface_destroy(base_marshaller, &surface_destroy);
 
     red_channel_begin_send_message(channel);
 }
 
 static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
 {
+    SpiceMarshaller *m = red_channel_get_marshaller(base);
     DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(base);
     RedWorker *worker = display_channel->common.worker;
 
@@ -8070,34 +8104,34 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_DRAW: {
         Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
-        send_qxl_drawable(display_channel, drawable);
+        send_qxl_drawable(display_channel, m, drawable);
         release_drawable(worker, drawable);
         break;
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_display_send_inval(display_channel, (CacheItem *)pipe_item);
+        red_display_send_inval(display_channel, 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_send_stream_start(display_channel, agent);
+        red_display_send_stream_start(display_channel, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_CLIP: {
         StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
-        red_display_send_stream_clip(display_channel, clip_item);
+        red_display_send_stream_clip(display_channel, 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_send_stream_end(display_channel, agent);
+        red_display_send_stream_end(display_channel, m, agent);
         red_display_release_stream(display_channel, agent);
         break;
     }
     case PIPE_ITEM_TYPE_UPGRADE:
-        red_display_send_upgrade(display_channel, (UpgradeItem *)pipe_item);
+        red_display_send_upgrade(display_channel, m, (UpgradeItem *)pipe_item);
         release_upgrade_item(worker, (UpgradeItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
@@ -8106,7 +8140,7 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         break;
     case PIPE_ITEM_TYPE_MIGRATE:
         red_printf("PIPE_ITEM_TYPE_MIGRATE");
-        display_channel_send_migrate(display_channel);
+        display_channel_send_migrate(display_channel, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
@@ -8114,7 +8148,7 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_IMAGE:
-        red_send_image(display_channel, (ImageItem *)pipe_item);
+        red_send_image(display_channel, m, (ImageItem *)pipe_item);
         release_image_item((ImageItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
@@ -8133,14 +8167,14 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     case PIPE_ITEM_TYPE_CREATE_SURFACE: {
         SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem,
                                                               pipe_item);
-        red_send_surface_create(display_channel, &surface_create->surface_create);
+        red_send_surface_create(display_channel, 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_send_surface_destroy(display_channel, surface_destroy->surface_destroy.surface_id);
+        red_send_surface_destroy(display_channel, m, surface_destroy->surface_destroy.surface_id);
         free(surface_destroy);
         break;
     }
@@ -8152,18 +8186,19 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
 
 static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
 {
+    SpiceMarshaller *m = red_channel_get_marshaller(channel);
     CursorChannel *cursor_channel = SPICE_CONTAINEROF(channel, CursorChannel, common.base);
 
     red_ref_channel(channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
-        red_send_cursor(cursor_channel, (CursorItem *)pipe_item);
+        red_send_cursor(cursor_channel, m, (CursorItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_LOCAL_CURSOR:
-        red_send_local_cursor(cursor_channel, (LocalCursor *)pipe_item);
+        red_send_local_cursor(cursor_channel, m, (LocalCursor *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_ONE:
-        red_cursor_send_inval(cursor_channel, (CacheItem *)pipe_item);
+        red_cursor_send_inval(cursor_channel, m, (CacheItem *)pipe_item);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
@@ -8277,7 +8312,6 @@ static void red_disconnect_channel(RedChannel *channel)
     channel->stream = NULL;
     channel->send_data.blocked = FALSE;
     channel->send_data.size = 0;
-    spice_marshaller_reset(channel->send_data.marshaller);
     red_unref_channel(channel);
 }
 
commit 9e46945a6189cff9a41b79b2bca70f0aacc60305
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 15:28:11 2010 +0200

    server/red_worker: use red_channel_destroy

diff --git a/server/red_worker.c b/server/red_worker.c
index b387967..ad5727d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7265,8 +7265,7 @@ static inline void red_unref_channel(RedChannel *channel)
     ASSERT(channel);
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     if (!--common->listener.refs) {
-        spice_marshaller_destroy(channel->send_data.marshaller);
-        free(channel);
+        red_channel_destroy(channel);
     }
 }
 
commit 966201c1ad5823c73c90981a1d70a02616140efa
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 14:23:36 2010 +0200

    server/inputs_channel: s/PIPE_ITEM_INIT/PIPE_ITEM_INPUTS_INIT/

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 9dedc93..c8022b2 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -64,7 +64,7 @@ typedef struct InputsChannel {
 } InputsChannel;
 
 enum {
-    PIPE_ITEM_INIT = SPICE_MSG_INPUTS_INIT,
+    PIPE_ITEM_INPUTS_INIT = SPICE_MSG_INPUTS_INIT,
     PIPE_ITEM_MOUSE_MOTION_ACK = SPICE_MSG_INPUTS_MOUSE_MOTION_ACK,
     PIPE_ITEM_KEY_MODIFIERS = SPICE_MSG_INPUTS_KEY_MODIFIERS,
     PIPE_ITEM_MIGRATE = SPICE_MSG_MIGRATE,
@@ -267,7 +267,7 @@ static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
                 SPICE_CONTAINEROF(base, KeyModifiersPipeItem, base)->modifiers;
             spice_marshall_msg_inputs_key_modifiers(m, &key_modifiers);
         }
-        case PIPE_ITEM_INIT:
+        case PIPE_ITEM_INPUTS_INIT:
         {
             SpiceMsgInputsInit inputs_init;
 
@@ -483,7 +483,7 @@ static void inputs_pipe_add_init(InputsChannel *inputs_channel)
     InputsInitPipeItem *item = spice_malloc(sizeof(InputsInitPipeItem));
 
     red_channel_pipe_item_init(&inputs_channel->base, &item->base,
-                               PIPE_ITEM_INIT);
+                               PIPE_ITEM_INPUTS_INIT);
     item->modifiers = kbd_get_leds(keyboard);
     red_channel_pipe_add_push(&inputs_channel->base, &item->base);
 }
commit 5e1ba1101bf0f64deaead21ad1c5d4669ebb4a8c
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 11:57:13 2010 +0200

    server/red_channel: move SET_ACK to red_channel

diff --git a/server/red_channel.c b/server/red_channel.c
index 17db700..5201da7 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include "stat.h"
 #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);
@@ -253,10 +254,33 @@ static void red_channel_reset_send_data(RedChannel *channel)
     channel->send_data.header->serial = ++channel->send_data.serial;
 }
 
+void red_channel_push_set_ack(RedChannel *channel)
+{
+    red_channel_pipe_add_type(channel, PIPE_ITEM_TYPE_SET_ACK);
+}
+
+static void red_channel_send_set_ack(RedChannel *channel)
+{
+    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;
+
+    spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
+
+    red_channel_begin_send_message(channel);
+}
+
 static void red_channel_send_item(RedChannel *channel, PipeItem *item)
 {
     red_channel_reset_send_data(channel);
     switch (item->type) {
+        case PIPE_ITEM_TYPE_SET_ACK:
+            red_channel_send_set_ack(channel);
+            return;
     }
     /* only reached if not handled here */
     channel->send_item(channel, item);
@@ -265,6 +289,9 @@ static void red_channel_send_item(RedChannel *channel, PipeItem *item)
 static void red_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
 {
     switch (item->type) {
+        case PIPE_ITEM_TYPE_SET_ACK:
+            free(item);
+            return;
     }
     /* only reached if not handled here */
     channel->release_item(channel, item, item_pushed);
diff --git a/server/red_channel.h b/server/red_channel.h
index 2d90de1..8e01c7a 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -89,6 +89,16 @@ typedef struct BufDescriptor {
     uint8_t *data;
 } BufDescriptor;
 
+/* 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,
+ * but we keep the 100 first allocated for base channel approach.
+ * */
+enum {
+    PIPE_ITEM_TYPE_SET_ACK=1,
+    PIPE_ITEM_TYPE_CHANNEL_BASE=101,
+};
+
 typedef struct PipeItem {
     RingItem link;
     int type;
@@ -226,6 +236,7 @@ void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type);
 
 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: 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
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 054a8eb..a85a1ad 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -67,8 +67,7 @@
 typedef struct TunnelWorker TunnelWorker;
 
 enum {
-    PIPE_ITEM_TYPE_SET_ACK,
-    PIPE_ITEM_TYPE_MIGRATE,
+    PIPE_ITEM_TYPE_MIGRATE = PIPE_ITEM_TYPE_CHANNEL_BASE,
     PIPE_ITEM_TYPE_MIGRATE_DATA,
     PIPE_ITEM_TYPE_TUNNEL_INIT,
     PIPE_ITEM_TYPE_SERVICE_IP_MAP,
@@ -2334,19 +2333,6 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
 /* outgoing msgs
 ********************************/
 
-static void tunnel_channel_send_set_ack(TunnelChannel *channel, PipeItem *item)
-{
-    ASSERT(channel);
-
-    channel->base.send_data.u.ack.generation = ++channel->base.ack_data.generation;
-    channel->base.send_data.u.ack.window = CLIENT_ACK_WINDOW;
-
-    red_channel_init_send_data(&channel->base, SPICE_MSG_SET_ACK, item);
-    red_channel_add_buf(&channel->base, &channel->base.send_data.u.ack, sizeof(SpiceMsgSetAck));
-
-    red_channel_begin_send_message(&channel->base);
-}
-
 static void tunnel_channel_send_migrate(TunnelChannel *channel, PipeItem *item)
 {
     ASSERT(channel);
@@ -2813,9 +2799,6 @@ static void tunnel_channel_send_item(RedChannel *channel, PipeItem *item)
     TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
 
     switch (item->type) {
-    case PIPE_ITEM_TYPE_SET_ACK:
-        tunnel_channel_send_set_ack(tunnel_channel, item);
-        break;
     case PIPE_ITEM_TYPE_TUNNEL_INIT:
         tunnel_channel_send_init(tunnel_channel, item);
         break;
@@ -2860,7 +2843,6 @@ static void tunnel_channel_release_pipe_item(RedChannel *channel, PipeItem *item
         return;
     }
     switch (item->type) {
-    case PIPE_ITEM_TYPE_SET_ACK:
     case PIPE_ITEM_TYPE_TUNNEL_INIT:
         free(item);
         break;
@@ -3409,7 +3391,7 @@ static void tunnel_channel_disconnect(RedChannel *channel)
 
 static void on_new_tunnel_channel(TunnelChannel *channel)
 {
-    red_channel_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_push_set_ack(&channel->base);
 
     if (channel->base.migrate) {
         channel->expect_migrate_data = TRUE;
diff --git a/server/red_worker.c b/server/red_worker.c
index 0bb624f..b387967 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -231,12 +231,11 @@ enum {
 };
 
 enum {
-    PIPE_ITEM_TYPE_DRAW,
+    PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_CHANNEL_BASE,
     PIPE_ITEM_TYPE_INVAL_ONE,
     PIPE_ITEM_TYPE_CURSOR,
     PIPE_ITEM_TYPE_MIGRATE,
     PIPE_ITEM_TYPE_LOCAL_CURSOR,
-    PIPE_ITEM_TYPE_SET_ACK,
     PIPE_ITEM_TYPE_CURSOR_INIT,
     PIPE_ITEM_TYPE_IMAGE,
     PIPE_ITEM_TYPE_STREAM_CREATE,
@@ -7548,21 +7547,6 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel, Drawable *
         red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, item);
 }
 
-static void red_send_set_ack(RedChannel *channel)
-{
-    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;
-
-    spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
-
-    red_channel_begin_send_message(channel);
-}
-
 static inline void red_send_verb(RedChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
@@ -8130,10 +8114,6 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
         display_channel_send_migrate_data(display_channel);
         free(pipe_item);
         break;
-    case PIPE_ITEM_TYPE_SET_ACK:
-        red_send_set_ack((RedChannel *)display_channel);
-        free(pipe_item);
-        break;
     case PIPE_ITEM_TYPE_IMAGE:
         red_send_image(display_channel, (ImageItem *)pipe_item);
         release_image_item((ImageItem *)pipe_item);
@@ -8196,10 +8176,6 @@ static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
         cursor_channel_send_migrate(cursor_channel);
         free(pipe_item);
         break;
-    case PIPE_ITEM_TYPE_SET_ACK:
-        red_send_set_ack(channel);
-        free(pipe_item);
-        break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
         red_reset_cursor_cache(cursor_channel);
         red_send_cursor_init(cursor_channel);
@@ -8672,7 +8648,7 @@ static void on_new_display_channel(RedWorker *worker)
     DisplayChannel *display_channel = worker->display_channel;
     ASSERT(display_channel);
 
-    red_channel_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_push_set_ack(&display_channel->common.base);
 
     if (display_channel->common.base.migrate) {
         display_channel->expect_migrate_data = TRUE;
@@ -9158,8 +9134,6 @@ static void display_channel_release_item(RedChannel *channel, PipeItem *item, in
     case PIPE_ITEM_TYPE_IMAGE:
         release_image_item((ImageItem *)item);
         break;
-    case PIPE_ITEM_TYPE_SET_ACK:
-        break;
     default:
         PANIC("invalid item type");
     }
@@ -9272,7 +9246,7 @@ static void on_new_cursor_channel(RedWorker *worker)
 
     ASSERT(channel);
     red_channel_ack_zero_messages_window(&channel->common.base);
-    red_channel_pipe_add_type(&channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_push_set_ack(&channel->common.base);
     if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
         red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
@@ -9293,9 +9267,6 @@ static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int
         case PIPE_ITEM_TYPE_CURSOR:
             red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
             break;
-        case PIPE_ITEM_TYPE_SET_ACK:
-            free(item);
-            break;
         default:
             PANIC("invalid item type");
     }
commit 2fcd35b073a20bfb67ab6fd14234ec7571220ec7
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 11:45:57 2010 +0200

    server/red_channel: add more ack api

diff --git a/server/red_channel.c b/server/red_channel.c
index 4492cfb..17db700 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -635,3 +635,13 @@ void red_channel_pipe_clear(RedChannel *channel)
     channel->pipe_size = 0;
 }
 
+void red_channel_ack_zero_messages_window(RedChannel *channel)
+{
+    channel->ack_data.messages_window = 0;
+}
+
+void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
+{
+    channel->ack_data.client_window = client_window;
+}
+
diff --git a/server/red_channel.h b/server/red_channel.h
index 9563c0e..2d90de1 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -224,6 +224,9 @@ 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_ack_zero_messages_window(RedChannel *channel);
+void red_channel_ack_set_client_window(RedChannel *channel, int client_window);
+
 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
 // adding elements or on events. but not sure if this is actually required (only result
 // should be that they ""try"" a little harder, but if the event system is correct it
diff --git a/server/red_worker.c b/server/red_worker.c
index adf73a1..0bb624f 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8682,7 +8682,7 @@ static void on_new_display_channel(RedWorker *worker)
     if (!display_channel_wait_for_init(display_channel)) {
         return;
     }
-    display_channel->common.base.ack_data.messages_window = 0;
+    red_channel_ack_zero_messages_window(&display_channel->common.base);
     if (worker->surfaces[0].context.canvas) {
         red_current_flush(worker, 0);
         push_new_primary_surface(worker);
@@ -8976,8 +8976,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
     }
 
     red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-
-    channel->common.base.ack_data.messages_window = 0;
+    red_channel_ack_zero_messages_window(&channel->common.base);
     return TRUE;
 }
 
@@ -9085,8 +9084,8 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     common->worker = worker;
     // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
     // make sense, does it?
-    channel->ack_data.client_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
-                                                      NARROW_CLIENT_ACK_WINDOW;
+    red_channel_ack_set_client_window(channel,
+        IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
 
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = &common->listener;
@@ -9272,8 +9271,7 @@ static void on_new_cursor_channel(RedWorker *worker)
     CursorChannel *channel = worker->cursor_channel;
 
     ASSERT(channel);
-
-    channel->common.base.ack_data.messages_window = 0;
+    red_channel_ack_zero_messages_window(&channel->common.base);
     red_channel_pipe_add_type(&channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
     if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
         red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
commit 766bb420bbba536113fbcc689d23b38b77cd0b39
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 11:37:35 2010 +0200

    server: use red_channel_get_message_serial

diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index 75112c3..74553c0 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -40,7 +40,7 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, CHANNEL *channe
     NewCacheItem *item;
     uint64_t serial;
 
-    serial = channel_message_serial((RedChannel *)channel);
+    serial = red_channel_get_message_serial((RedChannel *)channel);
     pthread_mutex_lock(&cache->lock);
     item = cache->hash_table[CACHE_HASH_KEY(id)];
 
@@ -88,7 +88,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 = channel_message_serial((RedChannel *)channel);
+    serial = red_channel_get_message_serial((RedChannel *)channel);
 
     pthread_mutex_lock(&cache->lock);
 
@@ -172,7 +172,7 @@ static void FUNC_NAME(reset)(CACHE *cache, CHANNEL *channel, SpiceMsgWaitForChan
     uint64_t serial;
     uint32_t i;
 
-    serial = channel_message_serial((RedChannel *)channel);
+    serial = red_channel_get_message_serial((RedChannel *)channel);
     pthread_mutex_lock(&cache->lock);
     PRIVATE_FUNC_NAME(clear)(cache);
 
diff --git a/server/red_worker.c b/server/red_worker.c
index ed15eda..adf73a1 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1259,11 +1259,6 @@ static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *i
     red_channel_pipe_add_after(&worker->display_channel->common.base, &item->link, pos);
 }
 
-static inline uint64_t channel_message_serial(RedChannel *channel)
-{
-    return channel->send_data.header->serial;
-}
-
 static void release_image_item(ImageItem *item)
 {
     if (!--item->refs) {
@@ -7626,7 +7621,7 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel)
     ASSERT(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
     display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
 
-    display_data.message_serial = channel_message_serial((RedChannel *)display_channel);
+    display_data.message_serial = red_channel_get_message_serial((RedChannel *)display_channel);
 
     display_data.pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
     display_data.pixmap_cache_id = display_channel->pixmap_cache->id;
commit 17b6a58f1eb27f5042a02eb690e127ee58987c25
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Nov 9 11:30:39 2010 +0200

    server/red_channel (all): makes red_channel_reset_send_data private
    
    ready the way for handling ack messages in RedChannel.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index ce532ca..9dedc93 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -257,7 +257,6 @@ static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
     InputsChannel *inputs_channel = (InputsChannel *)channel;
     SpiceMarshaller *m = inputs_channel->base.send_data.marshaller;
 
-    red_channel_reset_send_data(channel);
     red_channel_init_send_data(channel, base->type, base);
     switch (base->type) {
         case PIPE_ITEM_KEY_MODIFIERS:
diff --git a/server/main_channel.c b/server/main_channel.c
index 64048da..ca77b98 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -591,7 +591,6 @@ static void main_channel_send_item(RedChannel *channel, PipeItem *base)
 {
     MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
 
-    red_channel_reset_send_data(channel);
     red_channel_init_send_data(channel, base->type, base);
     switch (base->type) {
         case SPICE_MSG_MAIN_CHANNELS_LIST:
diff --git a/server/red_channel.c b/server/red_channel.c
index 7bc1b68..4492cfb 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -241,12 +241,41 @@ static void red_channel_peer_on_out_block(void *opaque)
                                      SPICE_WATCH_EVENT_WRITE);
 }
 
+static void red_channel_reset_send_data(RedChannel *channel)
+{
+    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;
+}
+
+static void red_channel_send_item(RedChannel *channel, PipeItem *item)
+{
+    red_channel_reset_send_data(channel);
+    switch (item->type) {
+    }
+    /* only reached if not handled here */
+    channel->send_item(channel, item);
+}
+
+static void red_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
+{
+    switch (item->type) {
+    }
+    /* only reached if not handled here */
+    channel->release_item(channel, item, item_pushed);
+}
+
 static void red_channel_peer_on_out_msg_done(void *opaque)
 {
     RedChannel *channel = (RedChannel *)opaque;
     channel->send_data.size = 0;
     if (channel->send_data.item) {
-        channel->release_item(channel, channel->send_data.item, TRUE);
+        red_channel_release_item(channel, channel->send_data.item, TRUE);
         channel->send_data.item = NULL;
     }
     if (channel->send_data.blocked) {
@@ -447,18 +476,6 @@ void red_channel_add_buf(RedChannel *channel, void *data, uint32_t size)
     channel->send_data.header->size += size;
 }
 
-void red_channel_reset_send_data(RedChannel *channel)
-{
-    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;
-}
-
 void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item)
 {
     ASSERT(channel->send_data.item == NULL);
@@ -503,7 +520,7 @@ void red_channel_push(RedChannel *channel)
     }
 
     while ((pipe_item = red_channel_pipe_get(channel))) {
-        channel->send_item(channel, pipe_item);
+        red_channel_send_item(channel, pipe_item);
     }
     channel->during_send = FALSE;
 }
@@ -609,11 +626,11 @@ void red_channel_pipe_clear(RedChannel *channel)
 
     ASSERT(channel);
     if (channel->send_data.item) {
-        channel->release_item(channel, channel->send_data.item, TRUE);
+        red_channel_release_item(channel, channel->send_data.item, TRUE);
     }
     while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
         ring_remove(&item->link);
-        channel->release_item(channel, item, FALSE);
+        red_channel_release_item(channel, item, FALSE);
     }
     channel->pipe_size = 0;
 }
diff --git a/server/red_channel.h b/server/red_channel.h
index fb5af99..9563c0e 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -203,9 +203,8 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
 /* default error handler that disconnects channel */
 void red_channel_default_peer_on_error(RedChannel *channel);
 
-/* when preparing send_data: should call reset, then init and then add_buf per buffer that is
+/* when preparing send_data: should call init and then add_buf per buffer that is
    being sent */
-void red_channel_reset_send_data(RedChannel *channel);
 void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item);
 void red_channel_add_buf(RedChannel *channel, void *data, uint32_t size);
 
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 2e6a336..054a8eb 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -2812,7 +2812,6 @@ static void tunnel_channel_send_item(RedChannel *channel, PipeItem *item)
 {
     TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
 
-    red_channel_reset_send_data(channel);
     switch (item->type) {
     case PIPE_ITEM_TYPE_SET_ACK:
         tunnel_channel_send_set_ack(tunnel_channel, item);
diff --git a/server/red_worker.c b/server/red_worker.c
index aeaaa8b..ed15eda 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -5928,7 +5928,6 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
 
 static inline void red_display_reset_send_data(DisplayChannel *channel)
 {
-    red_channel_reset_send_data((RedChannel *)channel);
     red_display_reset_compress_buf(channel);
     channel->send_data.free_list.res->count = 0;
     memset(channel->send_data.free_list.sync, 0, sizeof(channel->send_data.free_list.sync));
@@ -8182,7 +8181,6 @@ static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
     CursorChannel *cursor_channel = SPICE_CONTAINEROF(channel, CursorChannel, common.base);
 
     red_ref_channel(channel);
-    red_channel_reset_send_data(channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
         red_send_cursor(cursor_channel, (CursorItem *)pipe_item);
diff --git a/server/smartcard.c b/server/smartcard.c
index 6afa7cd..3675cc1 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -309,7 +309,6 @@ static void smartcard_channel_send_item(RedChannel *channel, PipeItem *item)
 {
     SmartCardChannel *smartcard_channel = (SmartCardChannel *)channel;
 
-    red_channel_reset_send_data(channel);
     switch (item->type) {
     case PIPE_ITEM_TYPE_ERROR:
         smartcard_channel_send_error(smartcard_channel, item);
commit cd99a0b4b36ce4ff3962df085189a585301e212d
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 15:16:52 2010 +0200

    server/red_worker: use red_channel

diff --git a/server/red_worker.c b/server/red_worker.c
index 3614eb8..aeaaa8b 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -57,6 +57,7 @@
 #include "demarshallers.h"
 #include "generated_marshallers.h"
 #include "zlib_encoder.h"
+#include "red_channel.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -252,11 +253,6 @@ enum {
     PIPE_ITEM_TYPE_DESTROY_SURFACE,
 };
 
-typedef struct PipeItem {
-    RingItem link;
-    int type;
-} PipeItem;
-
 typedef struct VerbItem {
     PipeItem base;
     uint16_t verb;
@@ -347,81 +343,6 @@ typedef struct LocalCursor {
 #define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
 #define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
 
-typedef struct RedChannel RedChannel;
-typedef void (*channel_disconnect_proc)(RedChannel *channel);
-typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
-typedef void (*channel_send_pipe_item_proc)(RedChannel *channel, PipeItem *item);
-typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, PipeItem *item, int item_pushed);
-typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type, void *message);
-
-#define MAX_SEND_VEC 100
-
-typedef int (*get_outgoing_msg_size_proc)(void *opaque);
-typedef void (*prepare_outgoing_proc)(void *opaque, struct iovec *vec, int *vec_size, int pos);
-typedef void (*on_outgoing_error_proc)(void *opaque);
-typedef void (*on_outgoing_block_proc)(void *opaque);
-typedef void (*on_outgoing_msg_done_proc)(void *opaque);
-
-typedef struct OutgoingHandler {
-    void *opaque;
-    struct iovec vec_buf[MAX_SEND_VEC];
-    int vec_size;
-    struct iovec *vec;
-    int pos;
-    int size;
-    get_outgoing_msg_size_proc get_msg_size;
-    prepare_outgoing_proc prepare;
-    on_outgoing_error_proc on_error;
-    on_outgoing_block_proc on_block;
-    on_outgoing_msg_done_proc on_msg_done;
-#ifdef RED_STATISTICS
-    uint64_t *out_bytes_counter;
-#endif
-} OutgoingHandler;
-
-struct RedChannel {
-    spice_parse_channel_func_t parser;
-    RedsStream *stream;
-    int migrate;
-
-    Ring pipe;
-    uint32_t pipe_size;
-
-    struct {
-        uint32_t client_window;
-        uint32_t generation;
-        uint32_t client_generation;
-        uint32_t messages_window;
-    } ack_data;
-
-    struct {
-        int blocked;
-        uint64_t serial;
-        SpiceDataHeader *header;
-        SpiceMarshaller *marshaller;
-        uint32_t size;
-        uint32_t pos;
-        void *item;
-    } send_data;
-
-    struct {
-        uint8_t buf[RECIVE_BUF_SIZE];
-        SpiceDataHeader *message;
-        uint8_t *now;
-        uint8_t *end;
-    } incoming;
-
-    OutgoingHandler outgoing;
-
-    channel_disconnect_proc disconnect;
-    channel_hold_pipe_item_proc hold_item;
-    channel_release_pipe_item_proc release_item;
-    channel_handle_parsed_proc handle_parsed;
-    channel_send_pipe_item_proc send_item;
-
-    int during_send;
-};
-
 typedef struct ImageItem {
     PipeItem link;
     int refs;
@@ -637,6 +558,7 @@ typedef struct CommonChannel {
     EventListener listener;
     uint32_t id;
     struct RedWorker *worker;
+    uint8_t recv_buf[RECIVE_BUF_SIZE];
 } CommonChannel;
 
 
@@ -990,7 +912,6 @@ typedef struct BitmapData {
 
 static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
 static void red_current_flush(RedWorker *worker, int surface_id);
-static void red_channel_push(RedChannel *channel);
 #ifdef DRAW_ALL
 #define red_update_area(worker, rect, surface_id)
 #define red_draw_drawable(worker, item)
@@ -1004,9 +925,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 red_channel_begin_send_message(RedChannel *channel);
 static inline void display_begin_send_message(DisplayChannel *channel);
-static void red_channel_receive(RedChannel *channel);
 static void red_release_pixmap_cache(DisplayChannel *channel);
 static void red_release_glz(DisplayChannel *channel);
 static void red_freeze_glz(DisplayChannel *channel);
@@ -1204,36 +1123,12 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
            draw_item->base.rgn.extents.y2);
 }
 
-static void red_channel_init_send_data(RedChannel *channel, uint16_t type, PipeItem *item)
-{
-    if (item) {
-        channel->hold_item(channel, item);
-        ASSERT(channel->send_data.item == NULL);
-        channel->send_data.item = item;
-    }
-    channel->send_data.header->type = type;
-}
-
 static inline void red_pipe_item_init(PipeItem *item, int type)
 {
     ring_item_init(&item->link);
     item->type = type;
 }
 
-static inline void red_channel_pipe_add(RedChannel *channel, PipeItem *item)
-{
-    ASSERT(channel);
-    channel->pipe_size++;
-    ring_add(&channel->pipe, &item->link);
-}
-
-static inline void red_channel_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos)
-{
-    ASSERT(channel && pos);
-    channel->pipe_size++;
-    ring_add_after(&item->link, &pos->link);
-}
-
 static inline int pipe_item_is_linked(PipeItem *item)
 {
     return ring_item_is_linked(&item->link);
@@ -1259,13 +1154,6 @@ static void red_pipe_add_verb(RedChannel* channel, uint16_t verb)
     red_channel_pipe_add(channel, &item->base);
 }
 
-static void red_channel_pipe_add_type(RedChannel* channel, int pipe_item_type)
-{
-    PipeItem *item = spice_new(PipeItem, 1);
-    red_pipe_item_init(item, pipe_item_type);
-    red_channel_pipe_add(channel, item);
-}
-
 static inline void red_create_surface_item(RedWorker *worker, int surface_id);
 static void red_add_surface_image(RedWorker *worker, int surface_id);
 
@@ -1392,19 +1280,16 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
     }
 }
 
-static void red_channel_pipe_clear(RedChannel *channel)
+static uint8_t *common_alloc_recv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
 {
-    PipeItem *item;
+    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
 
-    ASSERT(channel);
-    if (channel->send_data.item) {
-        channel->release_item(channel, channel->send_data.item, TRUE);
-    }
-    while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
-        ring_remove(&item->link);
-        channel->release_item(channel, item, FALSE);
-    }
-    channel->pipe_size = 0;
+    return common->recv_buf;
+}
+
+static void common_release_recv_buf(RedChannel *channel, SpiceDataHeader *msg_header, uint8_t* msg)
+{
+    return;
 }
 
 #define CLIENT_PIXMAPS_CACHE
@@ -6041,19 +5926,6 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
     }
 }
 
-static inline void red_channel_reset_send_data(RedChannel *channel)
-{
-    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.pos = 0;
-    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;
-}
-
 static inline void red_display_reset_send_data(DisplayChannel *channel)
 {
     red_channel_reset_send_data((RedChannel *)channel);
@@ -7307,83 +7179,6 @@ static void inline channel_release_res(RedChannel *channel)
     channel->send_data.item = NULL;
 }
 
-static void red_channel_peer_prepare_out_msg(void *opaque, struct iovec *vec,
-                                             int *vec_size, int pos)
-{
-    RedChannel *channel = (RedChannel *)opaque;
-
-    *vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
-                                            vec, MAX_SEND_VEC, pos);
-}
-
-static void red_channel_peer_on_out_block(void *opaque)
-{
-    RedChannel *channel = (RedChannel *)opaque;
-
-    channel->send_data.blocked = TRUE;
-}
-
-static void red_channel_peer_on_out_msg_done(void *opaque)
-{
-    RedChannel *channel = (RedChannel *)opaque;
-
-    channel->send_data.size = 0;
-    if (channel->send_data.item) {
-        channel->release_item(channel, channel->send_data.item, TRUE);
-        channel->send_data.item = NULL;
-    }
-    channel->send_data.blocked = FALSE;
-}
-
-static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
-{
-    int n;
-
-    ASSERT(stream);
-    if (handler->size == 0) {
-        handler->vec = handler->vec_buf;
-        handler->size = handler->get_msg_size(handler->opaque);
-        if (!handler->size) {  // nothing to be sent
-            return;
-        }
-    }
-    for (;;) {
-        handler->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
-        n = reds_stream_writev(stream, handler->vec, handler->vec_size);
-        if (n == -1) {
-            switch (errno) {
-            case EAGAIN:
-                handler->on_block(handler->opaque);
-                return;
-            case EINTR:
-                break;
-            case EPIPE:
-                handler->on_error(handler->opaque);
-                return;
-            default:
-                red_printf("%s", strerror(errno));
-                handler->on_error(handler->opaque);
-                return;
-            }
-        } else {
-            handler->pos += n;
-            stat_inc_counter(handler->out_bytes_counter, n);
-            if (handler->pos == handler->size) { // finished writing data
-                handler->on_msg_done(handler->opaque);
-                handler->vec = handler->vec_buf;
-                handler->pos = 0;
-                handler->size = 0;
-                return;
-            }
-        }
-    }
-}
-
-static void red_channel_send(RedChannel *channel)
-{
-    red_peer_handle_outgoing(channel->stream, &channel->outgoing);
-}
-
 static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
                                          uint64_t* sync_data)
 {
@@ -7408,16 +7203,6 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
     free_list->res->resources[free_list->res->count++].id = id;
 }
 
-static inline 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);
-}
-
 static inline void display_begin_send_message(DisplayChannel *channel)
 {
     FreeList *free_list = &channel->send_data.free_list;
@@ -8299,25 +8084,6 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
     red_channel_begin_send_message(channel);
 }
 
-static inline int red_channel_waiting_for_ack(RedChannel *channel)
-{
-    return (channel->ack_data.messages_window > channel->ack_data.client_window * 2);
-}
-
-static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
-{
-    PipeItem *item;
-    if (!channel || channel->send_data.blocked ||
-        red_channel_waiting_for_ack(channel) ||
-        !(item = (PipeItem *)ring_get_tail(&channel->pipe))) {
-        return NULL;
-    }
-
-    --channel->pipe_size;
-    ring_remove(&item->link);
-    return item;
-}
-
 static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
 {
     DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(base);
@@ -8411,29 +8177,6 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     red_unref_channel(&display_channel->common.base);
 }
 
-void red_channel_push(RedChannel *channel)
-{
-    PipeItem *pipe_item;
-
-    if (!channel) {
-        return;
-    }
-    if (!channel->during_send) {
-        channel->during_send = TRUE;
-    } else {
-        return;
-    }
-
-    if (channel->send_data.blocked) {
-        red_channel_send(channel);
-    }
-
-    while ((pipe_item = red_channel_pipe_get(channel))) {
-        channel->send_item(channel, pipe_item);
-    }
-    channel->during_send = FALSE;
-}
-
 static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
 {
     CursorChannel *cursor_channel = SPICE_CONTAINEROF(channel, CursorChannel, common.base);
@@ -8557,11 +8300,7 @@ void red_show_tree(RedWorker *worker)
     }
 }
 
-static inline int red_channel_is_connected(RedChannel *channel)
-{
-    return !!channel->stream;
-}
-
+// TODO: move to red_channel
 static void red_disconnect_channel(RedChannel *channel)
 {
     channel_release_res(channel);
@@ -8569,7 +8308,7 @@ static void red_disconnect_channel(RedChannel *channel)
     reds_stream_free(channel->stream);
     channel->stream = NULL;
     channel->send_data.blocked = FALSE;
-    channel->send_data.size = channel->send_data.pos = 0;
+    channel->send_data.size = 0;
     spice_marshaller_reset(channel->send_data.marshaller);
     red_unref_channel(channel);
 }
@@ -8962,26 +8701,6 @@ static void on_new_display_channel(RedWorker *worker)
     }
 }
 
-static int red_channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
-{
-    switch (type) {
-    case SPICE_MSGC_ACK_SYNC:
-        channel->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;
-        }
-        break;
-    case SPICE_MSGC_DISCONNECTING:
-        break;
-    default:
-        red_printf("invalid message type %u", type);
-        return FALSE;
-    }
-    return TRUE;
-}
-
 static GlzSharedDictionary *_red_find_glz_dictionary(uint8_t dict_id)
 {
     RingItem *now;
@@ -9288,79 +9007,6 @@ static int display_channel_handle_message(RedChannel *channel, uint32_t size, ui
     }
 }
 
-static void red_channel_receive(RedChannel *channel)
-{
-    for (;;) {
-        ssize_t n;
-        n = channel->incoming.end - channel->incoming.now;
-        ASSERT(n);
-        ASSERT(channel->stream);
-        n = reds_stream_read(channel->stream, channel->incoming.now, n);
-        if (n <= 0) {
-            if (n == 0) {
-                channel->disconnect(channel);
-                return;
-            }
-            ASSERT(n == -1);
-            switch (errno) {
-            case EAGAIN:
-                return;
-            case EINTR:
-                break;
-            case EPIPE:
-                channel->disconnect(channel);
-                return;
-            default:
-                red_printf("%s", strerror(errno));
-                channel->disconnect(channel);
-                return;
-            }
-        } else {
-            channel->incoming.now += n;
-            for (;;) {
-                SpiceDataHeader *header = channel->incoming.message;
-                uint8_t *data = (uint8_t *)(header+1);
-                size_t parsed_size;
-                uint8_t *parsed;
-                message_destructor_t parsed_free;
-
-                n = channel->incoming.now - (uint8_t *)header;
-                if (n < sizeof(SpiceDataHeader) ||
-                    n < sizeof(SpiceDataHeader) + header->size) {
-                    break;
-                }
-                parsed = channel->parser((void *)data, data + header->size, header->type,
-                                         SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
-
-                if (parsed == NULL) {
-                    red_printf("failed to parse message type %d", header->type);
-                    channel->disconnect(channel);
-                    return;
-                }
-
-                if (!channel->handle_parsed(channel, parsed_size, header->type, parsed)) {
-                    free(parsed);
-                    channel->disconnect(channel);
-                    return;
-                }
-                parsed_free(parsed);
-                channel->incoming.message = (SpiceDataHeader *)((uint8_t *)header +
-                                                                   sizeof(SpiceDataHeader) +
-                                                                   header->size);
-            }
-
-            if (channel->incoming.now == (uint8_t *)channel->incoming.message) {
-                channel->incoming.now = channel->incoming.buf;
-                channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
-            } else if (channel->incoming.now == channel->incoming.end) {
-                memcpy(channel->incoming.buf, channel->incoming.message, n);
-                channel->incoming.now = channel->incoming.buf + n;
-                channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
-            }
-        }
-    }
-}
-
 int common_channel_config_socket(RedChannel *channel)
 {
     int flags;
@@ -9391,19 +9037,25 @@ static void free_common_channel_from_listener(EventListener *ctx)
 
     free(common);
 }
-
-static void red_channel_default_peer_on_error(RedChannel *channel)
+void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
 {
-    channel->disconnect(channel);
 }
 
-static int red_channel_peer_get_out_msg_size(void *opaque)
+SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
-    RedChannel *channel = (RedChannel *)opaque;
+    return NULL; // apparently allowed?
+}
 
-    return channel->send_data.size;
+void worker_watch_remove(SpiceWatch *watch)
+{
 }
 
+SpiceCoreInterface worker_core = {
+    .watch_update_mask = worker_watch_update_mask,
+    .watch_add = worker_watch_add,
+    .watch_remove = worker_watch_remove,
+};
+
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
                                  RedsStream *stream, int migrate,
                                  event_listener_action_proc handler,
@@ -9417,47 +9069,31 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     RedChannel *channel;
     CommonChannel *common;
 
-    ASSERT(size >= sizeof(*channel));
-    common = spice_malloc0(size);
-    channel = &common->base;
-    ASSERT(common == (CommonChannel*)channel);
-    channel->stream = stream;
-    if (!common_channel_config_socket(channel)) {
+    channel = red_channel_create_parser(size, stream, &worker_core, migrate,
+                                        TRUE /* handle_acks */,
+                                        common_channel_config_socket,
+                                        spice_get_client_channel_parser(channel_id, NULL),
+                                        handle_parsed,
+                                        common_alloc_recv_buf,
+                                        common_release_recv_buf,
+                                        hold_item,
+                                        send_item,
+                                        release_item,
+                                        red_channel_default_peer_on_error,
+                                        red_channel_default_peer_on_error);
+    common = (CommonChannel *)channel;
+    if (!channel) {
         goto error;
     }
     common->id = worker->id;
-    channel->parser = spice_get_client_channel_parser(channel_id, NULL);
     common->listener.refs = 1;
     common->listener.action = handler;
     common->listener.free = free_common_channel_from_listener;
-    channel->disconnect = disconnect;
-    channel->send_item = send_item;
-    channel->hold_item = hold_item;
-    channel->release_item = release_item;
-    channel->handle_parsed = handle_parsed;
-    channel->stream = stream;
     common->worker = worker;
-    channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
-                                    // block flags)
+    // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
+    // make sense, does it?
     channel->ack_data.client_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
                                                       NARROW_CLIENT_ACK_WINDOW;
-    channel->ack_data.client_generation = ~0;
-    channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
-    channel->incoming.now = channel->incoming.buf;
-    channel->incoming.end = channel->incoming.buf + sizeof(channel->incoming.buf);
-    ring_init(&channel->pipe);
-    channel->send_data.marshaller = spice_marshaller_new();
-
-    channel->outgoing.opaque = channel;
-    channel->outgoing.pos = 0;
-    channel->outgoing.size = 0;
-    channel->outgoing.out_bytes_counter = 0;
-
-    channel->outgoing.get_msg_size = red_channel_peer_get_out_msg_size;
-    channel->outgoing.prepare = red_channel_peer_prepare_out_msg;
-    channel->outgoing.on_block = red_channel_peer_on_out_block;
-    channel->outgoing.on_error = (on_outgoing_error_proc)red_channel_default_peer_on_error;
-    channel->outgoing.on_msg_done = red_channel_peer_on_out_msg_done;
 
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = &common->listener;
@@ -9466,8 +9102,6 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
         goto error;
     }
 
-    channel->migrate = migrate;
-
     return channel;
 
 error:
commit ce3efca360086ab79d1b2828bec44197353a8d37
Author: Alon Levy <alevy at redhat.com>
Date:   Fri Feb 11 16:47:49 2011 +0200

    server/red_channe: make hold_item take a channel arg

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 551da27..ce532ca 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -508,7 +508,7 @@ static int inputs_channel_config_socket(RedChannel *channel)
     return TRUE;
 }
 
-static void inputs_channel_hold_pipe_item(PipeItem *item)
+static void inputs_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
 }
 
diff --git a/server/main_channel.c b/server/main_channel.c
index d24c7aa..64048da 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -776,7 +776,7 @@ static int main_channel_config_socket(RedChannel *channel)
     return TRUE;
 }
 
-static void main_channel_hold_pipe_item(PipeItem *item)
+static void main_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
 }
 
diff --git a/server/red_channel.c b/server/red_channel.c
index b077bcd..7bc1b68 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -465,7 +465,7 @@ void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem
     channel->send_data.header->type = msg_type;
     channel->send_data.item = item;
     if (item) {
-        channel->hold_item(item);
+        channel->hold_item(channel, item);
     }
 }
 
diff --git a/server/red_channel.h b/server/red_channel.h
index a23a618..fb5af99 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -107,7 +107,7 @@ typedef void (*channel_release_msg_recv_buf_proc)(RedChannel *channel,
 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)(PipeItem *item);
+typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
 typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
                                                PipeItem *item, int item_pushed);
 typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index da44cfe..2e6a336 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -3420,7 +3420,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
     }
 }
 
-static void tunnel_channel_hold_pipe_item(PipeItem *item)
+static void tunnel_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
 }
 
diff --git a/server/smartcard.c b/server/smartcard.c
index d890372..6afa7cd 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -465,7 +465,7 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
     return TRUE;
 }
 
-static void smartcard_channel_hold_pipe_item(PipeItem *item)
+static void smartcard_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
 }
 
commit 73858b93dccf595652f1b1e86fea1d0e7e9e153b
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 13:58:10 2010 +0200

    server/red_worker: introduce red_peer_handle_outgoing and OutgoingHandler
    
    From red_channel.

diff --git a/server/red_worker.c b/server/red_worker.c
index 683f8ad..3614eb8 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -354,6 +354,31 @@ typedef void (*channel_send_pipe_item_proc)(RedChannel *channel, PipeItem *item)
 typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, PipeItem *item, int item_pushed);
 typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type, void *message);
 
+#define MAX_SEND_VEC 100
+
+typedef int (*get_outgoing_msg_size_proc)(void *opaque);
+typedef void (*prepare_outgoing_proc)(void *opaque, struct iovec *vec, int *vec_size, int pos);
+typedef void (*on_outgoing_error_proc)(void *opaque);
+typedef void (*on_outgoing_block_proc)(void *opaque);
+typedef void (*on_outgoing_msg_done_proc)(void *opaque);
+
+typedef struct OutgoingHandler {
+    void *opaque;
+    struct iovec vec_buf[MAX_SEND_VEC];
+    int vec_size;
+    struct iovec *vec;
+    int pos;
+    int size;
+    get_outgoing_msg_size_proc get_msg_size;
+    prepare_outgoing_proc prepare;
+    on_outgoing_error_proc on_error;
+    on_outgoing_block_proc on_block;
+    on_outgoing_msg_done_proc on_msg_done;
+#ifdef RED_STATISTICS
+    uint64_t *out_bytes_counter;
+#endif
+} OutgoingHandler;
+
 struct RedChannel {
     spice_parse_channel_func_t parser;
     RedsStream *stream;
@@ -386,6 +411,8 @@ struct RedChannel {
         uint8_t *end;
     } incoming;
 
+    OutgoingHandler outgoing;
+
     channel_disconnect_proc disconnect;
     channel_hold_pipe_item_proc hold_item;
     channel_release_pipe_item_proc release_item;
@@ -393,12 +420,6 @@ struct RedChannel {
     channel_send_pipe_item_proc send_item;
 
     int during_send;
-
-#ifdef RED_STATISTICS
-    struct {
-        uint64_t *out_bytes_counter;
-    } outgoing;
-#endif
 };
 
 typedef struct ImageItem {
@@ -7277,8 +7298,6 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
     display_begin_send_message(display_channel);
 }
 
-#define MAX_SEND_VEC 100
-
 static void inline channel_release_res(RedChannel *channel)
 {
     if (!channel->send_data.item) {
@@ -7288,47 +7307,83 @@ static void inline channel_release_res(RedChannel *channel)
     channel->send_data.item = NULL;
 }
 
-static void red_channel_send(RedChannel *channel)
+static void red_channel_peer_prepare_out_msg(void *opaque, struct iovec *vec,
+                                             int *vec_size, int pos)
 {
-    for (;;) {
-        ssize_t n = channel->send_data.size - channel->send_data.pos;
-        struct iovec vec[MAX_SEND_VEC];
-        size_t vec_size;
-
-        if (!n) {
-            channel->send_data.blocked = FALSE;
-            if (channel->send_data.item) {
-                channel->release_item(channel, channel->send_data.item, FALSE);
-                channel->send_data.item = NULL;
-            }
-            break;
+    RedChannel *channel = (RedChannel *)opaque;
+
+    *vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
+                                            vec, MAX_SEND_VEC, pos);
+}
+
+static void red_channel_peer_on_out_block(void *opaque)
+{
+    RedChannel *channel = (RedChannel *)opaque;
+
+    channel->send_data.blocked = TRUE;
+}
+
+static void red_channel_peer_on_out_msg_done(void *opaque)
+{
+    RedChannel *channel = (RedChannel *)opaque;
+
+    channel->send_data.size = 0;
+    if (channel->send_data.item) {
+        channel->release_item(channel, channel->send_data.item, TRUE);
+        channel->send_data.item = NULL;
+    }
+    channel->send_data.blocked = FALSE;
+}
+
+static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
+{
+    int n;
+
+    ASSERT(stream);
+    if (handler->size == 0) {
+        handler->vec = handler->vec_buf;
+        handler->size = handler->get_msg_size(handler->opaque);
+        if (!handler->size) {  // nothing to be sent
+            return;
         }
-        vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
-                                               vec, MAX_SEND_VEC, channel->send_data.pos);
-        ASSERT(channel->stream);
-        n = reds_stream_writev(channel->stream, vec, vec_size);
+    }
+    for (;;) {
+        handler->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
+        n = reds_stream_writev(stream, handler->vec, handler->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
-                channel->send_data.blocked = TRUE;
+                handler->on_block(handler->opaque);
                 return;
             case EINTR:
                 break;
             case EPIPE:
-                channel->disconnect(channel);
+                handler->on_error(handler->opaque);
                 return;
             default:
                 red_printf("%s", strerror(errno));
-                channel->disconnect(channel);
+                handler->on_error(handler->opaque);
                 return;
             }
         } else {
-            channel->send_data.pos += n;
-            stat_inc_counter(channel->outgoing.out_bytes_counter, n);
+            handler->pos += n;
+            stat_inc_counter(handler->out_bytes_counter, n);
+            if (handler->pos == handler->size) { // finished writing data
+                handler->on_msg_done(handler->opaque);
+                handler->vec = handler->vec_buf;
+                handler->pos = 0;
+                handler->size = 0;
+                return;
+            }
         }
     }
 }
 
+static void red_channel_send(RedChannel *channel)
+{
+    red_peer_handle_outgoing(channel->stream, &channel->outgoing);
+}
+
 static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
                                          uint64_t* sync_data)
 {
@@ -8244,16 +8299,17 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
     red_channel_begin_send_message(channel);
 }
 
+static inline int red_channel_waiting_for_ack(RedChannel *channel)
+{
+    return (channel->ack_data.messages_window > channel->ack_data.client_window * 2);
+}
+
 static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
 {
     PipeItem *item;
     if (!channel || channel->send_data.blocked ||
-                                            !(item = (PipeItem *)ring_get_tail(&channel->pipe))) {
-        return NULL;
-    }
-
-    if (channel->ack_data.messages_window > channel->ack_data.client_window * 2) {
-        channel->send_data.blocked = TRUE;
+        red_channel_waiting_for_ack(channel) ||
+        !(item = (PipeItem *)ring_get_tail(&channel->pipe))) {
         return NULL;
     }
 
@@ -9336,6 +9392,18 @@ static void free_common_channel_from_listener(EventListener *ctx)
     free(common);
 }
 
+static void red_channel_default_peer_on_error(RedChannel *channel)
+{
+    channel->disconnect(channel);
+}
+
+static int red_channel_peer_get_out_msg_size(void *opaque)
+{
+    RedChannel *channel = (RedChannel *)opaque;
+
+    return channel->send_data.size;
+}
+
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
                                  RedsStream *stream, int migrate,
                                  event_listener_action_proc handler,
@@ -9380,6 +9448,17 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     ring_init(&channel->pipe);
     channel->send_data.marshaller = spice_marshaller_new();
 
+    channel->outgoing.opaque = channel;
+    channel->outgoing.pos = 0;
+    channel->outgoing.size = 0;
+    channel->outgoing.out_bytes_counter = 0;
+
+    channel->outgoing.get_msg_size = red_channel_peer_get_out_msg_size;
+    channel->outgoing.prepare = red_channel_peer_prepare_out_msg;
+    channel->outgoing.on_block = red_channel_peer_on_out_block;
+    channel->outgoing.on_error = (on_outgoing_error_proc)red_channel_default_peer_on_error;
+    channel->outgoing.on_msg_done = red_channel_peer_on_out_msg_done;
+
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = &common->listener;
     if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
commit 29a7bcd5964539bfdddc2489b33471038cf18477
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 11:12:03 2010 +0200

    server/red_worker: introduce common_channel_config_socket

diff --git a/server/red_worker.c b/server/red_worker.c
index 73e94bf..683f8ad 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9305,6 +9305,30 @@ static void red_channel_receive(RedChannel *channel)
     }
 }
 
+int common_channel_config_socket(RedChannel *channel)
+{
+    int flags;
+    int delay_val;
+    RedsStream *stream = channel->stream;
+
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
+        red_printf("accept failed, %s", strerror(errno));
+        return FALSE;
+    }
+
+    if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+        red_printf("accept failed, %s", strerror(errno));
+        return FALSE;
+    }
+
+    // TODO - this should be dynamic, not one time at channel creation
+    delay_val = IS_LOW_BANDWIDTH() ? 0 : 1;
+    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
+        red_printf("setsockopt failed, %s", strerror(errno));
+    }
+    return TRUE;
+}
+
 static void free_common_channel_from_listener(EventListener *ctx)
 {
     CommonChannel* common = SPICE_CONTAINEROF(ctx, CommonChannel, listener);
@@ -9324,28 +9348,15 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     struct epoll_event event;
     RedChannel *channel;
     CommonChannel *common;
-    int flags;
-    int delay_val;
-
-    if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
-        red_printf("accept failed, %s", strerror(errno));
-        goto error1;
-    }
-
-    if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
-        red_printf("accept failed, %s", strerror(errno));
-        goto error1;
-    }
-
-    delay_val = IS_LOW_BANDWIDTH() ? 0 : 1;
-    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
-        red_printf("setsockopt failed, %s", strerror(errno));
-    }
 
     ASSERT(size >= sizeof(*channel));
     common = spice_malloc0(size);
     channel = &common->base;
     ASSERT(common == (CommonChannel*)channel);
+    channel->stream = stream;
+    if (!common_channel_config_socket(channel)) {
+        goto error;
+    }
     common->id = worker->id;
     channel->parser = spice_get_client_channel_parser(channel_id, NULL);
     common->listener.refs = 1;
@@ -9373,16 +9384,15 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     event.data.ptr = &common->listener;
     if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
         red_printf("epoll_ctl failed, %s", strerror(errno));
-        goto error2;
+        goto error;
     }
 
     channel->migrate = migrate;
 
     return channel;
 
-error2:
+error:
     free(channel);
-error1:
     reds_stream_free(stream);
 
     return NULL;
commit beba2c72061e2a734aecd076bb7c2c1a3777589b
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 10:46:11 2010 +0200

    server/red_worker: line width fix

diff --git a/server/red_worker.c b/server/red_worker.c
index a8c0551..73e94bf 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8770,7 +8770,7 @@ static inline void flush_display_commands(RedWorker *worker)
         for (;;) {
             red_channel_push(&worker->display_channel->common.base);
             if (!worker->display_channel ||
-                                         worker->display_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
+                 worker->display_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
                 break;
             }
             RedChannel *channel = (RedChannel *)worker->display_channel;
commit 724348ce4976d035227c659b84caa6223d789404
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 10:44:20 2010 +0200

    server/red_worker: don't push to NULL channel (called from device input)

diff --git a/server/red_worker.c b/server/red_worker.c
index 57d67c1..a8c0551 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8352,13 +8352,16 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     default:
         red_error("invalid pipe item type");
     }
-    red_unref_channel((RedChannel *)display_channel);
+    red_unref_channel(&display_channel->common.base);
 }
 
 void red_channel_push(RedChannel *channel)
 {
     PipeItem *pipe_item;
 
+    if (!channel) {
+        return;
+    }
     if (!channel->during_send) {
         channel->during_send = TRUE;
     } else {
commit 705254b399e985272b60c639065aebe21a736eb7
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 10:43:36 2010 +0200

    server/red_worker: introduce red_channel_pipe_clear
    
    No more common_release_pipe_item

diff --git a/server/red_worker.c b/server/red_worker.c
index d70447b..57d67c1 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1371,69 +1371,17 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
     }
 }
 
-static void common_release_pipe_item(RedChannel *channel, PipeItem *item)
-{
-    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
-
-    switch (item->type) {
-    case PIPE_ITEM_TYPE_DRAW:
-        release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
-        break;
-    case PIPE_ITEM_TYPE_CURSOR:
-        red_release_cursor(common->worker, (CursorItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_UPGRADE:
-        release_upgrade_item(common->worker, (UpgradeItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_PIXMAP_RESET:
-    case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-    case PIPE_ITEM_TYPE_INVAL_ONE:
-    case PIPE_ITEM_TYPE_MIGRATE:
-    case PIPE_ITEM_TYPE_SET_ACK:
-    case PIPE_ITEM_TYPE_CURSOR_INIT:
-    case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_MIGRATE_DATA:
-    case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
-    case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
-        free(item);
-        break;
-    case PIPE_ITEM_TYPE_IMAGE:
-        release_image_item((ImageItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_STREAM_CREATE:
-        red_display_release_stream((DisplayChannel *)channel,
-                                   SPICE_CONTAINEROF(item, StreamAgent, create_item));
-        break;
-    case PIPE_ITEM_TYPE_STREAM_CLIP:
-        red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem*)item);
-        break;
-    case PIPE_ITEM_TYPE_STREAM_DESTROY:
-        red_display_release_stream((DisplayChannel *)channel,
-                                   SPICE_CONTAINEROF(item, StreamAgent, destroy_item));
-        break;
-    case PIPE_ITEM_TYPE_CREATE_SURFACE: {
-        SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem,
-                                                              pipe_item);
-        free(surface_create);
-        break;
-    }
-    case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
-        SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem,
-                                                                pipe_item);
-        free(surface_destroy);
-        break;
-    }
-    }
-}
-
-static void red_pipe_clear(RedChannel *channel)
+static void red_channel_pipe_clear(RedChannel *channel)
 {
     PipeItem *item;
 
     ASSERT(channel);
+    if (channel->send_data.item) {
+        channel->release_item(channel, channel->send_data.item, TRUE);
+    }
     while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
         ring_remove(&item->link);
-        common_release_pipe_item(channel, item);
+        channel->release_item(channel, item, FALSE);
     }
     channel->pipe_size = 0;
 }
@@ -8558,7 +8506,7 @@ static inline int red_channel_is_connected(RedChannel *channel)
 static void red_disconnect_channel(RedChannel *channel)
 {
     channel_release_res(channel);
-    red_pipe_clear(channel);
+    red_channel_pipe_clear(channel);
     reds_stream_free(channel->stream);
     channel->stream = NULL;
     channel->send_data.blocked = FALSE;
@@ -9492,6 +9440,8 @@ static void display_channel_release_item(RedChannel *channel, PipeItem *item, in
     case PIPE_ITEM_TYPE_IMAGE:
         release_image_item((ImageItem *)item);
         break;
+    case PIPE_ITEM_TYPE_SET_ACK:
+        break;
     default:
         PANIC("invalid item type");
     }
@@ -9622,7 +9572,16 @@ static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
 
     ASSERT(item);
-    red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
+    switch (item->type) {
+        case PIPE_ITEM_TYPE_CURSOR:
+            red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
+            break;
+        case PIPE_ITEM_TYPE_SET_ACK:
+            free(item);
+            break;
+        default:
+            PANIC("invalid item type");
+    }
 }
 
 static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrate)
commit a0a9718423409b45e320617b3a57f5d9454359f6
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 01:50:04 2010 +0200

    server/red_worker: add red_channel_push

diff --git a/server/red_worker.c b/server/red_worker.c
index 3af5924..d70447b 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -969,7 +969,7 @@ typedef struct BitmapData {
 
 static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
 static void red_current_flush(RedWorker *worker, int surface_id);
-static void display_channel_push(RedWorker *worker);
+static void red_channel_push(RedChannel *channel);
 #ifdef DRAW_ALL
 #define red_update_area(worker, rect, surface_id)
 #define red_draw_drawable(worker, item)
@@ -4560,7 +4560,7 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     /* not allowing lossy compression because probably, especially if it is a primary surface,
        it combines both "picture-like" areas with areas that are more "artificial"*/
     red_add_surface_area_image(worker, surface_id, &area, NULL, FALSE);
-    display_channel_push(worker);
+    red_channel_push(&worker->display_channel->common.base);
 }
 
 typedef struct {
@@ -8260,7 +8260,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
 
     red_channel_begin_send_message(channel);
 
-    red_release_cursor(cursor_channel->common.worker, cursor);
+    red_release_cursor(worker, cursor);
 }
 
 static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCreate *surface_create)
@@ -8407,13 +8407,24 @@ static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
     red_unref_channel((RedChannel *)display_channel);
 }
 
-static void display_channel_push(RedWorker *worker)
+void red_channel_push(RedChannel *channel)
 {
     PipeItem *pipe_item;
 
-    while ((pipe_item = red_channel_pipe_get((RedChannel *)worker->display_channel))) {
-        display_channel_send_item((RedChannel *)worker->display_channel, pipe_item);
+    if (!channel->during_send) {
+        channel->during_send = TRUE;
+    } else {
+        return;
     }
+
+    if (channel->send_data.blocked) {
+        red_channel_send(channel);
+    }
+
+    while ((pipe_item = red_channel_pipe_get(channel))) {
+        channel->send_item(channel, pipe_item);
+    }
+    channel->during_send = FALSE;
 }
 
 static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
@@ -8462,19 +8473,14 @@ static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
     red_unref_channel(channel);
 }
 
-static void cursor_channel_push(RedWorker *worker)
-{
-    PipeItem *pipe_item;
-
-    while ((pipe_item = red_channel_pipe_get((RedChannel *)worker->cursor_channel))) {
-        cursor_channel_send_item(&worker->cursor_channel->common.base, pipe_item);
-    }
-}
-
 static inline void red_push(RedWorker *worker)
 {
-    cursor_channel_push(worker);
-    display_channel_push(worker);
+    if (worker->cursor_channel) {
+        red_channel_push(&worker->cursor_channel->common.base);
+    }
+    if (worker->display_channel) {
+        red_channel_push(&worker->display_channel->common.base);
+    }
 }
 
 typedef struct ShowTreeData {
@@ -8802,7 +8808,7 @@ static inline void flush_display_commands(RedWorker *worker)
         }
 
         while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
-            display_channel_push(worker);
+            red_channel_push(&worker->display_channel->common.base);
         }
 
         if (ring_is_empty) {
@@ -8811,7 +8817,7 @@ static inline void flush_display_commands(RedWorker *worker)
         end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10;
         int sleep_count = 0;
         for (;;) {
-            display_channel_push(worker);
+            red_channel_push(&worker->display_channel->common.base);
             if (!worker->display_channel ||
                                          worker->display_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
                 break;
@@ -8844,7 +8850,7 @@ static inline void flush_cursor_commands(RedWorker *worker)
         }
 
         while (red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
-            cursor_channel_push(worker);
+            red_channel_push(&worker->cursor_channel->common.base);
         }
 
         if (ring_is_empty) {
@@ -8853,7 +8859,7 @@ static inline void flush_cursor_commands(RedWorker *worker)
         end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10;
         int sleep_count = 0;
         for (;;) {
-            cursor_channel_push(worker);
+            red_channel_push(&worker->cursor_channel->common.base);
             if (!worker->cursor_channel ||
                                         worker->cursor_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
                 break;
@@ -8889,7 +8895,7 @@ static void push_new_primary_surface(RedWorker *worker)
         if (!display_channel->common.base.migrate) {
             red_create_surface_item(worker, 0);
         }
-        display_channel_push(worker);
+        red_channel_push(&worker->display_channel->common.base);
     }
 }
 
@@ -9939,7 +9945,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
 
     if (worker->display_channel) {
         red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
-        display_channel_push(worker);
+        red_channel_push(&worker->display_channel->common.base);
     }
 
     if (worker->cursor_channel) {
@@ -10010,7 +10016,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_OOM:
         ASSERT(worker->running);
         while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
-            display_channel_push(worker);
+            red_channel_push(&worker->display_channel->common.base);
         }
         if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
             red_printf("oom current %u pipe %u", worker->current_size,
commit 111cf51103b1f3aa6820fac9f50da6c6be41f711
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 01:48:42 2010 +0200

    server/red_worker: add send_item

diff --git a/server/red_worker.c b/server/red_worker.c
index ef457dc..3af5924 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -350,6 +350,7 @@ typedef struct LocalCursor {
 typedef struct RedChannel RedChannel;
 typedef void (*channel_disconnect_proc)(RedChannel *channel);
 typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
+typedef void (*channel_send_pipe_item_proc)(RedChannel *channel, PipeItem *item);
 typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, PipeItem *item, int item_pushed);
 typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type, void *message);
 
@@ -389,6 +390,9 @@ struct RedChannel {
     channel_hold_pipe_item_proc hold_item;
     channel_release_pipe_item_proc release_item;
     channel_handle_parsed_proc handle_parsed;
+    channel_send_pipe_item_proc send_item;
+
+    int during_send;
 
 #ifdef RED_STATISTICS
     struct {
@@ -8412,9 +8416,9 @@ static void display_channel_push(RedWorker *worker)
     }
 }
 
-static void cursor_channel_send_item(CursorChannel *cursor_channel, PipeItem *pipe_item)
+static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
 {
-    RedChannel *channel = &cursor_channel->common.base;
+    CursorChannel *cursor_channel = SPICE_CONTAINEROF(channel, CursorChannel, common.base);
 
     red_ref_channel(channel);
     red_channel_reset_send_data(channel);
@@ -8463,7 +8467,7 @@ static void cursor_channel_push(RedWorker *worker)
     PipeItem *pipe_item;
 
     while ((pipe_item = red_channel_pipe_get((RedChannel *)worker->cursor_channel))) {
-        cursor_channel_send_item(worker->cursor_channel, pipe_item);
+        cursor_channel_send_item(&worker->cursor_channel->common.base, pipe_item);
     }
 }
 
@@ -9355,6 +9359,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
                                  RedsStream *stream, int migrate,
                                  event_listener_action_proc handler,
                                  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,
                                  channel_handle_parsed_proc handle_parsed)
@@ -9390,6 +9395,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     common->listener.action = handler;
     common->listener.free = free_common_channel_from_listener;
     channel->disconnect = disconnect;
+    channel->send_item = send_item;
     channel->hold_item = hold_item;
     channel->release_item = release_item;
     channel->handle_parsed = handle_parsed;
@@ -9496,6 +9502,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, in
                                                             SPICE_CHANNEL_DISPLAY, stream,
                                                             migrate, handle_channel_events,
                                                             red_disconnect_display,
+                                                            display_channel_send_item,
                                                             display_channel_hold_pipe_item,
                                                             display_channel_release_item,
                                                             display_channel_handle_message))) {
@@ -9622,6 +9629,7 @@ static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrat
                                                    SPICE_CHANNEL_CURSOR, stream, migrate,
                                                    handle_channel_events,
                                                    red_disconnect_cursor,
+                                                   cursor_channel_send_item,
                                                    cursor_channel_hold_pipe_item,
                                                    cursor_channel_release_item,
                                                    red_channel_handle_message))) {
commit f7a99f858efd484ec890eebd24c8f92002722e9b
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 01:44:11 2010 +0200

    server/red_worker: red_channel renames
    
    The renames are part of refactoring red_worker's RedChannel to reuse
    red_channel.h's RedChannel at the end.
    
    s/red_send_data/red_channel_send/
    s/red_pipe_get/red_channel_pipe_get/
    s/recive_data/incoming/
    s/red_receive/red_channel_receive/
    s/channel_handle_message/red_channel_handle_message/
    s/channel_is_connected/red_channel_is_connected/
    s/red_pipe_add_type/red_channel_pipe_add_type/

diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index 4d50fe4..75112c3 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -94,7 +94,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
 
     if (cache->generation != channel->CACH_GENERATION) {
         if (!channel->pending_pixmaps_sync) {
-            red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_SYNC);
+            red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_SYNC);
             channel->pending_pixmaps_sync = TRUE;
         }
         pthread_mutex_unlock(&cache->lock);
diff --git a/server/red_worker.c b/server/red_worker.c
index 21d2f6c..ef457dc 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -383,7 +383,7 @@ struct RedChannel {
         SpiceDataHeader *message;
         uint8_t *now;
         uint8_t *end;
-    } recive_data;
+    } incoming;
 
     channel_disconnect_proc disconnect;
     channel_hold_pipe_item_proc hold_item;
@@ -981,7 +981,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
 static inline void red_channel_begin_send_message(RedChannel *channel);
 static inline void display_begin_send_message(DisplayChannel *channel);
-static void red_receive(RedChannel *channel);
+static void red_channel_receive(RedChannel *channel);
 static void red_release_pixmap_cache(DisplayChannel *channel);
 static void red_release_glz(DisplayChannel *channel);
 static void red_freeze_glz(DisplayChannel *channel);
@@ -1234,7 +1234,7 @@ static void red_pipe_add_verb(RedChannel* channel, uint16_t verb)
     red_channel_pipe_add(channel, &item->base);
 }
 
-static void red_pipe_add_type(RedChannel* channel, int pipe_item_type)
+static void red_channel_pipe_add_type(RedChannel* channel, int pipe_item_type)
 {
     PipeItem *item = spice_new(PipeItem, 1);
     red_pipe_item_init(item, pipe_item_type);
@@ -7336,7 +7336,7 @@ static void inline channel_release_res(RedChannel *channel)
     channel->send_data.item = NULL;
 }
 
-static void red_send_data(RedChannel *channel)
+static void red_channel_send(RedChannel *channel)
 {
     for (;;) {
         ssize_t n = channel->send_data.size - channel->send_data.pos;
@@ -7408,7 +7408,7 @@ static inline void red_channel_begin_send_message(RedChannel *channel)
     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_send_data(channel);
+    red_channel_send(channel);
 }
 
 static inline void display_begin_send_message(DisplayChannel *channel)
@@ -8292,7 +8292,7 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
     red_channel_begin_send_message(channel);
 }
 
-static inline PipeItem *red_pipe_get(RedChannel *channel)
+static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
 {
     PipeItem *item;
     if (!channel || channel->send_data.blocked ||
@@ -8407,7 +8407,7 @@ static void display_channel_push(RedWorker *worker)
 {
     PipeItem *pipe_item;
 
-    while ((pipe_item = red_pipe_get((RedChannel *)worker->display_channel))) {
+    while ((pipe_item = red_channel_pipe_get((RedChannel *)worker->display_channel))) {
         display_channel_send_item((RedChannel *)worker->display_channel, pipe_item);
     }
 }
@@ -8462,7 +8462,7 @@ static void cursor_channel_push(RedWorker *worker)
 {
     PipeItem *pipe_item;
 
-    while ((pipe_item = red_pipe_get((RedChannel *)worker->cursor_channel))) {
+    while ((pipe_item = red_channel_pipe_get((RedChannel *)worker->cursor_channel))) {
         cursor_channel_send_item(worker->cursor_channel, pipe_item);
     }
 }
@@ -8540,7 +8540,7 @@ void red_show_tree(RedWorker *worker)
     }
 }
 
-static inline int channel_is_connected(RedChannel *channel)
+static inline int red_channel_is_connected(RedChannel *channel)
 {
     return !!channel->stream;
 }
@@ -8593,7 +8593,7 @@ static void red_migrate_display(RedWorker *worker)
 {
     if (worker->display_channel) {
         red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
-        red_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
+        red_channel_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
     }
 }
 
@@ -8814,8 +8814,8 @@ static inline void flush_display_commands(RedWorker *worker)
             }
             RedChannel *channel = (RedChannel *)worker->display_channel;
             red_ref_channel(channel);
-            red_receive(channel);
-            red_send_data(channel);
+            red_channel_receive(channel);
+            red_channel_send(channel);
             if (red_now() >= end_time) {
                 red_printf("update timeout");
                 red_disconnect_display(channel);
@@ -8856,8 +8856,8 @@ static inline void flush_cursor_commands(RedWorker *worker)
             }
             RedChannel *channel = (RedChannel *)worker->cursor_channel;
             red_ref_channel(channel);
-            red_receive(channel);
-            red_send_data(channel);
+            red_channel_receive(channel);
+            red_channel_send(channel);
             if (red_now() >= end_time) {
                 red_printf("flush cursor timeout");
                 red_disconnect_cursor(channel);
@@ -8881,7 +8881,7 @@ static void push_new_primary_surface(RedWorker *worker)
     DisplayChannel *display_channel;
 
     if ((display_channel = worker->display_channel)) {
-        red_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+        red_channel_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
         if (!display_channel->common.base.migrate) {
             red_create_surface_item(worker, 0);
         }
@@ -8894,7 +8894,7 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
     display_channel->expect_init = TRUE;
     uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
     for (;;) {
-        red_receive((RedChannel *)display_channel);
+        red_channel_receive((RedChannel *)display_channel);
         if (!display_channel->common.base.stream) {
             break;
         }
@@ -8923,7 +8923,7 @@ static void on_new_display_channel(RedWorker *worker)
     DisplayChannel *display_channel = worker->display_channel;
     ASSERT(display_channel);
 
-    red_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
 
     if (display_channel->common.base.migrate) {
         display_channel->expect_migrate_data = TRUE;
@@ -8938,14 +8938,14 @@ static void on_new_display_channel(RedWorker *worker)
         red_current_flush(worker, 0);
         push_new_primary_surface(worker);
         red_add_surface_image(worker, 0);
-        if (channel_is_connected(&display_channel->common.base)) {
+        if (red_channel_is_connected(&display_channel->common.base)) {
             red_pipe_add_verb(&display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
             red_disply_start_streams(display_channel);
         }
     }
 }
 
-static int channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
+static int red_channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
 {
     switch (type) {
     case SPICE_MSGC_ACK_SYNC:
@@ -9195,7 +9195,7 @@ static int display_channel_handle_migrate_mark(DisplayChannel *channel)
         return FALSE;
     }
     channel->expect_migrate_mark = FALSE;
-    red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
+    red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
     return TRUE;
 }
 
@@ -9233,7 +9233,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
 
     if (migrate_data->pixmap_cache_freezer) {
         channel->pixmap_cache->size = migrate_data->pixmap_cache_size;
-        red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_RESET);
+        red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_RESET);
     }
 
     if (display_channel_handle_migrate_glz_dictionary(channel, migrate_data)) {
@@ -9246,7 +9246,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
         PANIC("restoring global lz dictionary failed");
     }
 
-    red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+    red_channel_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
 
     channel->common.base.ack_data.messages_window = 0;
     return TRUE;
@@ -9267,18 +9267,18 @@ static int display_channel_handle_message(RedChannel *channel, uint32_t size, ui
     case SPICE_MSGC_MIGRATE_DATA:
         return display_channel_handle_migrate_data((DisplayChannel *)channel, size, message);
     default:
-        return channel_handle_message(channel, size, type, message);
+        return red_channel_handle_message(channel, size, type, message);
     }
 }
 
-static void red_receive(RedChannel *channel)
+static void red_channel_receive(RedChannel *channel)
 {
     for (;;) {
         ssize_t n;
-        n = channel->recive_data.end - channel->recive_data.now;
+        n = channel->incoming.end - channel->incoming.now;
         ASSERT(n);
         ASSERT(channel->stream);
-        n = reds_stream_read(channel->stream, channel->recive_data.now, n);
+        n = reds_stream_read(channel->stream, channel->incoming.now, n);
         if (n <= 0) {
             if (n == 0) {
                 channel->disconnect(channel);
@@ -9299,15 +9299,15 @@ static void red_receive(RedChannel *channel)
                 return;
             }
         } else {
-            channel->recive_data.now += n;
+            channel->incoming.now += n;
             for (;;) {
-                SpiceDataHeader *header = channel->recive_data.message;
+                SpiceDataHeader *header = channel->incoming.message;
                 uint8_t *data = (uint8_t *)(header+1);
                 size_t parsed_size;
                 uint8_t *parsed;
                 message_destructor_t parsed_free;
 
-                n = channel->recive_data.now - (uint8_t *)header;
+                n = channel->incoming.now - (uint8_t *)header;
                 if (n < sizeof(SpiceDataHeader) ||
                     n < sizeof(SpiceDataHeader) + header->size) {
                     break;
@@ -9327,18 +9327,18 @@ static void red_receive(RedChannel *channel)
                     return;
                 }
                 parsed_free(parsed);
-                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)header +
+                channel->incoming.message = (SpiceDataHeader *)((uint8_t *)header +
                                                                    sizeof(SpiceDataHeader) +
                                                                    header->size);
             }
 
-            if (channel->recive_data.now == (uint8_t *)channel->recive_data.message) {
-                channel->recive_data.now = channel->recive_data.buf;
-                channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
-            } else if (channel->recive_data.now == channel->recive_data.end) {
-                memcpy(channel->recive_data.buf, channel->recive_data.message, n);
-                channel->recive_data.now = channel->recive_data.buf + n;
-                channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
+            if (channel->incoming.now == (uint8_t *)channel->incoming.message) {
+                channel->incoming.now = channel->incoming.buf;
+                channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
+            } else if (channel->incoming.now == channel->incoming.end) {
+                memcpy(channel->incoming.buf, channel->incoming.message, n);
+                channel->incoming.now = channel->incoming.buf + n;
+                channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
             }
         }
     }
@@ -9400,9 +9400,9 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     channel->ack_data.client_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
                                                       NARROW_CLIENT_ACK_WINDOW;
     channel->ack_data.client_generation = ~0;
-    channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
-    channel->recive_data.now = channel->recive_data.buf;
-    channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
+    channel->incoming.message = (SpiceDataHeader *)channel->incoming.buf;
+    channel->incoming.now = channel->incoming.buf;
+    channel->incoming.end = channel->incoming.buf + sizeof(channel->incoming.buf);
     ring_init(&channel->pipe);
     channel->send_data.marshaller = spice_marshaller_new();
 
@@ -9431,11 +9431,11 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
     RedChannel *channel = &common->base;
 
     if ((events & EPOLLIN)) {
-        red_receive(channel);
+        red_channel_receive(channel);
     }
 
     if (channel->send_data.blocked) {
-        red_send_data(channel);
+        red_channel_send(channel);
     }
 }
 
@@ -9580,8 +9580,8 @@ static void red_disconnect_cursor(RedChannel *channel)
 static void red_migrate_cursor(RedWorker *worker)
 {
     if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
     }
 }
 
@@ -9592,9 +9592,9 @@ static void on_new_cursor_channel(RedWorker *worker)
     ASSERT(channel);
 
     channel->common.base.ack_data.messages_window = 0;
-    red_pipe_add_type(&channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
+    red_channel_pipe_add_type(&channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
     if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 }
 
@@ -9624,7 +9624,7 @@ static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrat
                                                    red_disconnect_cursor,
                                                    cursor_channel_hold_pipe_item,
                                                    cursor_channel_release_item,
-                                                   channel_handle_message))) {
+                                                   red_channel_handle_message))) {
         return;
     }
 #ifdef RED_STATISTICS
@@ -9707,8 +9707,8 @@ static void red_wait_outgoing_item(RedChannel *channel)
 
     do {
         usleep(DETACH_SLEEP_DURATION);
-        red_receive(channel);
-        red_send_data(channel);
+        red_channel_receive(channel);
+        red_channel_send(channel);
     } while ((blocked = channel->send_data.blocked) && red_now() < end_time);
 
     if (blocked) {
@@ -9736,16 +9736,16 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
 
     if (channel->send_data.blocked) {
-        red_receive(channel);
-        red_send_data(channel);
+        red_channel_receive(channel);
+        red_channel_send(channel);
     }
     // todo: different push for each channel
     red_push(common->worker);
 
     while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
         usleep(CHANNEL_PUSH_SLEEP_DURATION);
-        red_receive(channel);
-        red_send_data(channel);
+        red_channel_receive(channel);
+        red_channel_send(channel);
         red_push(common->worker);
     }
 
@@ -9883,7 +9883,7 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
     if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
             red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
@@ -9891,7 +9891,7 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     }
 
     if (worker->display_channel) {
-        red_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+        red_channel_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
         red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
     }
 
@@ -9935,7 +9935,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     }
 
     if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 
     message = RED_WORKER_MESSAGE_READY;
@@ -9959,7 +9959,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
     if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
             red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
@@ -10021,7 +10021,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
 
         red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
         if (worker->cursor_channel) {
-            red_pipe_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+            red_channel_pipe_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
             if (!cursor_red_channel->migrate) {
                 red_pipe_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
             }
commit b3ea0bec3d622fe36cb05944032b3faabd34434b
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Mar 2 08:36:45 2011 +0200

    server/red_tunnel_worker: use message_serial setter and getter
    
    fixes breakage in --enable-tunnel compilation.

diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index fddcf2c..da44cfe 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -2173,8 +2173,8 @@ static int tunnel_channel_handle_migrate_data(TunnelChannel *channel,
         goto error;
     }
 
-    ASSERT(channel->base.send_data.header.serial == 0);
-    channel->base.send_data.header.serial = migrate_data->message_serial;
+    ASSERT(red_channel_get_message_serial(&channel->base) == 0);
+    red_channel_set_message_serial(&channel->base, migrate_data->message_serial);
 
     net_slirp_state_restore(migrate_data->data + migrate_data->slirp_state);
 


More information about the Spice-commits mailing list