[Spice-commits] 56 commits - client/red_client.cpp configure.ac server/char_device.c server/char_device.h server/inputs_channel.c server/main_channel.c server/main_channel.h server/main_dispatcher.c server/main_dispatcher.h server/Makefile.am server/migration_protocol.h server/red_channel.c server/red_channel.h server/red_dispatcher.c server/red_dispatcher.h server/reds.c server/reds.h server/red_worker.c server/smartcard.c server/snd_worker.c server/spice.h server/spice-server.syms server/spicevmc.c spice-common

Yonit Halperin yhalperi at kemper.freedesktop.org
Sun Aug 26 23:16:02 PDT 2012


 client/red_client.cpp       |   18 -
 configure.ac                |    2 
 server/Makefile.am          |    1 
 server/char_device.c        |  199 +++++++++++-
 server/char_device.h        |   22 +
 server/inputs_channel.c     |  109 +++++-
 server/main_channel.c       |  458 ++++++++++++++++++++---------
 server/main_channel.h       |   31 -
 server/main_dispatcher.c    |   32 ++
 server/main_dispatcher.h    |    1 
 server/migration_protocol.h |  212 +++++++++++++
 server/red_channel.c        |  257 ++++++++++++++--
 server/red_channel.h        |   59 +++
 server/red_dispatcher.c     |   22 +
 server/red_dispatcher.h     |    2 
 server/red_worker.c         |  335 ++++++++++++---------
 server/reds.c               |  686 +++++++++++++++++++++++++++++++++++++++-----
 server/reds.h               |   18 -
 server/smartcard.c          |  287 +++++++++++++-----
 server/snd_worker.c         |  115 ++-----
 server/spice-server.syms    |    7 
 server/spice.h              |   13 
 server/spicevmc.c           |  108 +++++-
 spice-common                |    2 
 24 files changed, 2350 insertions(+), 646 deletions(-)

New commits:
commit c83a608fb464f1fd76024a6abd05ffb700172645
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Aug 14 15:39:01 2012 +0300

    enable seamless migration and set migration protocol version

diff --git a/server/main_channel.c b/server/main_channel.c
index 22660f5..0fd5ab6 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -1184,6 +1184,7 @@ MainChannel* main_channel_init(void)
                                         SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
     spice_assert(channel);
     red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
+    red_channel_set_cap(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
 
     client_cbs.migrate = main_channel_client_migrate;
     red_channel_register_client_cbs(channel, &client_cbs);
diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index c96b60a..fa17c7c 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -27,7 +27,7 @@
 
 /* increase the version when the version of any
  * of the migration data messages is increased */
-#define SPICE_MIGRATION_PROTOCOL_VERSION ~0
+#define SPICE_MIGRATION_PROTOCOL_VERSION 1
 
 typedef struct __attribute__ ((__packed__)) SpiceMigrateDataHeader {
     uint32_t magic;
commit c24276d941b1a55a35ab1b1a09b993bae502c659
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 13 14:20:47 2012 +0300

    inputs channel migration: don't send any msg after MSG_MIGRATE
    
    Pending motion acks, and keyboard modifiers messages will be sent
    by the destination after receiving the migration data.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index fcf3f82..acfbcff 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -64,13 +64,14 @@ struct SpiceTabletState {
 
 typedef struct InputsChannelClient {
     RedChannelClient base;
-    uint32_t motion_count;
+    uint16_t motion_count;
 } InputsChannelClient;
 
 typedef struct InputsChannel {
     RedChannel base;
     uint8_t recv_buf[RECEIVE_BUF_SIZE];
     VDAgentMouseState mouse_state;
+    int src_during_migrate;
 } InputsChannel;
 
 enum {
@@ -249,11 +250,12 @@ static void inputs_channel_send_migrate_data(RedChannelClient *rcc,
 {
     InputsChannelClient *icc = SPICE_CONTAINEROF(rcc, InputsChannelClient, base);
 
+    g_inputs_channel->src_during_migrate = FALSE;
     red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
 
     spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_MAGIC);
     spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_VERSION);
-    spice_marshaller_add_uint32(m, icc->motion_count);
+    spice_marshaller_add_uint16(m, icc->motion_count);
 }
 
 static void inputs_channel_release_pipe_item(RedChannelClient *rcc,
@@ -328,8 +330,10 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
     case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
         SpiceMsgcMouseMotion *mouse_motion = (SpiceMsgcMouseMotion *)buf;
 
-        if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
+        if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0 &&
+            !g_inputs_channel->src_during_migrate) {
             red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
+            icc->motion_count = 0;
         }
         if (mouse && reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
             SpiceMouseInterface *sif;
@@ -343,8 +347,10 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
     case SPICE_MSGC_INPUTS_MOUSE_POSITION: {
         SpiceMsgcMousePosition *pos = (SpiceMsgcMousePosition *)buf;
 
-        if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
+        if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0 &&
+            !g_inputs_channel->src_during_migrate) {
             red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
+            icc->motion_count = 0;
         }
         if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) {
             break;
@@ -518,9 +524,16 @@ static void inputs_connect(RedChannel *channel, RedClient *client,
     inputs_pipe_add_init(&icc->base);
 }
 
+static void inputs_migrate(RedChannelClient *rcc)
+{
+    g_inputs_channel->src_during_migrate = TRUE;
+    red_channel_client_default_migrate(rcc);
+}
+
 static void inputs_push_keyboard_modifiers(uint8_t modifiers)
 {
-    if (!g_inputs_channel || !red_channel_is_connected(&g_inputs_channel->base)) {
+    if (!g_inputs_channel || !red_channel_is_connected(&g_inputs_channel->base)||
+        g_inputs_channel->src_during_migrate) {
         return;
     }
     red_channel_pipes_new_add_push(&g_inputs_channel->base,
@@ -560,7 +573,13 @@ static int inputs_channel_handle_migrate_data(RedChannelClient *rcc,
         spice_error("bad header");
         return FALSE;
     }
+    key_modifiers_sender(NULL);
     icc->motion_count = mig_data->motion_count;
+
+    for (; icc->motion_count >= SPICE_INPUT_MOTION_ACK_BUNCH;
+           icc->motion_count -= SPICE_INPUT_MOTION_ACK_BUNCH) {
+        red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
+    }
     return TRUE;
 }
 
@@ -596,6 +615,7 @@ void inputs_init(void)
     }
 
     client_cbs.connect = inputs_connect;
+    client_cbs.migrate = inputs_migrate;
     red_channel_register_client_cbs(&g_inputs_channel->base, &client_cbs);
 
     reds_register_channel(&g_inputs_channel->base);
commit b18c6d4298677ad8521c7e9e144a3b5a18e29ca9
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Aug 8 18:10:15 2012 +0300

    inputs_channel: send and handle migration data

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 684dec6..fcf3f82 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -37,6 +37,7 @@
 #include "reds.h"
 #include "red_channel.h"
 #include "inputs_channel.h"
+#include "migration_protocol.h"
 
 // TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel
 // since it was defined once in reds.c which contained both.
@@ -76,6 +77,7 @@ enum {
     PIPE_ITEM_INPUTS_INIT = PIPE_ITEM_TYPE_CHANNEL_BASE,
     PIPE_ITEM_MOUSE_MOTION_ACK,
     PIPE_ITEM_KEY_MODIFIERS,
+    PIPE_ITEM_MIGRATE_DATA,
 };
 
 typedef struct InputsPipeItem {
@@ -241,6 +243,19 @@ static PipeItem *inputs_key_modifiers_item_new(
     return &item->base;
 }
 
+static void inputs_channel_send_migrate_data(RedChannelClient *rcc,
+                                             SpiceMarshaller *m,
+                                             PipeItem *item)
+{
+    InputsChannelClient *icc = SPICE_CONTAINEROF(rcc, InputsChannelClient, base);
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
+
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_MAGIC);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_VERSION);
+    spice_marshaller_add_uint32(m, icc->motion_count);
+}
+
 static void inputs_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *base, int item_pushed)
 {
@@ -275,6 +290,9 @@ static void inputs_channel_send_item(RedChannelClient *rcc, PipeItem *base)
         case PIPE_ITEM_MOUSE_MOTION_ACK:
             red_channel_client_init_send_data(rcc, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK, base);
             break;
+        case PIPE_ITEM_MIGRATE_DATA:
+            inputs_channel_send_migrate_data(rcc, m, base);
+            break;
         default:
             spice_warning("invalid pipe iten %d", base->type);
             break;
@@ -423,8 +441,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        spice_printerr("unexpected type %d", type);
-        return FALSE;
+        return red_channel_client_handle_message(rcc, size, type, message);
     }
     return TRUE;
 }
@@ -520,6 +537,33 @@ static void key_modifiers_sender(void *opaque)
     inputs_push_keyboard_modifiers(kbd_get_leds(keyboard));
 }
 
+static int inputs_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
+{
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MIGRATE_DATA);
+    return TRUE;
+}
+
+static int inputs_channel_handle_migrate_data(RedChannelClient *rcc,
+                                              uint32_t size,
+                                              void *message)
+{
+    InputsChannelClient *icc = SPICE_CONTAINEROF(rcc, InputsChannelClient, base);
+    SpiceMigrateDataHeader *header;
+    SpiceMigrateDataInputs *mig_data;
+
+    header = (SpiceMigrateDataHeader *)message;
+    mig_data = (SpiceMigrateDataInputs *)(header + 1);
+
+    if (!migration_protocol_validate_header(header,
+                                            SPICE_MIGRATE_DATA_INPUTS_MAGIC,
+                                            SPICE_MIGRATE_DATA_INPUTS_VERSION)) {
+        spice_error("bad header");
+        return FALSE;
+    }
+    icc->motion_count = mig_data->motion_count;
+    return TRUE;
+}
+
 void inputs_init(void)
 {
     ChannelCbs channel_cbs = { NULL, };
@@ -534,6 +578,8 @@ void inputs_init(void)
     channel_cbs.release_item = inputs_channel_release_pipe_item;
     channel_cbs.alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
     channel_cbs.release_recv_buf = inputs_channel_release_msg_rcv_buf;
+    channel_cbs.handle_migrate_data = inputs_channel_handle_migrate_data;
+    channel_cbs.handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
 
     g_inputs_channel = (InputsChannel *)red_channel_create_parser(
                                     sizeof(InputsChannel),
@@ -543,7 +589,7 @@ void inputs_init(void)
                                     spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL),
                                     inputs_channel_handle_parsed,
                                     &channel_cbs,
-                                    0);
+                                    SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
 
     if (!g_inputs_channel) {
         spice_error("failed to allocate Inputs Channel");
commit 0f4bc12090d0cc21f18a3379506b1d3b13bbf135
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Aug 8 18:09:22 2012 +0300

    migration_protocol: add inputs channel migration data
    
    Storing the motion count in uint16_t and not in uint32_t since
    the exact count is not important, just its division in
    SPICE_INPUT_MOTION_ACK_BUNCH (see the next 2 patches).

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index 285d86d..c96b60a 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -182,6 +182,18 @@ typedef struct __attribute__ ((__packed__)) MigrateDisplaySurfacesAtClientLossy
     MigrateDisplaySurfaceLossy surfaces[0];
 } MigrateDisplaySurfacesAtClientLossy;
 
+/* ****************
+ * inputs channel
+ * ***************/
+
+#define SPICE_MIGRATE_DATA_INPUTS_VERSION 1
+#define SPICE_MIGRATE_DATA_INPUTS_MAGIC (*(uint32_t *)"ICMD")
+
+
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataInputs {
+    uint16_t motion_count;
+} SpiceMigrateDataInputs;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit 115d095d469cd6e9697c4947e985379ec86fc768
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 22:25:57 2012 +0300

    main_channel: don't expect init msg in a seamless migration destination
    
    If the server is a destination of seamless migration, send msgs to the client,
    even though an init msg has not been sent to the client.

diff --git a/server/main_channel.c b/server/main_channel.c
index 7094181..22660f5 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -157,6 +157,7 @@ struct MainChannelClient {
     int mig_wait_prev_complete;
     int mig_wait_prev_try_seamless;
     int init_sent;
+    int seamless_mig_dst;
 };
 
 enum NetTestStage {
@@ -726,14 +727,17 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
     MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, base);
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
-    if (!mcc->init_sent && base->type != SPICE_MSG_MAIN_INIT) {
+    /* In semi-seamless migration (dest side), the connection is started from scratch, and
+     * we ignore any pipe item that arrives before the INIT msg is sent.
+     * For seamless we don't send INIT, and the connection continues from the same place
+     * it stopped on the src side. */
+    if (!mcc->init_sent && !mcc->seamless_mig_dst && base->type != PIPE_ITEM_TYPE_MAIN_INIT) {
         spice_printerr("Init msg for client %p was not sent yet "
-                   "(client is probably during migration). Ignoring msg type %d",
+                       "(client is probably during semi-seamless migration). Ignoring msg type %d",
                    rcc->client, base->type);
         main_channel_release_pipe_item(rcc, base, FALSE);
         return;
     }
-
     switch (base->type) {
         case PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST:
             main_channel_marshall_channels(rcc, m, base);
@@ -845,6 +849,7 @@ void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
                                                         uint32_t src_version)
 {
     if (reds_on_migrate_dst_set_seamless(mcc, src_version)) {
+        mcc->seamless_mig_dst = TRUE;
         red_channel_client_pipe_add_empty_msg(&mcc->base,
                                              SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
     } else {
commit e142bd9a611ce5980b29e8084b7d154013a16686
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 21:58:39 2012 +0300

    red_channel: set send_data.last_sent_serial in red_channel_client_set_message_serial
    
    red_channel_client_set_message_serial is called for setting
    the serial of the display channel messages after migration (on the
    destination side). The serial is retrieved from the migration data.

diff --git a/server/red_channel.c b/server/red_channel.c
index 97a26d1..c720b70 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -1269,6 +1269,7 @@ uint64_t red_channel_client_get_message_serial(RedChannelClient *rcc)
 
 void red_channel_client_set_message_serial(RedChannelClient *rcc, uint64_t serial)
 {
+    rcc->send_data.last_sent_serial = serial;
     rcc->send_data.serial = serial;
 }
 
commit 26027036c05cac96e2648ee146d63ba83af2d35e
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 13:35:19 2012 +0300

    red_channel: remove unused migrate flag from RedChannel
    
    The relevant flags reside in RedChannelClient and RedClient

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index d753bac..684dec6 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -539,7 +539,6 @@ void inputs_init(void)
                                     sizeof(InputsChannel),
                                     core,
                                     SPICE_CHANNEL_INPUTS, 0,
-                                    FALSE, // TODO: set migration?
                                     FALSE, /* handle_acks */
                                     spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL),
                                     inputs_channel_handle_parsed,
diff --git a/server/main_channel.c b/server/main_channel.c
index 1df19df..7094181 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -1172,7 +1172,7 @@ MainChannel* main_channel_init(void)
     // TODO: set the migration flag of the channel
     channel = red_channel_create_parser(sizeof(MainChannel), core,
                                         SPICE_CHANNEL_MAIN, 0,
-                                        FALSE, FALSE, /* handle_acks */
+                                        FALSE, /* handle_acks */
                                         spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL),
                                         main_channel_handle_parsed,
                                         &channel_cbs,
diff --git a/server/red_channel.c b/server/red_channel.c
index 18b69d3..97a26d1 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -768,7 +768,7 @@ void red_channel_client_default_migrate(RedChannelClient *rcc)
 RedChannel *red_channel_create(int size,
                                SpiceCoreInterface *core,
                                uint32_t type, uint32_t id,
-                               int migrate, int handle_acks,
+                               int handle_acks,
                                channel_handle_message_proc handle_message,
                                ChannelCbs *channel_cbs,
                                uint32_t migration_flags)
@@ -790,7 +790,6 @@ RedChannel *red_channel_create(int size,
     memcpy(&channel->channel_cbs, channel_cbs, sizeof(ChannelCbs));
 
     channel->core = core;
-    channel->migrate = migrate;
     ring_init(&channel->clients);
 
     // TODO: send incoming_cb as parameters instead of duplicating?
@@ -879,14 +878,14 @@ static int do_nothing_handle_message(RedChannelClient *rcc,
 RedChannel *red_channel_create_parser(int size,
                                SpiceCoreInterface *core,
                                uint32_t type, uint32_t id,
-                               int migrate, int handle_acks,
+                               int handle_acks,
                                spice_parse_channel_func_t parser,
                                channel_handle_parsed_proc handle_parsed,
                                ChannelCbs *channel_cbs,
                                uint32_t migration_flags)
 {
     RedChannel *channel = red_channel_create(size, core, type, id,
-                                             migrate, handle_acks,
+                                             handle_acks,
                                              do_nothing_handle_message,
                                              channel_cbs,
                                              migration_flags);
diff --git a/server/red_channel.h b/server/red_channel.h
index aab7d2d..0bd4cb1 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -284,7 +284,6 @@ struct RedChannel {
     RingItem link; // channels link for reds
 
     SpiceCoreInterface *core;
-    int migrate;
     int handle_acks;
 
     // RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there
@@ -320,7 +319,7 @@ struct RedChannel {
 RedChannel *red_channel_create(int size,
                                SpiceCoreInterface *core,
                                uint32_t type, uint32_t id,
-                               int migrate, int handle_acks,
+                               int handle_acks,
                                channel_handle_message_proc handle_message,
                                ChannelCbs *channel_cbs,
                                uint32_t migration_flags);
@@ -330,7 +329,7 @@ RedChannel *red_channel_create(int size,
 RedChannel *red_channel_create_parser(int size,
                                SpiceCoreInterface *core,
                                uint32_t type, uint32_t id,
-                               int migrate, int handle_acks,
+                               int handle_acks,
                                spice_parse_channel_func_t parser,
                                channel_handle_parsed_proc handle_parsed,
                                ChannelCbs *channel_cbs,
diff --git a/server/red_worker.c b/server/red_worker.c
index 3b64e0c..28fed60 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -10076,7 +10076,7 @@ CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
     return ccc;
 }
 
-static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type, int migrate,
+static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type,
                                  int migration_flags,
                                  channel_disconnect_proc on_disconnect,
                                  channel_send_pipe_item_proc send_item,
@@ -10104,7 +10104,6 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_t
 
     channel = red_channel_create_parser(size, &worker_core,
                                         channel_type, worker->id,
-                                        migrate,
                                         TRUE /* handle_acks */,
                                         spice_get_client_channel_parser(channel_type, NULL),
                                         handle_parsed,
@@ -10265,7 +10264,7 @@ static void display_channel_create(RedWorker *worker, int migrate)
     spice_info("create display channel");
     if (!(worker->display_channel = (DisplayChannel *)__new_channel(
             worker, sizeof(*display_channel),
-            SPICE_CHANNEL_DISPLAY, migrate,
+            SPICE_CHANNEL_DISPLAY,
             SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
             display_channel_client_on_disconnect,
             display_channel_send_item,
@@ -10470,7 +10469,7 @@ static void cursor_channel_create(RedWorker *worker, int migrate)
     spice_info("create cursor channel");
     worker->cursor_channel = (CursorChannel *)__new_channel(
         worker, sizeof(*worker->cursor_channel),
-        SPICE_CHANNEL_CURSOR, migrate,
+        SPICE_CHANNEL_CURSOR,
         0,
         cursor_channel_client_on_disconnect,
         cursor_channel_send_item,
diff --git a/server/smartcard.c b/server/smartcard.c
index 7c3a070..a7e81d5 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -842,7 +842,6 @@ static void smartcard_init(void)
 
     g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
                                              core, SPICE_CHANNEL_SMARTCARD, 0,
-                                             FALSE /* migration - TODO?*/,
                                              FALSE /* handle_acks */,
                                              smartcard_channel_handle_message,
                                              &channel_cbs,
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 7c47242..995823c 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -97,7 +97,6 @@ struct SndChannel {
     int blocked;
 
     uint32_t command;
-    int migrate;
     uint32_t ack_generation;
     uint32_t client_ack_generation;
     uint32_t out_messages;
@@ -923,7 +922,6 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
         goto error2;
     }
 
-    channel->migrate = migrate;
     channel->send_messages = send_messages;
     channel->handle_message = handle_message;
     channel->on_message_done = on_message_done;
@@ -1101,7 +1099,7 @@ static void on_new_playback_channel(SndWorker *worker)
     spice_assert(playback_channel);
 
     snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_MODE_MASK);
-    if (!playback_channel->base.migrate && playback_channel->base.active) {
+    if (playback_channel->base.active) {
         snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_CTRL_MASK);
     }
     snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_VOLUME_MASK);
@@ -1318,10 +1316,8 @@ static void on_new_record_channel(SndWorker *worker)
     spice_assert(record_channel);
 
     snd_set_command((SndChannel *)record_channel, SND_RECORD_VOLUME_MASK);
-    if (!record_channel->base.migrate) {
-        if (record_channel->base.active) {
-            snd_set_command((SndChannel *)record_channel, SND_RECORD_CTRL_MASK);
-        }
+    if (record_channel->base.active) {
+        snd_set_command((SndChannel *)record_channel, SND_RECORD_CTRL_MASK);
     }
 }
 
diff --git a/server/spicevmc.c b/server/spicevmc.c
index b6eaa08..058a182 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -417,7 +417,6 @@ SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
 
     state = (SpiceVmcState*)red_channel_create(sizeof(SpiceVmcState),
                                    core, channel_type, id[channel_type]++,
-                                   FALSE /* migration - TODO? */,
                                    FALSE /* handle_acks */,
                                    spicevmc_red_channel_client_handle_message,
                                    &channel_cbs,
commit 934fb14ccc731689369c55ead8125a590c0c4343
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 14:39:22 2012 +0300

    snd_worker: handling migration
    
    The playback and record channel send SPICE_MSG_MIGRATE to the client.
    Both playback and record channel does not have a state to restore:
    while in the legacy migration implementation the record channel
    used to restore the mode and start time, it looks unnecessary since
    the client receives from the src MSG_RECORD_STOP before the migration
    completion notification (when the vm is stopped). Afterwards, when the vm
    starts on the dest side, the client receives MSG_RECORD_START.

diff --git a/server/snd_worker.c b/server/snd_worker.c
index bcf1452..7c47242 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -169,16 +169,6 @@ struct SpiceRecordState {
     SpiceVolumeState volume;
 };
 
-#define RECORD_MIG_VERSION 1
-
-typedef struct __attribute__ ((__packed__)) RecordMigrateData {
-    uint32_t version;
-    uint64_t serial;
-    uint32_t start_time;
-    uint32_t mode;
-    uint32_t mode_time;
-} RecordMigrateData;
-
 typedef struct RecordChannel {
     SndChannel base;
     uint32_t samples[RECORD_SAMPLES_SIZE];
@@ -404,17 +394,6 @@ static int snd_record_handle_message(SndChannel *channel, size_t size, uint32_t
     }
     case SPICE_MSGC_DISCONNECTING:
         break;
-    case SPICE_MSGC_MIGRATE_DATA: {
-        RecordMigrateData* mig_data = (RecordMigrateData *)message;
-        if (mig_data->version != RECORD_MIG_VERSION) {
-            spice_printerr("invalid mig version");
-            break;
-        }
-        record_channel->mode = mig_data->mode;
-        record_channel->mode_time = mig_data->mode_time;
-        record_channel->start_time = mig_data->start_time;
-        break;
-    }
     default:
         spice_printerr("invalid message type %u", type);
         return FALSE;
@@ -551,18 +530,23 @@ static int snd_begin_send_message(SndChannel *channel)
     return snd_send_data(channel);
 }
 
-
-static int snd_playback_send_migrate(PlaybackChannel *channel)
+static int snd_channel_send_migrate(SndChannel *channel)
 {
     SpiceMsgMigrate migrate;
 
-    if (!snd_reset_send_data((SndChannel *)channel, SPICE_MSG_MIGRATE)) {
+    if (!snd_reset_send_data(channel, SPICE_MSG_MIGRATE)) {
         return FALSE;
     }
+    spice_debug(NULL);
     migrate.flags = 0;
-    spice_marshall_msg_migrate(channel->base.send_data.marshaller, &migrate);
+    spice_marshall_msg_migrate(channel->send_data.marshaller, &migrate);
+
+    return snd_begin_send_message(channel);
+}
 
-    return snd_begin_send_message((SndChannel *)channel);
+static int snd_playback_send_migrate(PlaybackChannel *channel)
+{
+    return snd_channel_send_migrate(&channel->base);
 }
 
 static int snd_send_volume(SndChannel *channel, SpiceVolumeState *st, int msg)
@@ -732,41 +716,11 @@ static int snd_record_send_mute(RecordChannel *record_channel)
 
 static int snd_record_send_migrate(RecordChannel *record_channel)
 {
-    SndChannel *channel = (SndChannel *)record_channel;
-    SpiceMsgMigrate migrate;
-    SpiceDataHeaderOpaque *header;
-    RecordMigrateData *data;
-
-    if (!snd_reset_send_data(channel, SPICE_MSG_MIGRATE)) {
-        return FALSE;
-    }
-
-    header = &channel->channel_client->send_data.header;
-    migrate.flags = SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    spice_marshall_msg_migrate(channel->send_data.marshaller, &migrate);
-
-    header->data = spice_marshaller_reserve_space(channel->send_data.marshaller, header->header_size);
-    header->set_msg_size(header, sizeof(RecordMigrateData));
-    header->set_msg_type(header, SPICE_MSG_MIGRATE_DATA);
-    ++channel->send_data.serial;
-    if (!channel->channel_client->is_mini_header) {
-        header->set_msg_serial(header, channel->send_data.serial);
-        header->set_msg_sub_list(header, 0);
-    }
-
-    data = (RecordMigrateData *)spice_marshaller_reserve_space(channel->send_data.marshaller,
-                                                               sizeof(RecordMigrateData));
-    data->version = RECORD_MIG_VERSION;
-    data->serial = channel->send_data.serial;
-    data->start_time = record_channel->start_time;
-    data->mode = record_channel->mode;
-    data->mode_time = record_channel->mode_time;
-
-    channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
-    header->set_msg_size(header, channel->send_data.size - header->header_size -
-                         header->header_size - sizeof(*data));
-
-    return snd_send_data(channel);
+    /* No need for migration data: if recording has started before migration,
+     * the client receives RECORD_STOP from the src before the migration completion
+     * notification (when the vm is stopped).
+     * Afterwards, when the vm starts on the dest, the client receives RECORD_START. */
+    return snd_channel_send_migrate(&record_channel->base);
 }
 
 static int snd_playback_send_write(PlaybackChannel *playback_channel)
@@ -1238,6 +1192,7 @@ static void snd_record_migrate_channel_client(RedChannelClient *rcc)
 {
     SndWorker *worker;
 
+    spice_debug(NULL);
     spice_assert(rcc->channel);
     spice_assert(rcc->channel->data);
     worker = (SndWorker *)rcc->channel->data;
@@ -1444,6 +1399,7 @@ static void snd_playback_migrate_channel_client(RedChannelClient *rcc)
     spice_assert(rcc->channel);
     spice_assert(rcc->channel->data);
     worker = (SndWorker *)rcc->channel->data;
+    spice_debug(NULL);
 
     if (worker->connection) {
         spice_assert(worker->connection->channel_client == rcc);
commit 8874f3b259034dd3983c400d7ba918839b25ede8
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 14:14:09 2012 +0300

    snd_channel: fix double release
    
    Due to the fix in the previous patch, snd_disconnect_channel can be
    called both when there is write/read error in the channel, or from
    red_client_destroy (which calls client_cbs.disconnect).
    Multiple calls to snd_disconnect_channel resulted in calling
    channel->cleanup(channel) more than once (double release).

diff --git a/server/snd_worker.c b/server/snd_worker.c
index 2746940..bcf1452 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -219,15 +219,20 @@ static void snd_disconnect_channel(SndChannel *channel)
     SndWorker *worker;
 
     if (!channel) {
+        spice_debug("not connected");
         return;
     }
-    channel->cleanup(channel);
-    worker = channel->worker;
-    red_channel_client_disconnect(worker->connection->channel_client);
-    core->watch_remove(channel->stream->watch);
-    channel->stream->watch = NULL;
-    reds_stream_free(channel->stream);
-    spice_marshaller_destroy(channel->send_data.marshaller);
+    spice_debug("%p", channel);
+    if (channel->stream) {
+        channel->cleanup(channel);
+        worker = channel->worker;
+        red_channel_client_disconnect(worker->connection->channel_client);
+        core->watch_remove(channel->stream->watch);
+        channel->stream->watch = NULL;
+        reds_stream_free(channel->stream);
+        channel->stream = NULL;
+        spice_marshaller_destroy(channel->send_data.marshaller);
+    }
     snd_channel_put(channel);
 }
 
@@ -992,13 +997,15 @@ static void snd_disconnect_channel_client(RedChannelClient *rcc)
 {
     SndWorker *worker;
 
+    spice_debug(NULL);
     spice_assert(rcc->channel);
     spice_assert(rcc->channel->data);
     worker = (SndWorker *)rcc->channel->data;
 
-    spice_assert(worker->connection->channel_client == rcc);
-    snd_disconnect_channel(worker->connection);
-    spice_assert(worker->connection == NULL);
+    if (worker->connection) {
+        spice_assert(worker->connection->channel_client == rcc);
+        snd_disconnect_channel(worker->connection);
+    }
 }
 
 static void snd_set_command(SndChannel *channel, uint32_t command)
commit 08d223beb39ee74422deaf04f7644ed795906720
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 14:04:38 2012 +0300

    red_channel (dummy): fix not adding dummy RedChannelClient to the client
    
    snd channel wasn't added to be part of the client's channels list.
    As a result, when the client was destroyed, or migrated, snd channel
    client wasn't destroy, or its migration callback wasn't called.
    
    However, due to adding dummy channels to the client, we need special
    handling for calls to disconnecting dummy channel clients.
    
    TODO: we need to refactor snd_worker to use red_channel

diff --git a/server/red_channel.c b/server/red_channel.c
index 803804e..18b69d3 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -998,9 +998,7 @@ static void red_channel_client_unref(RedChannelClient *rcc)
 void red_channel_client_destroy(RedChannelClient *rcc)
 {
     rcc->destroying = 1;
-    if (red_channel_client_is_connected(rcc)) {
-        red_channel_client_disconnect(rcc);
-    }
+    red_channel_client_disconnect(rcc);
     red_client_remove_channel(rcc);
     red_channel_client_unref(rcc);
 }
@@ -1370,7 +1368,11 @@ void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type)
 
 int red_channel_client_is_connected(RedChannelClient *rcc)
 {
-    return rcc->stream != NULL;
+    if (!rcc->dummy) {
+        return rcc->stream != NULL;
+    } else {
+        return rcc->dummy_connected;
+    }
 }
 
 int red_channel_is_connected(RedChannel *channel)
@@ -1429,10 +1431,23 @@ static void red_client_remove_channel(RedChannelClient *rcc)
     pthread_mutex_unlock(&rcc->client->lock);
 }
 
+static void red_channel_client_disconnect_dummy(RedChannelClient *rcc)
+{
+    spice_assert(rcc->dummy);
+    if (ring_item_is_linked(&rcc->channel_link)) {
+        red_channel_remove_client(rcc);
+    }
+    rcc->dummy_connected = FALSE;
+}
+
 void red_channel_client_disconnect(RedChannelClient *rcc)
 {
     spice_printerr("%p (channel %p type %d id %d)", rcc, rcc->channel,
                                                 rcc->channel->type, rcc->channel->id);
+    if (rcc->dummy) {
+        red_channel_client_disconnect_dummy(rcc);
+        return;
+    }
     if (!red_channel_client_is_connected(rcc)) {
         return;
     }
@@ -1490,8 +1505,12 @@ RedChannelClient *red_channel_client_create_dummy(int size,
 
     rcc->incoming.header.data = rcc->incoming.header_buf;
     rcc->incoming.serial = 1;
+    ring_init(&rcc->pipe);
 
+    rcc->dummy = TRUE;
+    rcc->dummy_connected = TRUE;
     red_channel_add_client(channel, rcc);
+    red_client_add_channel(client, rcc);
     pthread_mutex_unlock(&client->lock);
     return rcc;
 error:
@@ -1499,13 +1518,6 @@ error:
     return NULL;
 }
 
-void red_channel_client_destroy_dummy(RedChannelClient *rcc)
-{
-    red_channel_remove_client(rcc);
-    red_channel_client_destroy_remote_caps(rcc);
-    free(rcc);
-}
-
 void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb)
 {
     RingItem *link;
diff --git a/server/red_channel.h b/server/red_channel.h
index de72fff..aab7d2d 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -228,6 +228,8 @@ struct RedChannelClient {
     RedChannel *channel;
     RedClient  *client;
     RedsStream *stream;
+    int dummy;
+    int dummy_connected;
 
     uint32_t refs;
 
@@ -353,8 +355,6 @@ RedChannelClient *red_channel_client_create_dummy(int size,
                                                   RedClient  *client,
                                                   int num_common_caps, uint32_t *common_caps,
                                                   int num_caps, uint32_t *caps);
-void red_channel_client_destroy_dummy(RedChannelClient *rcc);
-
 
 int red_channel_is_connected(RedChannel *channel);
 int red_channel_client_is_connected(RedChannelClient *rcc);
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 3599c6f..2746940 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -223,7 +223,7 @@ static void snd_disconnect_channel(SndChannel *channel)
     }
     channel->cleanup(channel);
     worker = channel->worker;
-    red_channel_client_destroy_dummy(worker->connection->channel_client);
+    red_channel_client_disconnect(worker->connection->channel_client);
     core->watch_remove(channel->stream->watch);
     channel->stream->watch = NULL;
     reds_stream_free(channel->stream);
commit 8e7b22b7861d2859167767822f29749bfe3ecc16
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 13:17:46 2012 +0300

    display migration: restore destination state
    
    Restoring display channel from migration data.
    Not notifying client about changes that are artifacts of loading the vm.
    Remove legacy migration code.

diff --git a/server/red_worker.c b/server/red_worker.c
index 4bc5df0..3b64e0c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -483,24 +483,6 @@ struct PixmapCache {
 
 #define NUM_STREAMS 50
 
-#define DISPLAY_MIGRATE_DATA_MAGIC (*(uint32_t*)"DMDA")
-#define DISPLAY_MIGRATE_DATA_VERSION 2
-
-typedef struct __attribute__ ((__packed__)) DisplayChannelMigrateData {
-    //todo: add ack_generation + move common to generic migration data
-    uint32_t magic;
-    uint32_t version;
-    uint64_t message_serial;
-
-    uint8_t pixmap_cache_freezer;
-    uint8_t pixmap_cache_id;
-    int64_t pixmap_cache_size;
-    uint64_t pixmap_cache_clients[MAX_CACHE_CLIENTS];
-
-    uint8_t glz_dict_id;
-    GlzEncDictRestoreData glz_dict_restore_data;
-} DisplayChannelMigrateData;
-
 typedef struct WaitForChannels {
     SpiceMsgWaitForChannels header;
     SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
@@ -614,6 +596,11 @@ typedef struct CommonChannel {
     struct RedWorker *worker;
     uint8_t recv_buf[RECIVE_BUF_SIZE];
     uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
+    int during_target_migrate; /* TRUE when the client that is associated with the channel
+                                  is during migration. Turned off when the vm is started.
+                                  The flag is used to avoid sending messages that are artifacts
+                                  of the transition from stopped vm to loaded vm (e.g., recreation
+                                  of the primary surface) */
 } CommonChannel;
 
 typedef struct CommonChannelClient {
@@ -629,7 +616,6 @@ struct DisplayChannelClient {
     CommonChannelClient common;
 
     int expect_init;
-    int expect_migrate_data;
 
     PixmapCache *pixmap_cache;
     uint32_t pixmap_cache_generation;
@@ -669,10 +655,6 @@ struct DisplayChannelClient {
 struct DisplayChannel {
     CommonChannel common; // Must be the first thing
 
-    // only required for one client, can be the first (or choose it by speed
-    // and keep a pointer to it here?)
-    int expect_migrate_data;
-
     int enable_jpeg;
     int jpeg_quality;
     int enable_zlib_glz_wrap;
@@ -915,6 +897,7 @@ typedef struct RedWorker {
     RedSurface surfaces[NUM_SURFACES];
     uint32_t n_surfaces;
     SpiceImageSurfaces image_surfaces;
+    uint32_t primary_surface_generation;
 
     MonitorsConfig *monitors_config;
 
@@ -1670,7 +1653,8 @@ static inline void red_destroy_surface_item(RedWorker *worker,
     SurfaceDestroyItem *destroy;
     RedChannel *channel;
 
-    if (!dcc || !dcc->surface_client_created[surface_id]) {
+    if (!dcc || worker->display_channel->common.during_target_migrate ||
+        !dcc->surface_client_created[surface_id]) {
         return;
     }
     dcc->surface_client_created[surface_id] = FALSE;
@@ -4872,7 +4856,13 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
     int n = 0;
     uint64_t start = red_now();
 
-    if (!worker->running) {
+    /* we don't process the command ring if we are at the migration target and we
+     * are expecting migration data. The migration data includes the list
+     * of surfaces that are held by the client. We need to have it before
+     * processing commands in order not to render and send surfaces unnecessarily
+     */
+    if (!worker->running || (worker->display_channel &&
+        red_channel_waits_for_migrate_data(&worker->display_channel->common.base))) {
         *ring_is_empty = TRUE;
         return n;
     }
@@ -9249,7 +9239,8 @@ static inline void red_create_surface_item(DisplayChannelClient *dcc, int surfac
     uint32_t flags = is_primary_surface(worker, surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
 
     /* don't send redundant create surface commands to client */
-    if (!dcc || dcc->surface_client_created[surface_id]) {
+    if (!dcc || worker->display_channel->common.during_target_migrate ||
+        dcc->surface_client_created[surface_id]) {
         return;
     }
     surface = &worker->surfaces[surface_id];
@@ -9442,13 +9433,10 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
 
 static void push_new_primary_surface(DisplayChannelClient *dcc)
 {
-    RedWorker *worker = DCC_TO_WORKER(dcc);
     RedChannelClient *rcc = &dcc->common.base;
 
     red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-    if (!worker->display_channel->common.base.migrate) {
-        red_create_surface_item(dcc, 0);
-    }
+    red_create_surface_item(dcc, 0);
     red_channel_client_push(rcc);
 }
 
@@ -9488,10 +9476,9 @@ static void on_new_display_channel_client(DisplayChannelClient *dcc)
     RedWorker *worker = display_channel->common.worker;
     RedChannelClient *rcc = &dcc->common.base;
 
-    red_channel_push_set_ack(&display_channel->common.base);
+    red_channel_client_push_set_ack(&dcc->common.base);
 
-    if (display_channel->common.base.migrate) {
-        display_channel->expect_migrate_data = TRUE;
+    if (red_channel_client_waits_for_migrate_data(rcc)) {
         return;
     }
 
@@ -9499,7 +9486,6 @@ static void on_new_display_channel_client(DisplayChannelClient *dcc)
         return;
     }
     red_channel_client_ack_zero_messages_window(&dcc->common.base);
-    red_channel_client_push_set_ack(&dcc->common.base);
     if (worker->surfaces[0].context.canvas) {
         red_current_flush(worker, 0);
         push_new_primary_surface(dcc);
@@ -9726,7 +9712,7 @@ static int display_channel_init(DisplayChannelClient *dcc, SpiceMsgcDisplayInit
 }
 
 static int display_channel_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
-                                                         DisplayChannelMigrateData *migrate_info)
+                                                         SpiceMigrateDataDisplay *migrate_info)
 {
     spice_assert(!dcc->glz_dict);
     ring_init(&dcc->glz_drawables);
@@ -9734,7 +9720,7 @@ static int display_channel_handle_migrate_glz_dictionary(DisplayChannelClient *d
     pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
     return !!(dcc->glz_dict = red_restore_glz_dictionary(dcc,
                                                          migrate_info->glz_dict_id,
-                                                         &migrate_info->glz_dict_restore_data));
+                                                         &migrate_info->glz_dict_data));
 }
 
 static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
@@ -9749,46 +9735,99 @@ static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
 static uint64_t display_channel_handle_migrate_data_get_serial(
                 RedChannelClient *rcc, uint32_t size, void *message)
 {
-    DisplayChannelMigrateData *migrate_data = message;
+    SpiceMigrateDataDisplay *migrate_data;
 
-    if (size < sizeof(*migrate_data)) {
-        spice_warning("bad message size");
-        return 0;
+    migrate_data = (SpiceMigrateDataDisplay *)((uint8_t *)message + sizeof(SpiceMigrateDataHeader));
+
+    return migrate_data->message_serial;
+}
+
+static int display_channel_client_restore_surface(DisplayChannelClient *dcc, uint32_t surface_id)
+{
+    if (surface_id == 0) {
+        if (dcc->common.worker->primary_surface_generation <= 1) {
+            dcc->surface_client_created[surface_id] = TRUE;
+            return TRUE;
+        } else {
+            /* red_create_surface_item already updated the client */
+            return FALSE;
+        }
+    } else {
+        /* we don't process commands till we receive the migration data, thus,
+         * we should have not created any off-screen surface */
+        spice_assert(!dcc->surface_client_created[surface_id]);
+        dcc->surface_client_created[surface_id] = TRUE;
+        return TRUE;
     }
-    if (migrate_data->magic != DISPLAY_MIGRATE_DATA_MAGIC ||
-        migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
-        spice_warning("invalid content");
-        return 0;
+}
+
+static void display_channel_client_restore_surfaces_lossless(DisplayChannelClient *dcc,
+                                                             MigrateDisplaySurfacesAtClientLossless *mig_surfaces)
+{
+    uint32_t i;
+
+    spice_debug(NULL);
+    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
+        uint32_t surface_id = mig_surfaces->surfaces[i].id;
+
+        display_channel_client_restore_surface(dcc, surface_id);
     }
-    return migrate_data->message_serial;
 }
 
+static void display_channel_client_restore_surfaces_lossy(DisplayChannelClient *dcc,
+                                                          MigrateDisplaySurfacesAtClientLossy *mig_surfaces)
+{
+    uint32_t i;
+
+    spice_debug(NULL);
+    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
+        uint32_t surface_id = mig_surfaces->surfaces[i].id;
+
+        if (display_channel_client_restore_surface(dcc, surface_id)) {
+            SpiceMigrateDataRect *mig_lossy_rect;
+            SpiceRect lossy_rect;
+
+            spice_assert(dcc->surface_client_created[surface_id]);
+
+            mig_lossy_rect = &mig_surfaces->surfaces[i].lossy_rect;
+            lossy_rect.left = mig_lossy_rect->left;
+            lossy_rect.top = mig_lossy_rect->top;
+            lossy_rect.right = mig_lossy_rect->right;
+            lossy_rect.bottom = mig_lossy_rect->bottom;
+            region_init(&dcc->surface_client_lossy_region[surface_id]);
+            region_add(&dcc->surface_client_lossy_region[surface_id], &lossy_rect);
+        }
+    }
+}
 static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size,
-                                                    void *message)
+                                               void *message)
 {
-    DisplayChannelMigrateData *migrate_data;
+    SpiceMigrateDataHeader *header;
+    SpiceMigrateDataDisplay *migrate_data;
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-    RedChannel *channel = &display_channel->common.base;
+    uint8_t *surfaces;
     int i;
 
-    if (size < sizeof(*migrate_data)) {
-        spice_warning("bad message size");
-        return FALSE;
-    }
-    migrate_data = (DisplayChannelMigrateData *)message;
-    if (migrate_data->magic != DISPLAY_MIGRATE_DATA_MAGIC ||
-        migrate_data->version != DISPLAY_MIGRATE_DATA_VERSION) {
-        spice_warning("invalid content");
+    spice_debug(NULL);
+    if (size < sizeof(*migrate_data) + sizeof(SpiceMigrateDataHeader)) {
+        spice_error("bad message size");
         return FALSE;
     }
-    if (!display_channel->expect_migrate_data) {
-        spice_warning("unexpected");
+    header = (SpiceMigrateDataHeader *)message;
+    migrate_data = (SpiceMigrateDataDisplay *)(header + 1);
+    if (!migration_protocol_validate_header(header,
+                                            SPICE_MIGRATE_DATA_DISPLAY_MAGIC,
+                                            SPICE_MIGRATE_DATA_DISPLAY_VERSION)) {
+        spice_error("bad header");
         return FALSE;
     }
-    display_channel->expect_migrate_data = FALSE;
+    /* size is set to -1 in order to keep the cache freezed till the original
+     * channel client that freezed the cache on the src size receive the migrate
+     * data and unfreeze the cache by setting its size > 0 and by triggering
+     * pixmap_cache_reset */
     dcc->pixmap_cache = red_get_pixmap_cache(dcc->common.base.client,
-                                            migrate_data->pixmap_cache_id, -1);
+                                             migrate_data->pixmap_cache_id, -1);
     if (!dcc->pixmap_cache) {
         return FALSE;
     }
@@ -9800,10 +9839,11 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
     pthread_mutex_unlock(&dcc->pixmap_cache->lock);
 
     if (migrate_data->pixmap_cache_freezer) {
+        /* activating the cache. The cache will start to be active after
+         * pixmap_cache_reset is called, when handling PIPE_ITEM_TYPE_PIXMAP_RESET */
         dcc->pixmap_cache->size = migrate_data->pixmap_cache_size;
-        // TODO - should this be red_channel_client_pipe_add_type?
-        red_channel_pipes_add_type(channel,
-                                   PIPE_ITEM_TYPE_PIXMAP_RESET);
+        red_channel_client_pipe_add_type(rcc,
+                                         PIPE_ITEM_TYPE_PIXMAP_RESET);
     }
 
     if (display_channel_handle_migrate_glz_dictionary(dcc, migrate_data)) {
@@ -9815,8 +9855,27 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
     } else {
         spice_critical("restoring global lz dictionary failed");
     }
+    if (migrate_data->low_bandwidth_setting) {
+        red_channel_client_ack_set_client_window(rcc, WIDE_CLIENT_ACK_WINDOW);
+        if (dcc->common.worker->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
+            display_channel->enable_jpeg = TRUE;
+        }
+        if (dcc->common.worker->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
+            display_channel->enable_zlib_glz_wrap = TRUE;
+        }
+    }
+
+    surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr;
+    if (display_channel->enable_jpeg) {
+        display_channel_client_restore_surfaces_lossy(dcc,
+            (MigrateDisplaySurfacesAtClientLossy *)surfaces);
+    } else {
+            display_channel_client_restore_surfaces_lossless(dcc,
+            (MigrateDisplaySurfacesAtClientLossless*)surfaces);
+    }
 
     red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+    /* enable sending messages */
     red_channel_client_ack_zero_messages_window(rcc);
     return TRUE;
 }
@@ -9947,6 +10006,7 @@ static CommonChannelClient *common_channel_client_create(int size,
                                                          CommonChannel *common,
                                                          RedClient *client,
                                                          RedsStream *stream,
+                                                         int mig_target,
                                                          uint32_t *common_caps,
                                                          int num_common_caps,
                                                          uint32_t *caps,
@@ -9962,6 +10022,7 @@ static CommonChannelClient *common_channel_client_create(int size,
     CommonChannelClient *common_cc = (CommonChannelClient*)rcc;
     common_cc->worker = common->worker;
     common_cc->id = common->worker->id;
+    common->during_target_migrate = mig_target;
 
     // TODO: move wide/narrow ack setting to red_channel.
     red_channel_client_ack_set_client_window(rcc,
@@ -9973,12 +10034,14 @@ static CommonChannelClient *common_channel_client_create(int size,
 
 DisplayChannelClient *display_channel_client_create(CommonChannel *common,
                                                     RedClient *client, RedsStream *stream,
+                                                    int mig_target,
                                                     uint32_t *common_caps, int num_common_caps,
                                                     uint32_t *caps, int num_caps)
 {
     DisplayChannelClient *dcc =
         (DisplayChannelClient*)common_channel_client_create(
             sizeof(DisplayChannelClient), common, client, stream,
+            mig_target,
             common_caps, num_common_caps,
             caps, num_caps);
 
@@ -9992,12 +10055,14 @@ DisplayChannelClient *display_channel_client_create(CommonChannel *common,
 
 CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
                                                RedClient *client, RedsStream *stream,
+                                               int mig_target,
                                                uint32_t *common_caps, int num_common_caps,
                                                uint32_t *caps, int num_caps)
 {
     CursorChannelClient *ccc =
         (CursorChannelClient*)common_channel_client_create(
             sizeof(CursorChannelClient), common, client, stream,
+            mig_target,
             common_caps,
             num_common_caps,
             caps,
@@ -10252,6 +10317,7 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
     display_channel = worker->display_channel;
     spice_info("add display channel client");
     dcc = display_channel_client_create(&display_channel->common, client, stream,
+                                        migrate,
                                         common_caps, num_common_caps,
                                         caps, num_caps);
     if (!dcc) {
@@ -10333,7 +10399,7 @@ static void on_new_cursor_channel(RedWorker *worker, RedChannelClient *rcc)
     red_channel_client_push_set_ack(rcc);
     // TODO: why do we check for context.canvas? defer this to after display cc is connected
     // and test it's canvas? this is just a test to see if there is an active renderer?
-    if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
+    if (worker->surfaces[0].context.canvas && !channel->common.during_target_migrate) {
         red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 }
@@ -10431,6 +10497,7 @@ static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream
     channel = worker->cursor_channel;
     spice_info("add cursor channel client");
     ccc = cursor_channel_create_rcc(&channel->common, client, stream,
+                                    migrate,
                                     common_caps, num_common_caps,
                                     caps, num_caps);
     if (!ccc) {
@@ -10711,7 +10778,7 @@ static inline void red_cursor_reset(RedWorker *worker)
     if (cursor_is_connected(worker)) {
         red_channel_pipes_add_type(&worker->cursor_channel->common.base,
                                    PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        if (!worker->cursor_channel->common.base.migrate) {
+        if (!worker->cursor_channel->common.during_target_migrate) {
             red_pipes_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
         red_wait_outgoing_items(&worker->cursor_channel->common.base);
@@ -10725,6 +10792,7 @@ static inline void dev_destroy_surfaces(RedWorker *worker)
 {
     int i;
 
+    spice_debug(NULL);
     flush_all_qxl_commands(worker);
     //to handle better
     for (i = 0; i < NUM_SURFACES; ++i) {
@@ -10882,6 +10950,7 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
     uint8_t *line_0;
     int error;
 
+    spice_debug(NULL);
     spice_warn_if(surface_id != 0);
     spice_warn_if(surface.height == 0);
     spice_warn_if(((uint64_t)abs(surface.stride) * (uint64_t)surface.height) !=
@@ -10897,19 +10966,25 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
     }
 
+    if (!worker->display_channel->common.during_target_migrate) {
+        worker->primary_surface_generation++;
+    } else {
+         worker->primary_surface_generation = 1;
+    }
     red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
     set_monitors_config_to_primary(worker);
-    if (!worker->driver_has_monitors_config) {
-        red_worker_push_monitors_config(worker);
-    }
-    if (display_is_connected(worker)) {
+
+    if (display_is_connected(worker) && !worker->display_channel->common.during_target_migrate) {
+        if (!worker->driver_has_monitors_config) {
+            red_worker_push_monitors_config(worker);
+        }
         red_pipes_add_verb(&worker->display_channel->common.base,
                            SPICE_MSG_DISPLAY_MARK);
         red_channel_push(&worker->display_channel->common.base);
     }
 
-    if (cursor_is_connected(worker)) {
+    if (cursor_is_connected(worker) && !worker->cursor_channel->common.during_target_migrate) {
         red_channel_pipes_add_type(&worker->cursor_channel->common.base,
                                    PIPE_ITEM_TYPE_CURSOR_INIT);
     }
@@ -10927,6 +11002,7 @@ static void dev_destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
 {
     spice_warn_if(surface_id != 0);
 
+    spice_debug(NULL);
     if (!worker->surfaces[surface_id].context.canvas) {
         spice_warning("double destroy of primary surface");
         return;
@@ -11009,15 +11085,13 @@ void handle_dev_stop(void *opaque, void *payload)
 void handle_dev_start(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
-    RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
-    RedChannel *display_red_channel = &worker->display_channel->common.base;
 
     spice_assert(!worker->running);
     if (worker->cursor_channel) {
-        cursor_red_channel->migrate = FALSE;
+        worker->cursor_channel->common.during_target_migrate = FALSE;
     }
     if (worker->display_channel) {
-        display_red_channel->migrate = FALSE;
+        worker->display_channel->common.during_target_migrate = FALSE;
     }
     worker->running = TRUE;
 }
commit 29776c92160d91919043339a02099c3bdd62b6ec
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 11:50:13 2012 +0300

    display migration: marshall migration data

diff --git a/server/red_worker.c b/server/red_worker.c
index d6e3f69..4bc5df0 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -79,6 +79,7 @@
 #include "red_dispatcher.h"
 #include "dispatcher.h"
 #include "main_channel.h"
+#include "migration_protocol.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -8409,20 +8410,56 @@ static inline void red_marshall_inval(RedChannelClient *rcc,
     spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
+static void display_channel_marshall_migrate_data_surfaces(DisplayChannelClient *dcc,
+                                                           SpiceMarshaller *m,
+                                                           int lossy)
+{
+    SpiceMarshaller *m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
+    uint32_t *num_surfaces_created;
+    uint32_t i;
+
+    num_surfaces_created = (uint32_t *)spice_marshaller_reserve_space(m2, sizeof(uint32_t));
+    *num_surfaces_created = 0;
+    for (i = 0; i < NUM_SURFACES; i++) {
+        SpiceRect lossy_rect;
+        SpiceMigrateDataRect lossy_rect_marshall;
+        if (!dcc->surface_client_created[i]) {
+            continue;
+        }
+        spice_marshaller_add_uint32(m2, i);
+        (*num_surfaces_created)++;
+
+        if (!lossy) {
+            continue;
+        }
+        region_extents(&dcc->surface_client_lossy_region[i], &lossy_rect);
+        lossy_rect_marshall.left = lossy_rect.left;
+        lossy_rect_marshall.top = lossy_rect.top;
+        lossy_rect_marshall.right = lossy_rect.right;
+        lossy_rect_marshall.bottom = lossy_rect.bottom;
+        spice_marshaller_add_ref(m2, (uint8_t *)&lossy_rect_marshall, sizeof(lossy_rect_marshall));
+    }
+}
+
 static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
                                                   SpiceMarshaller *base_marshaller)
 {
+    DisplayChannel *display_channel;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-    DisplayChannelMigrateData display_data;
+    SpiceMigrateDataDisplay display_data;
+
+    display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
+    spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC);
+    spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_VERSION);
 
     spice_assert(dcc->pixmap_cache);
-    display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
-    spice_assert(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
-    display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
+    spice_assert(MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == 4 &&
+                 MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == MAX_CACHE_CLIENTS);
 
     display_data.message_serial = red_channel_client_get_message_serial(rcc);
+    display_data.low_bandwidth_setting = display_channel_client_is_low_bandwidth(dcc);
 
     display_data.pixmap_cache_freezer = pixmap_cache_freeze(dcc->pixmap_cache);
     display_data.pixmap_cache_id = dcc->pixmap_cache->id;
@@ -8434,11 +8471,14 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
     red_freeze_glz(dcc);
     display_data.glz_dict_id = dcc->glz_dict->id;
     glz_enc_dictionary_get_restore_data(dcc->glz_dict->dict,
-                                        &display_data.glz_dict_restore_data,
+                                        &display_data.glz_dict_data,
                                         &dcc->glz_data.usr);
 
+    /* all data besided the surfaces ref */
     spice_marshaller_add_ref(base_marshaller,
-                             (uint8_t *)&display_data, sizeof(display_data));
+                             (uint8_t *)&display_data, sizeof(display_data) - sizeof(uint32_t));
+    display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller,
+                                                   display_channel->enable_jpeg);
 }
 
 static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc,
commit 558c4cbb4c4e2588e84f6f1ce3433f8f3512644f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 11:32:49 2012 +0300

    display & cursor migration: send SPICE_MSG_MIGRATE

diff --git a/server/red_worker.c b/server/red_worker.c
index 69cd9af..d6e3f69 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -253,8 +253,6 @@ enum {
     PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_CHANNEL_BASE,
     PIPE_ITEM_TYPE_INVAL_ONE,
     PIPE_ITEM_TYPE_CURSOR,
-    PIPE_ITEM_TYPE_DISPLAY_MIGRATE, /* tmp. It will be substituted with
-                                       red_channel/PIPE_ITEM_TYPE_MIGRATE */
     PIPE_ITEM_TYPE_CURSOR_INIT,
     PIPE_ITEM_TYPE_IMAGE,
     PIPE_ITEM_TYPE_STREAM_CREATE,
@@ -630,7 +628,6 @@ struct DisplayChannelClient {
     CommonChannelClient common;
 
     int expect_init;
-    int expect_migrate_mark;
     int expect_migrate_data;
 
     PixmapCache *pixmap_cache;
@@ -673,7 +670,6 @@ struct DisplayChannel {
 
     // only required for one client, can be the first (or choose it by speed
     // and keep a pointer to it here?)
-    int expect_migrate_mark;
     int expect_migrate_data;
 
     int enable_jpeg;
@@ -8413,18 +8409,6 @@ static inline void red_marshall_inval(RedChannelClient *rcc,
     spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
 }
 
-static void display_channel_marshall_migrate(RedChannelClient *rcc,
-    SpiceMarshaller *base_marshaller)
-{
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    SpiceMsgMigrate migrate;
-
-    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
-    migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
-    spice_marshall_msg_migrate(base_marshaller, &migrate);
-    display_channel->expect_migrate_mark = TRUE;
-}
-
 static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
                                                   SpiceMarshaller *base_marshaller)
 {
@@ -8755,17 +8739,6 @@ static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *bas
     add_buf_from_info(base_marshaller, &info);
 }
 
-static void cursor_channel_marshall_migrate(RedChannelClient *rcc,
-                                            SpiceMarshaller *base_marshaller)
-{
-    SpiceMsgMigrate migrate;
-
-    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
-    migrate.flags = 0;
-
-    spice_marshall_msg_migrate(base_marshaller, &migrate);
-}
-
 static void red_marshall_cursor(RedChannelClient *rcc,
                    SpiceMarshaller *m, CursorPipeItem *cursor_pipe_item)
 {
@@ -8910,10 +8883,6 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
     case PIPE_ITEM_TYPE_VERB:
         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         break;
-    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
-        spice_info("PIPE_ITEM_TYPE_MIGRATE");
-        display_channel_marshall_migrate(rcc, m);
-        break;
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
         display_channel_marshall_migrate_data(rcc, m);
         break;
@@ -8975,10 +8944,6 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
     case PIPE_ITEM_TYPE_VERB:
         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         break;
-    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
-        spice_info("PIPE_ITEM_TYPE_MIGRATE");
-        cursor_channel_marshall_migrate(rcc, m);
-        break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
         red_reset_cursor_cache(rcc);
         red_marshall_cursor_init(rcc, m, pipe_item);
@@ -9120,14 +9085,9 @@ void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
 
 static void red_migrate_display(RedWorker *worker, RedChannelClient *rcc)
 {
-    // TODO: replace all worker->display_channel tests with
-    // is_connected
     if (red_channel_client_is_connected(rcc)) {
-        red_pipe_add_verb(rcc, PIPE_ITEM_TYPE_DISPLAY_MIGRATE);
-//        red_pipes_add_verb(&worker->display_channel->common.base,
-//                           SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
-//        red_channel_pipes_add_type(&worker->display_channel->common.base,
-//                                   PIPE_ITEM_TYPE_MIGRATE);
+        red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+        red_channel_client_default_migrate(rcc);
     }
 }
 
@@ -9742,11 +9702,6 @@ static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedChannel *channel = &display_channel->common.base;
 
-    if (!display_channel->expect_migrate_mark) {
-        spice_warning("unexpected");
-        return FALSE;
-    }
-    display_channel->expect_migrate_mark = FALSE;
     red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
     return TRUE;
 }
@@ -10170,7 +10125,6 @@ static void display_channel_client_release_item_before_push(DisplayChannelClient
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
     case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
@@ -10323,12 +10277,10 @@ static void red_disconnect_cursor(RedChannel *channel)
 
 static void red_migrate_cursor(RedWorker *worker, RedChannelClient *rcc)
 {
-//    if (cursor_is_connected(worker)) {
     if (red_channel_client_is_connected(rcc)) {
         red_channel_client_pipe_add_type(rcc,
                                          PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        red_channel_client_pipe_add_type(rcc,
-                                         PIPE_ITEM_TYPE_DISPLAY_MIGRATE);
+        red_channel_client_default_migrate(rcc);
     }
 }
 
@@ -10367,7 +10319,6 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient *
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
     case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
     case PIPE_ITEM_TYPE_CURSOR_INIT:
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
         free(item);
commit 6b741688711697c9ebc698875bdcd884cf0ded46
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 6 10:33:44 2012 +0300

    migration_protocol: add display channel migration data

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index d2a5575..285d86d 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -19,6 +19,7 @@
 #define _H_MIGRATION_PROTOCOL
 
 #include <spice/vd_agent.h>
+#include "glz_encoder_dictionary.h"
 
 /* ************************************************
  * src-server to dst-server migration data messages
@@ -109,6 +110,78 @@ typedef struct __attribute__ ((__packed__)) SpiceMigrateDataMain {
     } client2agent;
 } SpiceMigrateDataMain;
 
+/* ****************
+ * display channel
+ * ***************/
+
+#define SPICE_MIGRATE_DATA_DISPLAY_VERSION 1
+#define SPICE_MIGRATE_DATA_DISPLAY_MAGIC (*(uint32_t *)"DCMD")
+
+/*
+ * TODO: store the cache and dictionary data only in one channel (the
+ *       freezer).
+ * TODO: optimizations: don't send surfaces information if it will be faster
+ *       to resend the surfaces on-demand.
+ * */
+#define MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS 4
+
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataDisplay {
+    uint64_t message_serial;
+    uint8_t low_bandwidth_setting;
+
+    /*
+     * Synchronizing the shared pixmap cache.
+     * For now, the cache is not migrated, and instead, we reset it and send
+     * SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS to the client.
+     * In order to keep the client and server caches consistent:
+     * The channel which freezed the cache on the src side, unfreezes it
+     * on the dest side, and increases its generation (see 'reset' in red_client_shared_cach.h).
+     * In order to enforce that images that are added to the cache by other channels
+     * will reach the client only after SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS,
+     * we send SPICE_MSG_WAIT_FOR_CHANNELS
+     * (see the generation mismatch handling in 'add' in red_client_shared_cach.h).
+     */
+    uint8_t pixmap_cache_id;
+    int64_t pixmap_cache_size;
+    uint8_t pixmap_cache_freezer;
+    uint64_t pixmap_cache_clients[MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS];
+
+    uint8_t glz_dict_id;
+    GlzEncDictRestoreData glz_dict_data;
+
+    uint32_t surfaces_at_client_ptr; /* reference to MigrateDisplaySurfacesAtClientLossless/Lossy.
+                                        Lossy: when jpeg-wan-compression(qemu cmd line)=always
+                                        or when jpeg-wan-compression=auto,
+                                        and low_bandwidth_setting=TRUE */
+
+} SpiceMigrateDataDisplay;
+
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataRect {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} SpiceMigrateDataRect;
+
+typedef struct __attribute__ ((__packed__)) MigrateDisplaySurfaceLossless {
+    uint32_t id;
+} MigrateDisplaySurfaceLossless;
+
+typedef struct __attribute__ ((__packed__)) MigrateDisplaySurfaceLossy {
+    uint32_t id;
+    SpiceMigrateDataRect lossy_rect;
+} MigrateDisplaySurfaceLossy;
+
+typedef struct __attribute__ ((__packed__)) MigrateDisplaySurfacesAtClientLossless {
+    uint32_t num_surfaces;
+    MigrateDisplaySurfaceLossless surfaces[0];
+} MigrateDisplaySurfacesAtClientLossless;
+
+typedef struct __attribute__ ((__packed__)) MigrateDisplaySurfacesAtClientLossy {
+    uint32_t num_surfaces;
+    MigrateDisplaySurfaceLossy surfaces[0];
+} MigrateDisplaySurfacesAtClientLossy;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit 35227cd11fe27e882f81009bdc80fdf4d9c4f9b6
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 22:23:38 2012 +0300

    inputs channel: use the default red_channel behaviour for client_cbs.migrate
    
    The default callback sends SPICE_MSG_MIGRATE to the client.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 9f96624..d753bac 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -447,12 +447,6 @@ static void inputs_channel_on_disconnect(RedChannelClient *rcc)
     inputs_relase_keys();
 }
 
-static void inputs_migrate(RedChannelClient *rcc)
-{
-    spice_assert(g_inputs_channel == (InputsChannel *)rcc->channel);
-    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_MIGRATE);
-}
-
 static void inputs_pipe_add_init(RedChannelClient *rcc)
 {
     InputsInitPipeItem *item = spice_malloc(sizeof(InputsInitPipeItem));
@@ -557,7 +551,6 @@ void inputs_init(void)
     }
 
     client_cbs.connect = inputs_connect;
-    client_cbs.migrate = inputs_migrate;
     red_channel_register_client_cbs(&g_inputs_channel->base, &client_cbs);
 
     reds_register_channel(&g_inputs_channel->base);
commit 5aec370a7a7c588572f7edace41a3ce2c482c555
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 22:20:08 2012 +0300

    inputs channel: fix using spice messages enums as pipe items type
    
    A channel pipe item type must start from PIPE_ITEM_TYPE_CHANNEL_BASE.
    SPICE_MSG_MIGRATE value eq. PIPE_ITEM_TYPE_SET_ACK. Setting a pipe item
    type to SPICE_MSG_MIGRATE, leads to red_channel handling PIPE_ITEM_TYPE_SET_ACK.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 269e2dc..9f96624 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -73,10 +73,9 @@ typedef struct InputsChannel {
 } InputsChannel;
 
 enum {
-    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,
+    PIPE_ITEM_INPUTS_INIT = PIPE_ITEM_TYPE_CHANNEL_BASE,
+    PIPE_ITEM_MOUSE_MOTION_ACK,
+    PIPE_ITEM_KEY_MODIFIERS,
 };
 
 typedef struct InputsPipeItem {
@@ -252,33 +251,32 @@ static void inputs_channel_send_item(RedChannelClient *rcc, PipeItem *base)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
-    red_channel_client_init_send_data(rcc, base->type, base);
     switch (base->type) {
         case PIPE_ITEM_KEY_MODIFIERS:
         {
             SpiceMsgInputsKeyModifiers key_modifiers;
 
+            red_channel_client_init_send_data(rcc, SPICE_MSG_INPUTS_KEY_MODIFIERS, base);
             key_modifiers.modifiers =
                 SPICE_CONTAINEROF(base, KeyModifiersPipeItem, base)->modifiers;
             spice_marshall_msg_inputs_key_modifiers(m, &key_modifiers);
+            break;
         }
         case PIPE_ITEM_INPUTS_INIT:
         {
             SpiceMsgInputsInit inputs_init;
 
+            red_channel_client_init_send_data(rcc, SPICE_MSG_INPUTS_INIT, base);
             inputs_init.keyboard_modifiers =
                 SPICE_CONTAINEROF(base, InputsInitPipeItem, base)->modifiers;
             spice_marshall_msg_inputs_init(m, &inputs_init);
-        }
-        case PIPE_ITEM_MIGRATE:
-        {
-            SpiceMsgMigrate migrate;
-
-            migrate.flags = 0;
-            spice_marshall_msg_migrate(m, &migrate);
             break;
         }
+        case PIPE_ITEM_MOUSE_MOTION_ACK:
+            red_channel_client_init_send_data(rcc, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK, base);
+            break;
         default:
+            spice_warning("invalid pipe iten %d", base->type);
             break;
     }
     red_channel_client_begin_send_message(rcc);
@@ -452,7 +450,7 @@ static void inputs_channel_on_disconnect(RedChannelClient *rcc)
 static void inputs_migrate(RedChannelClient *rcc)
 {
     spice_assert(g_inputs_channel == (InputsChannel *)rcc->channel);
-    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MIGRATE);
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_MIGRATE);
 }
 
 static void inputs_pipe_add_init(RedChannelClient *rcc)
commit 9c6a49c364699ea20d3603572fa5b829612d8914
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Aug 14 15:42:36 2012 +0300

    char_device: don't connect a migrated client if the state of the device might have changed since it was created
    
    If reading/writing from the device have occured before migration data
    has arrived, the migration data might no longer be relvant, and we
    disconnect the client.

diff --git a/server/char_device.c b/server/char_device.c
index b85a24d..ac2632d 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -681,20 +681,25 @@ void spice_char_device_state_destroy(SpiceCharDeviceState *char_dev)
     spice_char_device_state_unref(char_dev);
 }
 
-void spice_char_device_client_add(SpiceCharDeviceState *dev,
-                                  RedClient *client,
-                                  int do_flow_control,
-                                  uint32_t max_send_queue_size,
-                                  uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens,
-                                  int wait_for_migrate_data)
+int spice_char_device_client_add(SpiceCharDeviceState *dev,
+                                 RedClient *client,
+                                 int do_flow_control,
+                                 uint32_t max_send_queue_size,
+                                 uint32_t num_client_tokens,
+                                 uint32_t num_send_tokens,
+                                 int wait_for_migrate_data)
 {
     SpiceCharDeviceClientState *dev_client;
 
     spice_assert(dev);
     spice_assert(client);
 
-    spice_assert(!wait_for_migrate_data || (dev->num_clients == 0 && !dev->active));
+    if (wait_for_migrate_data && (dev->num_clients > 0 || dev->active)) {
+        spice_warning("can't restore device %p from migration data. The device "
+                      "has already been active", dev);
+        return FALSE;
+    }
+
     dev->wait_for_migrate_data = wait_for_migrate_data;
 
     spice_debug("dev_state %p client %p", dev, client);
@@ -721,6 +726,7 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
     dev->num_clients++;
     /* Now that we have a client, forward any pending device data */
     spice_char_device_wakeup(dev);
+    return TRUE;
 }
 
 void spice_char_device_client_remove(SpiceCharDeviceState *dev,
diff --git a/server/char_device.h b/server/char_device.h
index 6688e91..d6d75e3 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -148,13 +148,13 @@ void spice_char_device_reset(SpiceCharDeviceState *dev);
 
 /* max_send_queue_size = how many messages we can read from the device and enqueue for this client,
  * when we have tokens for other clients and no tokens for this one */
-void spice_char_device_client_add(SpiceCharDeviceState *dev,
-                                  RedClient *client,
-                                  int do_flow_control,
-                                  uint32_t max_send_queue_size,
-                                  uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens,
-                                  int wait_for_migrate_data);
+int spice_char_device_client_add(SpiceCharDeviceState *dev,
+                                 RedClient *client,
+                                 int do_flow_control,
+                                 uint32_t max_send_queue_size,
+                                 uint32_t num_client_tokens,
+                                 uint32_t num_send_tokens,
+                                 int wait_for_migrate_data);
 
 void spice_char_device_client_remove(SpiceCharDeviceState *dev,
                                      RedClient *client);
diff --git a/server/reds.c b/server/reds.c
index ba42b88..8ad8425 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1111,13 +1111,21 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
      * flow control, but will have no other problem.
      */
     if (!spice_char_device_client_exists(dev_state, rcc->client)) {
-        spice_char_device_client_add(dev_state,
-                                     rcc->client,
-                                     TRUE, /* flow control */
-                                     REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
-                                     REDS_AGENT_WINDOW_SIZE,
-                                     num_tokens,
-                                     red_channel_client_waits_for_migrate_data(rcc));
+        int client_added;
+
+        client_added = spice_char_device_client_add(dev_state,
+                                                    rcc->client,
+                                                    TRUE, /* flow control */
+                                                    REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
+                                                    REDS_AGENT_WINDOW_SIZE,
+                                                    num_tokens,
+                                                    red_channel_client_waits_for_migrate_data(rcc));
+
+        if (!client_added) {
+            spice_warning("failed to add client to agent");
+            reds_client_disconnect(rcc->client);
+            return;
+        }
     } else {
         spice_char_device_send_to_client_tokens_set(dev_state,
                                                     rcc->client,
@@ -3580,13 +3588,21 @@ static SpiceCharDeviceState *attach_to_red_agent(SpiceCharDeviceInstance *sin)
     } else {
        spice_debug("waiting for migration data");
         if (!spice_char_device_client_exists(reds->agent_state.base, reds_get_client())) {
-            spice_char_device_client_add(reds->agent_state.base,
-                                         reds_get_client(),
-                                         TRUE, /* flow control */
-                                         REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
-                                         REDS_AGENT_WINDOW_SIZE,
-                                         ~0,
-                                         TRUE);
+            int client_added;
+
+            client_added = spice_char_device_client_add(reds->agent_state.base,
+                                                        reds_get_client(),
+                                                        TRUE, /* flow control */
+                                                        REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
+                                                        REDS_AGENT_WINDOW_SIZE,
+                                                        ~0,
+                                                        TRUE);
+
+            if (!client_added) {
+                spice_warning("failed to add client to agent");
+                reds_disconnect();
+            }
+
         }
     }
     return state->base;
diff --git a/server/smartcard.c b/server/smartcard.c
index 0ec8a13..7c3a070 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -339,17 +339,25 @@ static void smartcard_char_device_attach_client(SpiceCharDeviceInstance *char_de
                                                 SmartCardChannelClient *scc)
 {
     SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st);
+    int client_added;
 
     spice_assert(!scc->smartcard_state && !st->scc);
     st->scc = scc;
-    spice_char_device_client_add(st->chardev_st,
-                                 scc->base.client,
-                                 FALSE, /* no flow control yet */
-                                 0, /* send queue size */
-                                 ~0,
-                                 ~0,
-                                 red_channel_client_waits_for_migrate_data(&scc->base));
     scc->smartcard_state = st;
+    client_added = spice_char_device_client_add(st->chardev_st,
+                                                scc->base.client,
+                                                FALSE, /* no flow control yet */
+                                                0, /* send queue size */
+                                                ~0,
+                                                ~0,
+                                                red_channel_client_waits_for_migrate_data(
+                                                    &scc->base));
+    if (!client_added) {
+        spice_warning("failed");
+        st->scc = NULL;
+        scc->smartcard_state = NULL;
+        red_channel_client_disconnect(&scc->base);
+    }
 }
 
 static void smartcard_char_device_notify_reader_remove(SmartCardDeviceState *st)
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 1ce3169..b6eaa08 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -384,8 +384,12 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
     state->rcc = rcc;
     red_channel_client_ack_zero_messages_window(rcc);
 
-    spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0,
-                                 red_channel_client_waits_for_migrate_data(rcc));
+    if (!spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0,
+                                      red_channel_client_waits_for_migrate_data(rcc))) {
+        spice_warning("failed to add client to spicevmc");
+        red_channel_client_disconnect(rcc);
+        return;
+    }
 
     if (sif->state) {
         sif->state(sin, 1);
commit a180fc5e0b1efdecc3101fbe04d9478e18a940ec
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 20:43:13 2012 +0300

    main: restore state from migration data
    
    Also removed old migration leftovers.

diff --git a/server/main_channel.c b/server/main_channel.c
index 0c31c88..1df19df 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -500,31 +500,26 @@ static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
     reds_marshall_migrate_data(m); // TODO: from reds split. ugly separation.
 }
 
-static uint64_t main_channel_handle_migrate_data_get_serial(RedChannelClient *base,
+static int main_channel_handle_migrate_data(RedChannelClient *rcc,
     uint32_t size, void *message)
 {
-    MainMigrateData *data = message;
-
-    if (size < sizeof(*data)) {
-        spice_printerr("bad message size");
-        return 0;
-    }
-    return data->serial;
-}
+    MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, base);
+    SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message;
 
-static int main_channel_handle_migrate_data(RedChannelClient *base,
-    uint32_t size, void *message)
-{
-    MainChannelClient *mcc = SPICE_CONTAINEROF(base, MainChannelClient, base);
-    MainMigrateData *data = message;
+    /* not supported with multi-clients */
+    spice_assert(rcc->channel->clients_num == 1);
 
-    if (size < sizeof(*data)) {
-        spice_printerr("bad message size");
+    if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataMain)) {
+        spice_printerr("bad message size %u", size);
         return FALSE;
     }
-    mcc->ping_id = data->ping_id;
-    reds_on_main_receive_migrate_data(data, ((uint8_t*)message) + size);
-    return TRUE;
+    if (!migration_protocol_validate_header(header,
+                                            SPICE_MIGRATE_DATA_MAIN_MAGIC,
+                                            SPICE_MIGRATE_DATA_MAIN_VERSION)) {
+        spice_error("bad header");
+        return FALSE;
+    }
+    return reds_handle_migrate_data(mcc, (SpiceMigrateDataMain *)(header + 1), size);
 }
 
 void main_channel_push_init(MainChannelClient *mcc,
@@ -1173,7 +1168,6 @@ MainChannel* main_channel_init(void)
     channel_cbs.release_recv_buf = main_channel_release_msg_rcv_buf;
     channel_cbs.handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
     channel_cbs.handle_migrate_data = main_channel_handle_migrate_data;
-    channel_cbs.handle_migrate_data_get_serial = main_channel_handle_migrate_data_get_serial;
 
     // TODO: set the migration flag of the channel
     channel = red_channel_create_parser(sizeof(MainChannel), core,
diff --git a/server/main_channel.h b/server/main_channel.h
index cc73104..285a009 100644
--- a/server/main_channel.h
+++ b/server/main_channel.h
@@ -24,27 +24,6 @@
 #include "reds.h"
 #include "red_channel.h"
 
-/* This is a temporary measure for reds/main split - should not be in a header,
- * but private (although only reds.c includes main_channel.h) */
-struct MainMigrateData {
-    uint32_t version;
-    uint32_t serial;
-    uint32_t ping_id;
-
-    uint32_t agent_connected;
-    uint32_t client_agent_started;
-    uint32_t num_client_tokens;
-    uint32_t send_tokens;
-
-    uint32_t read_state;
-    VDIChunkHeader vdi_chunk_header;
-    uint32_t recive_len;
-    uint32_t message_recive_len;
-    uint32_t read_buf_len;
-
-    uint32_t write_queue_size;
-};
-
 // TODO: Defines used to calculate receive buffer size, and also by reds.c
 // other options: is to make a reds_main_consts.h, to duplicate defines.
 #define REDS_AGENT_WINDOW_SIZE 10
diff --git a/server/reds.c b/server/reds.c
index 40426e8..ba42b88 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -181,6 +181,9 @@ typedef struct VDIPortState {
     AgentMsgFilter read_filter;
 
     VDIChunkHeader vdi_chunk_header;
+
+    SpiceMigrateDataMain *mig_data; /* storing it when migration data arrives
+                                       before agent is attached */
 } VDIPortState;
 
 /* messages that are addressed to the agent and are created in the server */
@@ -716,6 +719,8 @@ void reds_client_disconnect(RedClient *client)
          *  messages read from the agent */
         reds->agent_state.read_filter.result = AGENT_MSG_FILTER_DISCARD;
         reds->agent_state.read_filter.discard_all = TRUE;
+        free(reds->agent_state.mig_data);
+        reds->agent_state.mig_data = NULL;
 
         reds_mig_cleanup();
     }
@@ -793,8 +798,8 @@ static void reds_agent_remove(void)
 
     vdagent = NULL;
     reds_update_mouse_mode();
-
-    if (reds_main_channel_connected()) {
+    if (reds_main_channel_connected() &&
+        !red_channel_waits_for_migrate_data(&reds->main_channel->base)) {
         main_channel_push_agent_disconnected(reds->main_channel);
     }
 }
@@ -1343,9 +1348,114 @@ void reds_marshall_migrate_data(SpiceMarshaller *m)
                  agent_state->write_filter.result);
 }
 
-void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
+static int reds_agent_state_restore(SpiceMigrateDataMain *mig_data)
+{
+    VDIPortState *agent_state = &reds->agent_state;
+    uint32_t chunk_header_remaining;
+
+    agent_state->vdi_chunk_header = mig_data->agent2client.chunk_header;
+    spice_assert(mig_data->agent2client.chunk_header_size <= sizeof(VDIChunkHeader));
+    chunk_header_remaining = sizeof(VDIChunkHeader) - mig_data->agent2client.chunk_header_size;
+    if (chunk_header_remaining) {
+        agent_state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
+        agent_state->recive_pos = (uint8_t *)&agent_state->vdi_chunk_header +
+            mig_data->agent2client.chunk_header_size;
+        agent_state->recive_len = chunk_header_remaining;
+    } else {
+        agent_state->message_recive_len = agent_state->vdi_chunk_header.size;
+    }
+
+    if (!mig_data->agent2client.msg_header_done) {
+        uint8_t *partial_msg_header;
+
+        if (!chunk_header_remaining) {
+            uint32_t cur_buf_size;
+
+            agent_state->read_state = VDI_PORT_READ_STATE_READ_DATA;
+            agent_state->current_read_buf = vdi_port_read_buf_get();
+            spice_assert(agent_state->current_read_buf);
+            partial_msg_header = (uint8_t *)mig_data + mig_data->agent2client.msg_header_ptr -
+                sizeof(SpiceMiniDataHeader);
+            memcpy(agent_state->current_read_buf->data,
+                   partial_msg_header,
+                   mig_data->agent2client.msg_header_partial_len);
+            agent_state->recive_pos = agent_state->current_read_buf->data +
+                                      mig_data->agent2client.msg_header_partial_len;
+            cur_buf_size = sizeof(agent_state->current_read_buf->data) -
+                           mig_data->agent2client.msg_header_partial_len;
+            agent_state->recive_len = MIN(agent_state->message_recive_len, cur_buf_size);
+            agent_state->current_read_buf->len = agent_state->recive_len +
+                                                 mig_data->agent2client.msg_header_partial_len;
+            agent_state->message_recive_len -= agent_state->recive_len;
+        } else {
+            spice_assert(mig_data->agent2client.msg_header_partial_len == 0);
+        }
+    } else {
+            agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
+            agent_state->current_read_buf = NULL;
+            agent_state->recive_pos = NULL;
+            agent_state->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining;
+            agent_state->read_filter.result = mig_data->agent2client.msg_filter_result;
+    }
+
+    agent_state->read_filter.discard_all = FALSE;
+    agent_state->write_filter.discard_all = !mig_data->client_agent_started;
+    agent_state->client_agent_started = mig_data->client_agent_started;
+
+    agent_state->write_filter.msg_data_to_read = mig_data->client2agent.msg_remaining;
+    agent_state->write_filter.result = mig_data->client2agent.msg_filter_result;
+
+    spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
+                agent_state->write_filter.discard_all,
+                agent_state->write_filter.msg_data_to_read,
+                 agent_state->write_filter.result);
+    spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
+                agent_state->read_filter.discard_all,
+                agent_state->read_filter.msg_data_to_read,
+                 agent_state->read_filter.result);
+    return spice_char_device_state_restore(agent_state->base, &mig_data->agent_base);
+}
+
+/*
+ * The agent device is not attached to the dest before migration is completed. It is
+ * attached only after the vm is started. It might be attached before or after
+ * the migration data has reached the server.
+ */
+int reds_handle_migrate_data(MainChannelClient *mcc, SpiceMigrateDataMain *mig_data, uint32_t size)
 {
-    spice_warning("not implemented");
+    VDIPortState *agent_state = &reds->agent_state;
+
+    if (mig_data->agent_base.connected) {
+        if (agent_state->base) { // agent was attached before migration data has arrived
+            if (!vdagent) {
+                spice_assert(agent_state->plug_generation > 0);
+                main_channel_push_agent_disconnected(reds->main_channel);
+                spice_debug("agent is no longer connected");
+            } else {
+                if (agent_state->plug_generation > 1) {
+                    /* spice_char_device_state_reset takes care of not making the device wait for migration data */
+                    spice_debug("agent has been detached and reattached before receiving migration data");
+                    main_channel_push_agent_disconnected(reds->main_channel);
+                    main_channel_push_agent_connected(reds->main_channel);
+                } else {
+                    return reds_agent_state_restore(mig_data);
+                }
+            }
+        } else {
+            /* restore agent starte when the agent gets attached */
+            spice_assert(agent_state->plug_generation == 0);
+            agent_state->mig_data = spice_memdup(mig_data, size);
+        }
+    } else {
+        if (vdagent) {
+            /* spice_char_device_client_remove disables waiting for migration data */
+            spice_char_device_client_remove(agent_state->base,
+                                            main_channel_client_get_base(mcc)->client);
+            main_channel_push_agent_connected(reds->main_channel);
+        }
+    }
+
+    return TRUE;
 }
 
 static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
@@ -1568,6 +1678,18 @@ static int reds_find_client(RedClient *client)
     return FALSE;
 }
 
+/* should be used only when there is one client */
+static RedClient *reds_get_client(void)
+{
+    spice_assert(reds->num_clients <= 1);
+
+    if (reds->num_clients == 0) {
+        return NULL;
+    }
+
+    return SPICE_CONTAINEROF(ring_get_head(&reds->clients), RedClient, link);
+}
+
 // TODO: now that main is a separate channel this should
 // actually be joined with reds_handle_other_links, become reds_handle_link
 static void reds_handle_main_link(RedLinkInfo *link)
@@ -1624,6 +1746,9 @@ static void reds_handle_main_link(RedLinkInfo *link)
     red_client_set_main(client, mcc);
 
     if (vdagent) {
+        if (mig_target) {
+            spice_warning("unexpected: vdagent attached to destination during migration");
+        }
         reds->agent_state.read_filter.discard_all = FALSE;
         reds->agent_state.plug_generation++;
     }
@@ -3320,13 +3445,10 @@ static void reds_mig_remove_wait_disconnect_client(RedClient *client)
 
 static void reds_migrate_channels_seamless(void)
 {
-    RingItem *client_item;
     RedClient *client;
 
     /* seamless migration is supported for only one client for now */
-    spice_assert(reds->num_clients == 1);
-    client_item = ring_get_head(&reds->clients);
-    client = SPICE_CONTAINEROF(client_item, RedClient, link);
+    client = reds_get_client();
     red_client_migrate(client);
 }
 
@@ -3446,9 +3568,27 @@ static SpiceCharDeviceState *attach_to_red_agent(SpiceCharDeviceInstance *sin)
     state->read_filter.discard_all = FALSE;
     reds->agent_state.plug_generation++;
 
-    /* we will assoicate the client with the char device, upon reds_on_main_agent_start,
-     * in response to MSGC_AGENT_START */
-    main_channel_push_agent_connected(reds->main_channel);
+    if (reds->agent_state.mig_data) {
+        spice_assert(reds->agent_state.plug_generation == 1);
+        reds_agent_state_restore(reds->agent_state.mig_data);
+        free(reds->agent_state.mig_data);
+        reds->agent_state.mig_data = NULL;
+    } else if (!red_channel_waits_for_migrate_data(&reds->main_channel->base)) {
+        /* we will assoicate the client with the char device, upon reds_on_main_agent_start,
+         * in response to MSGC_AGENT_START */
+        main_channel_push_agent_connected(reds->main_channel);
+    } else {
+       spice_debug("waiting for migration data");
+        if (!spice_char_device_client_exists(reds->agent_state.base, reds_get_client())) {
+            spice_char_device_client_add(reds->agent_state.base,
+                                         reds_get_client(),
+                                         TRUE, /* flow control */
+                                         REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
+                                         REDS_AGENT_WINDOW_SIZE,
+                                         ~0,
+                                         TRUE);
+        }
+    }
     return state->base;
 }
 
diff --git a/server/reds.h b/server/reds.h
index e33e518..f8e8d56 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -32,6 +32,7 @@
 #include "common/messages.h"
 #include "spice.h"
 #include "red_channel.h"
+#include "migration_protocol.h"
 
 #define SPICE_GNUC_VISIBLE __attribute__ ((visibility ("default")))
 
@@ -152,7 +153,8 @@ void reds_release_agent_data_buffer(uint8_t *buf);
 void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size);
 void reds_on_main_migrate_connected(int seamless); //should be called when all the clients
                                                    // are connected to the target
-void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end);
+int reds_handle_migrate_data(MainChannelClient *mcc,
+                             SpiceMigrateDataMain *mig_data, uint32_t size);
 void reds_on_main_mouse_mode_request(void *message, size_t size);
 /* migration dest side: returns whether it can support seamless migration
  * with the given src migration protocol version */
commit fa9bfd01f182b34ceb8ff30ae730577cd64965cc
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 16:57:21 2012 +0300

    main: send migration data
    
    Also removed some unused definitions from reds that used to belong to
    old agent and migration code.

diff --git a/server/main_channel.c b/server/main_channel.c
index 6cdbc4d..0c31c88 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -496,13 +496,8 @@ static void main_channel_push_migrate_data_item(MainChannel *main_chan)
 static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
                                                     SpiceMarshaller *m, PipeItem *item)
 {
-    MainMigrateData *data = (MainMigrateData *)
-                            spice_marshaller_reserve_space(m, sizeof(MainMigrateData));
-
     red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
-    reds_marshall_migrate_data_item(m, data); // TODO: from reds split. ugly separation.
-    data->serial = red_channel_client_get_message_serial(rcc);
-    data->ping_id = SPICE_CONTAINEROF(rcc, MainChannelClient, base)->ping_id;
+    reds_marshall_migrate_data(m); // TODO: from reds split. ugly separation.
 }
 
 static uint64_t main_channel_handle_migrate_data_get_serial(RedChannelClient *base,
@@ -996,17 +991,13 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
 #endif
         break;
     }
-    case SPICE_MSGC_MIGRATE_FLUSH_MARK:
-        break;
-    case SPICE_MSGC_MIGRATE_DATA: {
-                }
     case SPICE_MSGC_DISCONNECTING:
         break;
     case SPICE_MSGC_MAIN_MIGRATE_END:
         main_channel_client_handle_migrate_end(mcc);
         break;
     default:
-        spice_printerr("unexpected type %d", type);
+        return red_channel_client_handle_message(rcc, size, type, message);
     }
     return TRUE;
 }
@@ -1046,6 +1037,7 @@ static void main_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
 
 static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
 {
+    spice_debug(NULL);
     main_channel_push_migrate_data_item(SPICE_CONTAINEROF(rcc->channel,
                                         MainChannel, base));
     return TRUE;
diff --git a/server/reds.c b/server/reds.c
index 1deceb4..40426e8 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -123,8 +123,6 @@ int agent_copypaste = TRUE;
 #define MIGRATE_TIMEOUT (1000 * 10) /* 10sec */
 #define MM_TIMER_GRANULARITY_MS (1000 / 30)
 #define MM_TIME_DELTA 400 /*ms*/
-#define VDI_PORT_WRITE_RETRY_TIMEOUT 100 /*ms*/
-
 
 typedef struct TicketAuthentication {
     char password[SPICE_MAX_PASSWORD_LENGTH];
@@ -166,6 +164,7 @@ enum {
 typedef struct VDIPortState {
     SpiceCharDeviceState *base;
     uint32_t plug_generation;
+    int client_agent_started;
 
     /* write to agent */
     SpiceCharDeviceWriteBuffer *recv_from_client_buf;
@@ -635,6 +634,7 @@ static void reds_reset_vdp(void)
        messages written by the client */
     state->write_filter.result = AGENT_MSG_FILTER_DISCARD;
     state->write_filter.discard_all = TRUE;
+    state->client_agent_started = FALSE;
 
     /* reseting and not destroying the state as a workaround for a bad
      * tokens management in the vdagent protocol:
@@ -1097,6 +1097,7 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
     }
     spice_assert(vdagent->st && vdagent->st == dev_state);
     rcc = main_channel_client_get_base(mcc);
+    reds->agent_state.client_agent_started = TRUE;
     /*
      * Note that in older releases, send_tokens were set to ~0 on both client
      * and server. The server ignored the client given tokens.
@@ -1263,16 +1264,83 @@ void reds_on_main_channel_migrate(MainChannelClient *mcc)
     }
 }
 
-#define MAIN_CHANNEL_MIG_DATA_VERSION 1
+void reds_marshall_migrate_data(SpiceMarshaller *m)
+{
+    SpiceMigrateDataMain mig_data;
+    VDIPortState *agent_state = &reds->agent_state;
+    SpiceMarshaller *m2;
 
-typedef struct WriteQueueInfo {
-    uint32_t port;
-    uint32_t len;
-} WriteQueueInfo;
+    memset(&mig_data, 0, sizeof(mig_data));
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_MAGIC);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_VERSION);
 
-void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data)
-{
-    spice_warning("not implemented");
+    if (!vdagent) {
+        spice_assert(!agent_state->base); /* MSG_AGENT_CONNECTED_TOKENS is supported by the client
+                                             (see spice_server_migrate_connect), so SpiceCharDeviceState
+                                             is destroyed when the agent is disconnected and
+                                             there is no need to track the client tokens
+                                             (see reds_reset_vdp) */
+        spice_char_device_state_migrate_data_marshall_empty(m);
+        spice_marshaller_add_ref(m,
+                                 (uint8_t *)&mig_data + sizeof(SpiceMigrateDataCharDevice),
+                                 sizeof(SpiceMigrateDataMain) - sizeof(SpiceMigrateDataCharDevice)
+                                 );
+        return;
+    }
+
+    spice_char_device_state_migrate_data_marshall(reds->agent_state.base, m);
+    spice_marshaller_add_uint8(m, reds->agent_state.client_agent_started);
+
+    mig_data.agent2client.chunk_header = agent_state->vdi_chunk_header;
+
+    /* agent to client partial msg */
+    if (agent_state->read_state == VDI_PORT_READ_STATE_READ_HEADER) {
+        mig_data.agent2client.chunk_header_size = agent_state->recive_pos -
+            (uint8_t *)&agent_state->vdi_chunk_header;
+
+        mig_data.agent2client.msg_header_done = FALSE;
+        mig_data.agent2client.msg_header_partial_len = 0;
+        spice_assert(!agent_state->read_filter.msg_data_to_read );
+    } else {
+        mig_data.agent2client.chunk_header_size = sizeof(VDIChunkHeader);
+        mig_data.agent2client.chunk_header.size = agent_state->message_recive_len;
+        if (agent_state->read_state == VDI_PORT_READ_STATE_READ_DATA) {
+            /* in the middle of reading the message header (see reds_on_main_channel_migrate) */
+            mig_data.agent2client.msg_header_done = FALSE;
+            mig_data.agent2client.msg_header_partial_len =
+                agent_state->recive_pos - agent_state->current_read_buf->data;
+            spice_assert(mig_data.agent2client.msg_header_partial_len < sizeof(VDAgentMessage));
+            spice_assert(!agent_state->read_filter.msg_data_to_read);
+        } else {
+            mig_data.agent2client.msg_header_done =  TRUE;
+            mig_data.agent2client.msg_remaining = agent_state->read_filter.msg_data_to_read;
+            mig_data.agent2client.msg_filter_result = agent_state->read_filter.result;
+        }
+    }
+    spice_marshaller_add_uint32(m, mig_data.agent2client.chunk_header_size);
+    spice_marshaller_add_ref(m,
+                             (uint8_t *)&mig_data.agent2client.chunk_header,
+                             sizeof(VDIChunkHeader));
+    spice_marshaller_add_uint8(m, mig_data.agent2client.msg_header_done);
+    spice_marshaller_add_uint32(m, mig_data.agent2client.msg_header_partial_len);
+    m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
+    spice_marshaller_add_ref(m2, agent_state->current_read_buf->data,
+                             mig_data.agent2client.msg_header_partial_len);
+    spice_marshaller_add_uint32(m, mig_data.agent2client.msg_remaining);
+    spice_marshaller_add_uint8(m, mig_data.agent2client.msg_filter_result);
+
+    mig_data.client2agent.msg_remaining = agent_state->write_filter.msg_data_to_read;
+    mig_data.client2agent.msg_filter_result = agent_state->write_filter.result;
+    spice_marshaller_add_uint32(m, mig_data.client2agent.msg_remaining);
+    spice_marshaller_add_uint8(m, mig_data.client2agent.msg_filter_result);
+    spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
+                agent_state->read_filter.discard_all,
+                agent_state->read_filter.msg_data_to_read,
+                 agent_state->read_filter.result);
+    spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
+                agent_state->write_filter.discard_all,
+                agent_state->write_filter.msg_data_to_read,
+                 agent_state->write_filter.result);
 }
 
 void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
@@ -4130,6 +4198,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char*
                                                     const char* cert_subject)
 {
     SpiceMigrateInterface *sif;
+    int try_seamless;
 
     spice_info(NULL);
     spice_assert(migration_interface);
@@ -4149,9 +4218,20 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char*
 
     reds->expect_migrate = TRUE;
 
+    /*
+     * seamless migration support was added to the client after the support in
+     * agent_connect_tokens, so there shouldn't be contradicition - if
+     * the client is capable of seamless migration, it is capbable of agent_connected_tokens.
+     * The demand for agent_connected_tokens support is in order to assure that if migration
+     * occured when the agent was not connected, the tokens state after migration will still
+     * be valid (see reds_reset_vdp for more details).
+     */
+    try_seamless = reds->seamless_migration_enabled &&
+                   red_channel_test_remote_cap(&reds->main_channel->base,
+                   SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
     /* main channel will take care of clients that are still during migration (at target)*/
     if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice,
-                                     reds->seamless_migration_enabled)) {
+                                     try_seamless)) {
         reds_mig_started();
     } else {
         if (reds->num_clients == 0) {
diff --git a/server/reds.h b/server/reds.h
index a575d11..e33e518 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -135,7 +135,7 @@ void reds_client_disconnect(RedClient *client);
 
 // Temporary (?) for splitting main channel
 typedef struct MainMigrateData MainMigrateData;
-void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data);
+void reds_marshall_migrate_data(SpiceMarshaller *m);
 void reds_fill_channels(SpiceMsgChannels *channels_info);
 int reds_num_of_channels(void);
 int reds_num_of_clients(void);
commit 3af4b7235d23e9d0be2da780d5da9b3fcb29466f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 15:57:44 2012 +0300

    main: send MSG_MIGRATE upon vm migration completion
    
    Before sending the above msg, if there is a pending partial msg that
    has been read from the agent, we send it to the client. The alternative
    was to keep the msg as part of the migration data, and then
    to send it to the destination server via the client and to wait there
    for the msg chunk completion, before sending it to the client. Of
    course, the latter is less efficient.

diff --git a/server/main_channel.c b/server/main_channel.c
index 648a06d..6cdbc4d 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -1160,10 +1160,17 @@ uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc)
     return mcc->bitrate_per_sec;
 }
 
+static void main_channel_client_migrate(RedChannelClient *rcc)
+{
+    reds_on_main_channel_migrate(SPICE_CONTAINEROF(rcc, MainChannelClient, base));
+    red_channel_client_default_migrate(rcc);
+}
+
 MainChannel* main_channel_init(void)
 {
     RedChannel *channel;
     ChannelCbs channel_cbs = { NULL, };
+    ClientCbs client_cbs = {NULL, };
 
     channel_cbs.config_socket = main_channel_config_socket;
     channel_cbs.on_disconnect = main_channel_client_on_disconnect;
@@ -1187,6 +1194,9 @@ MainChannel* main_channel_init(void)
     spice_assert(channel);
     red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
 
+    client_cbs.migrate = main_channel_client_migrate;
+    red_channel_register_client_cbs(channel, &client_cbs);
+
     return (MainChannel *)channel;
 }
 
diff --git a/server/red_channel.c b/server/red_channel.c
index 16335a3..803804e 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -901,7 +901,7 @@ RedChannel *red_channel_create_parser(int size,
 
 void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs)
 {
-    spice_assert(client_cbs->connect);
+    spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN);
     channel->client_cbs.connect = client_cbs->connect;
 
     if (client_cbs->disconnect) {
diff --git a/server/reds.c b/server/reds.c
index f1cc2f2..1deceb4 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1219,6 +1219,50 @@ void reds_on_main_mouse_mode_request(void *message, size_t size)
     }
 }
 
+/*
+ * Push partial agent data, even if not all the chunk was consumend,
+ * in order to avoid the roundtrip (src-server->client->dest-server)
+ */
+void reds_on_main_channel_migrate(MainChannelClient *mcc)
+{
+    VDIPortState *agent_state = &reds->agent_state;
+    uint32_t read_data_len;
+
+    spice_assert(reds->num_clients == 1);
+
+    if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) {
+        return;
+    }
+    spice_assert(agent_state->current_read_buf->data &&
+                 agent_state->recive_pos > agent_state->current_read_buf->data);
+    read_data_len = agent_state->recive_pos - agent_state->current_read_buf->data;
+
+    if (agent_state->read_filter.msg_data_to_read ||
+        read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */
+        VDIReadBuf *read_buf = agent_state->current_read_buf;
+
+        spice_debug("push partial read %u (msg first chunk? %d)", read_data_len,
+                    !agent_state->read_filter.msg_data_to_read);
+
+        read_buf->len = read_data_len;
+        if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) {
+            main_channel_client_push_agent_data(mcc,
+                                                read_buf->data,
+                                                read_buf->len,
+                                                vdi_port_read_buf_release,
+                                                read_buf);
+        } else {
+            vdi_port_read_buf_unref(read_buf);
+        }
+
+        spice_assert(agent_state->recive_len);
+        agent_state->message_recive_len += agent_state->recive_len;
+        agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
+        agent_state->current_read_buf = NULL;
+        agent_state->recive_pos = NULL;
+    }
+}
+
 #define MAIN_CHANNEL_MIG_DATA_VERSION 1
 
 typedef struct WriteQueueInfo {
diff --git a/server/reds.h b/server/reds.h
index 779d0db..a575d11 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -159,6 +159,7 @@ void reds_on_main_mouse_mode_request(void *message, size_t size);
 int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version);
 void reds_on_client_semi_seamless_migrate_complete(RedClient *client);
 void reds_on_client_seamless_migrate_complete(RedClient *client);
+void reds_on_main_channel_migrate(MainChannelClient *mcc);
 void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
 #endif
commit c617379821feb0c2cf990394163765498ae1bda1
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 16:00:55 2012 +0300

    reds: s/HADER/HEADER

diff --git a/server/reds.c b/server/reds.c
index a5a5a75..f1cc2f2 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -158,7 +158,7 @@ static VDIReadBuf *vdi_port_read_buf_ref(VDIReadBuf *buf);
 static void vdi_port_read_buf_unref(VDIReadBuf *buf);
 
 enum {
-    VDI_PORT_READ_STATE_READ_HADER,
+    VDI_PORT_READ_STATE_READ_HEADER,
     VDI_PORT_READ_STATE_GET_BUFF,
     VDI_PORT_READ_STATE_READ_DATA,
 };
@@ -621,7 +621,7 @@ static void reds_reset_vdp(void)
     VDIPortState *state = &reds->agent_state;
     SpiceCharDeviceInterface *sif;
 
-    state->read_state = VDI_PORT_READ_STATE_READ_HADER;
+    state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
     state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
     state->recive_len = sizeof(state->vdi_chunk_header);
     state->message_recive_len = 0;
@@ -894,7 +894,7 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe
     sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
     while (vdagent) {
         switch (state->read_state) {
-        case VDI_PORT_READ_STATE_READ_HADER:
+        case VDI_PORT_READ_STATE_READ_HEADER:
             n = sif->read(vdagent, state->recive_pos, state->recive_len);
             if (!n) {
                 return NULL;
@@ -929,7 +929,7 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe
             state->current_read_buf = NULL;
             state->recive_pos = NULL;
             if (state->message_recive_len == 0) {
-                state->read_state = VDI_PORT_READ_STATE_READ_HADER;
+                state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
                 state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
                 state->recive_len = sizeof(state->vdi_chunk_header);
             } else {
@@ -3616,7 +3616,7 @@ static void init_vd_agent_resources(void)
     agent_msg_filter_init(&state->write_filter, agent_copypaste, TRUE);
     agent_msg_filter_init(&state->read_filter, agent_copypaste, TRUE);
 
-    state->read_state = VDI_PORT_READ_STATE_READ_HADER;
+    state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
     state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
     state->recive_len = sizeof(state->vdi_chunk_header);
 
commit 443b2d4270c7379cb3a54501299223302f54a3db
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 15:05:20 2012 +0300

    migration_protocol: add migration data for the main channel (mainly for the agent)

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index 67ad1bf..d2a5575 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -18,6 +18,8 @@
 #ifndef _H_MIGRATION_PROTOCOL
 #define _H_MIGRATION_PROTOCOL
 
+#include <spice/vd_agent.h>
+
 /* ************************************************
  * src-server to dst-server migration data messages
  * ************************************************/
@@ -76,6 +78,37 @@ typedef struct __attribute__ ((__packed__)) SpiceMigrateDataSmartcard {
     uint32_t read_data_ptr;
 } SpiceMigrateDataSmartcard;
 
+/* *********************************
+ * main channel (mainly guest agent)
+ * *********************************/
+#define SPICE_MIGRATE_DATA_MAIN_VERSION 1 /* NOTE: increase version when CHAR_DEVICE_VERSION
+                                             is increased */
+#define SPICE_MIGRATE_DATA_MAIN_MAGIC (*(uint32_t *)"MNMD")
+
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataMain {
+    SpiceMigrateDataCharDevice agent_base;
+    uint8_t client_agent_started; /* for discarding messages */
+
+    struct __attribute__ ((__packed__)) {
+        /* partial data read from device. Such data is stored only
+         * if the chunk header or the entire msg header haven't yet been read completely.
+         * Once the headers are read, partial reads of chunks can be sent as
+         * smaller chunks to the client, without the roundtrip overhead of migration data */
+        uint32_t chunk_header_size;
+        VDIChunkHeader chunk_header;
+        uint8_t msg_header_done;
+        uint32_t msg_header_partial_len;
+        uint32_t msg_header_ptr;
+        uint32_t msg_remaining;
+        uint8_t msg_filter_result;
+    } agent2client;
+
+    struct __attribute__ ((__packed__)) {
+        uint32_t msg_remaining;
+        uint8_t msg_filter_result;
+    } client2agent;
+} SpiceMigrateDataMain;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit d866114d9087c66b59ec13742bb6beee79f166d6
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 14:35:57 2012 +0300

    main_channel: fix using spice messages enums as pipe items type
    
    A channel pipe item type must start from PIPE_ITEM_TYPE_CHANNEL_BASE.
    SPICE_MSG_MIGRATE value eq. PIPE_ITEM_TYPE_SET_ACK. Setting a pipe item
    type to SPICE_MSG_MIGRATE, leads to red_channel handling PIPE_ITEM_TYPE_SET_ACK.
    
    Also removed sending SPICE_MSG_MIGRATE. It will be handled in the next
    patch.

diff --git a/server/main_channel.c b/server/main_channel.c
index e06bb05..648a06d 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -56,6 +56,25 @@
 
 static uint8_t zero_page[ZERO_BUF_SIZE] = {0};
 
+enum {
+    PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST = PIPE_ITEM_TYPE_CHANNEL_BASE,
+    PIPE_ITEM_TYPE_MAIN_PING,
+    PIPE_ITEM_TYPE_MAIN_MOUSE_MODE,
+    PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED,
+    PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN,
+    PIPE_ITEM_TYPE_MAIN_AGENT_DATA,
+    PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA,
+    PIPE_ITEM_TYPE_MAIN_INIT,
+    PIPE_ITEM_TYPE_MAIN_NOTIFY,
+    PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN,
+    PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS,
+    PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST,
+    PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME,
+    PIPE_ITEM_TYPE_MAIN_NAME,
+    PIPE_ITEM_TYPE_MAIN_UUID,
+    PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS,
+};
+
 typedef struct RedsOutItem RedsOutItem;
 struct RedsOutItem {
     PipeItem base;
@@ -204,7 +223,7 @@ static PipeItem *main_mouse_mode_item_new(RedChannelClient *rcc, void *data, int
     MainMouseModeItemInfo *info = data;
 
     red_channel_pipe_item_init(rcc->channel, &item->base,
-                               SPICE_MSG_MAIN_MOUSE_MODE);
+                               PIPE_ITEM_TYPE_MAIN_MOUSE_MODE);
     item->current_mode = info->current_mode;
     item->is_client_mouse_allowed = info->is_client_mouse_allowed;
     return &item->base;
@@ -214,7 +233,7 @@ static PipeItem *main_ping_item_new(MainChannelClient *mcc, int size)
 {
     PingPipeItem *item = spice_malloc(sizeof(PingPipeItem));
 
-    red_channel_pipe_item_init(mcc->base.channel, &item->base, SPICE_MSG_PING);
+    red_channel_pipe_item_init(mcc->base.channel, &item->base, PIPE_ITEM_TYPE_MAIN_PING);
     item->size = size;
     return &item->base;
 }
@@ -224,7 +243,7 @@ static PipeItem *main_agent_tokens_item_new(RedChannelClient *rcc, uint32_t num_
     TokensPipeItem *item = spice_malloc(sizeof(TokensPipeItem));
 
     red_channel_pipe_item_init(rcc->channel, &item->base,
-                               SPICE_MSG_MAIN_AGENT_TOKEN);
+                               PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN);
     item->tokens = num_tokens;
     return &item->base;
 }
@@ -236,7 +255,7 @@ static PipeItem *main_agent_data_item_new(RedChannelClient *rcc, uint8_t* data,
     AgentDataPipeItem *item = spice_malloc(sizeof(AgentDataPipeItem));
 
     red_channel_pipe_item_init(rcc->channel, &item->base,
-                               SPICE_MSG_MAIN_AGENT_DATA);
+                               PIPE_ITEM_TYPE_MAIN_AGENT_DATA);
     item->data = data;
     item->len = len;
     item->free_data = free_data;
@@ -252,7 +271,7 @@ static PipeItem *main_init_item_new(MainChannelClient *mcc,
     InitPipeItem *item = spice_malloc(sizeof(InitPipeItem));
 
     red_channel_pipe_item_init(mcc->base.channel, &item->base,
-                               SPICE_MSG_MAIN_INIT);
+                               PIPE_ITEM_TYPE_MAIN_INIT);
     item->connection_id = connection_id;
     item->display_channels_hint = display_channels_hint;
     item->current_mouse_mode = current_mouse_mode;
@@ -267,7 +286,7 @@ static PipeItem *main_name_item_new(MainChannelClient *mcc, const char *name)
     NamePipeItem *item = spice_malloc(sizeof(NamePipeItem) + strlen(name) + 1);
 
     red_channel_pipe_item_init(mcc->base.channel, &item->base,
-                               SPICE_MSG_MAIN_NAME);
+                               PIPE_ITEM_TYPE_MAIN_NAME);
     item->msg.name_len = strlen(name) + 1;
     memcpy(&item->msg.name, name, item->msg.name_len);
 
@@ -279,7 +298,7 @@ static PipeItem *main_uuid_item_new(MainChannelClient *mcc, const uint8_t uuid[1
     UuidPipeItem *item = spice_malloc(sizeof(UuidPipeItem));
 
     red_channel_pipe_item_init(mcc->base.channel, &item->base,
-                               SPICE_MSG_MAIN_UUID);
+                               PIPE_ITEM_TYPE_MAIN_UUID);
     memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid));
 
     return &item->base;
@@ -296,7 +315,7 @@ static PipeItem *main_notify_item_new(RedChannelClient *rcc, void *data, int num
     NotifyPipeInfo *info = data;
 
     red_channel_pipe_item_init(rcc->channel, &item->base,
-                               SPICE_MSG_NOTIFY);
+                               PIPE_ITEM_TYPE_MAIN_NOTIFY);
     item->mess = info->mess;
     item->mess_len = info->mess_len;
     return &item->base;
@@ -309,7 +328,7 @@ static PipeItem *main_multi_media_time_item_new(
 
     item = spice_malloc(sizeof(MultiMediaTimePipeItem));
     red_channel_pipe_item_init(rcc->channel, &item->base,
-                               SPICE_MSG_MAIN_MULTI_MEDIA_TIME);
+                               PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME);
     item->time = info->time;
     return &item->base;
 }
@@ -321,13 +340,16 @@ static void main_channel_push_channels(MainChannelClient *mcc)
                    "during migration");
         return;
     }
-    red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_CHANNELS_LIST);
+    red_channel_client_pipe_add_type(&mcc->base, PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST);
 }
 
-static void main_channel_marshall_channels(SpiceMarshaller *m)
+static void main_channel_marshall_channels(RedChannelClient *rcc,
+                                           SpiceMarshaller *m,
+                                           PipeItem *item)
 {
     SpiceMsgChannels* channels_info;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item);
     channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels)
                             + reds_num_of_channels() * sizeof(SpiceChannelId));
     reds_fill_channels(channels_info);
@@ -347,19 +369,24 @@ int main_channel_client_push_ping(MainChannelClient *mcc, int size)
     return TRUE;
 }
 
-static void main_channel_marshall_ping(SpiceMarshaller *m, int size, int ping_id)
+static void main_channel_marshall_ping(RedChannelClient *rcc,
+                                       SpiceMarshaller *m,
+                                       PingPipeItem *item)
 {
+    MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, base);
     struct timespec time_space;
     SpiceMsgPing ping;
+    int size_left = item->size;
 
-    ping.id = ping_id;
+    red_channel_client_init_send_data(rcc, SPICE_MSG_PING, &item->base);
+    ping.id = ++(mcc->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);
 
-    while (size > 0) {
-        int now = MIN(ZERO_BUF_SIZE, size);
-        size -= now;
+    while (size_left > 0) {
+        int now = MIN(ZERO_BUF_SIZE, size_left);
+        size_left -= now;
         spice_marshaller_add_ref(m, zero_page, now);
     }
 }
@@ -376,44 +403,53 @@ void main_channel_push_mouse_mode(MainChannel *main_chan, int current_mode,
         main_mouse_mode_item_new, &info);
 }
 
-static void main_channel_marshall_mouse_mode(SpiceMarshaller *m, int current_mode,
-                                             int is_client_mouse_allowed)
+static void main_channel_marshall_mouse_mode(RedChannelClient *rcc,
+                                             SpiceMarshaller *m,
+                                             MouseModePipeItem *item)
 {
     SpiceMsgMainMouseMode mouse_mode;
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MOUSE_MODE, &item->base);
     mouse_mode.supported_modes = SPICE_MOUSE_MODE_SERVER;
-    if (is_client_mouse_allowed) {
+    if (item->is_client_mouse_allowed) {
         mouse_mode.supported_modes |= SPICE_MOUSE_MODE_CLIENT;
     }
-    mouse_mode.current_mode = current_mode;
+    mouse_mode.current_mode = item->current_mode;
     spice_marshall_msg_main_mouse_mode(m, &mouse_mode);
 }
 
 void main_channel_push_agent_connected(MainChannel *main_chan)
 {
     if (red_channel_test_remote_cap(&main_chan->base, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
-        red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS);
+        red_channel_pipes_add_type(&main_chan->base, PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
     } else {
-        red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
+        red_channel_pipes_add_empty_msg(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
     }
 }
 
-static void main_channel_marshall_agent_connected(SpiceMarshaller *m)
+static void main_channel_marshall_agent_connected(SpiceMarshaller *m,
+                                                  RedChannelClient *rcc,
+                                                  PipeItem *item)
 {
     SpiceMsgMainAgentConnectedTokens connected;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS, item);
     connected.num_tokens = REDS_AGENT_WINDOW_SIZE;
     spice_marshall_msg_main_agent_connected_tokens(m, &connected);
 }
 
 void main_channel_push_agent_disconnected(MainChannel *main_chan)
 {
-    red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_DISCONNECTED);
+    red_channel_pipes_add_type(&main_chan->base, PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
 }
 
-static void main_channel_marshall_agent_disconnected(SpiceMarshaller *m)
+static void main_channel_marshall_agent_disconnected(RedChannelClient *rcc,
+                                                     SpiceMarshaller *m,
+                                                     PipeItem *item)
 {
     SpiceMsgMainAgentDisconnect disconnect;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_AGENT_DISCONNECTED, item);
     disconnect.error_code = SPICE_LINK_ERR_OK;
     spice_marshall_msg_main_agent_disconnected(m, &disconnect);
 }
@@ -425,11 +461,13 @@ void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t num_
     red_channel_client_pipe_add_push(&mcc->base, item);
 }
 
-static void main_channel_marshall_tokens(SpiceMarshaller *m, uint32_t num_tokens)
+static void main_channel_marshall_tokens(RedChannelClient *rcc,
+                                         SpiceMarshaller *m, TokensPipeItem *item)
 {
     SpiceMsgMainAgentTokens tokens;
 
-    tokens.num_tokens = num_tokens;
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_AGENT_TOKEN, &item->base);
+    tokens.num_tokens = item->tokens;
     spice_marshall_msg_main_agent_token(m, &tokens);
 }
 
@@ -442,25 +480,29 @@ void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* data,
     red_channel_client_pipe_add_push(&mcc->base, item);
 }
 
-static void main_channel_marshall_agent_data(SpiceMarshaller *m,
-                                  AgentDataPipeItem *item)
+static void main_channel_marshall_agent_data(RedChannelClient *rcc,
+                                             SpiceMarshaller *m,
+                                             AgentDataPipeItem *item)
 {
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_AGENT_DATA, &item->base);
     spice_marshaller_add_ref(m, item->data, item->len);
 }
 
 static void main_channel_push_migrate_data_item(MainChannel *main_chan)
 {
-    red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MIGRATE_DATA);
+    red_channel_pipes_add_type(&main_chan->base, PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
 }
 
-static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int serial, int ping_id)
+static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
+                                                    SpiceMarshaller *m, PipeItem *item)
 {
     MainMigrateData *data = (MainMigrateData *)
                             spice_marshaller_reserve_space(m, sizeof(MainMigrateData));
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
     reds_marshall_migrate_data_item(m, data); // TODO: from reds split. ugly separation.
-    data->serial = serial;
-    data->ping_id = ping_id;
+    data->serial = red_channel_client_get_message_serial(rcc);
+    data->ping_id = SPICE_CONTAINEROF(rcc, MainChannelClient, base)->ping_id;
 }
 
 static uint64_t main_channel_handle_migrate_data_get_serial(RedChannelClient *base,
@@ -503,11 +545,14 @@ void main_channel_push_init(MainChannelClient *mcc,
     red_channel_client_pipe_add_push(&mcc->base, item);
 }
 
-static void main_channel_marshall_init(SpiceMarshaller *m,
+static void main_channel_marshall_init(RedChannelClient *rcc,
+                                       SpiceMarshaller *m,
                                        InitPipeItem *item)
 {
     SpiceMsgMainInit init; // TODO - remove this copy, make InitPipeItem reuse SpiceMsgMainInit
 
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_INIT, &item->base);
     init.session_id = item->connection_id;
     init.display_channels_hint = item->display_channels_hint;
     init.current_mouse_mode = item->current_mouse_mode;
@@ -565,10 +610,12 @@ static uint64_t get_time_stamp(void)
     return time_space.tv_sec * 1000 * 1000 * 1000 + time_space.tv_nsec;
 }
 
-static void main_channel_marshall_notify(SpiceMarshaller *m, NotifyPipeItem *item)
+static void main_channel_marshall_notify(RedChannelClient *rcc,
+                                         SpiceMarshaller *m, NotifyPipeItem *item)
 {
     SpiceMsgNotify notify;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_NOTIFY, &item->base);
     notify.time_stamp = get_time_stamp(); // TODO - move to main_new_notify_item
     notify.severity = SPICE_NOTIFY_SEVERITY_WARN;
     notify.visibilty = SPICE_NOTIFY_VISIBILITY_HIGH;
@@ -595,41 +642,32 @@ static void main_channel_fill_migrate_dst_info(MainChannel *main_channel,
     }
 }
 
-static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelClient *rcc)
+static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelClient *rcc,
+                                                PipeItem *item)
 {
     SpiceMsgMainMigrationBegin migrate;
     MainChannel *main_ch;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN, item);
     main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
     main_channel_fill_migrate_dst_info(main_ch, &migrate.dst_info);
     spice_marshall_msg_main_migrate_begin(m, &migrate);
 }
 
 static void main_channel_marshall_migrate_begin_seamless(SpiceMarshaller *m,
-                                                         RedChannelClient *rcc)
+                                                         RedChannelClient *rcc,
+                                                         PipeItem *item)
 {
     SpiceMsgMainMigrateBeginSeamless migrate_seamless;
     MainChannel *main_ch;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS, item);
     main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
     main_channel_fill_migrate_dst_info(main_ch, &migrate_seamless.dst_info);
     migrate_seamless.src_mig_version = SPICE_MIGRATION_PROTOCOL_VERSION;
     spice_marshall_msg_main_migrate_begin_seamless(m, &migrate_seamless);
 }
 
-void main_channel_push_migrate(MainChannel *main_chan)
-{
-    red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MIGRATE);
-}
-
-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(m, &migrate);
-}
-
 void main_channel_push_multi_media_time(MainChannel *main_chan, int time)
 {
     MultiMediaTimePipeItem info = {
@@ -656,15 +694,17 @@ static void main_channel_fill_mig_target(MainChannel *main_channel, RedsMigSpice
 void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_target)
 {
     main_channel_fill_mig_target(main_chan, mig_target);
-    red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST);
+    red_channel_pipes_add_type(&main_chan->base, PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
 }
 
-static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelClient *rcc)
+static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelClient *rcc,
+                                                 PipeItem *item)
 {
     SpiceMsgMainMigrationSwitchHost migrate;
     MainChannel *main_ch;
 
     spice_printerr("");
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item);
     main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
     migrate.port = main_ch->mig_target.port;
     migrate.sport = main_ch->mig_target.sport;
@@ -680,11 +720,13 @@ static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelC
     spice_marshall_msg_main_migrate_switch_host(m, &migrate);
 }
 
-static void main_channel_marshall_multi_media_time(SpiceMarshaller *m,
-    MultiMediaTimePipeItem *item)
+static void main_channel_marshall_multi_media_time(RedChannelClient *rcc,
+                                                   SpiceMarshaller *m,
+                                                   MultiMediaTimePipeItem *item)
 {
     SpiceMsgMainMultiMediaTime time_mes;
 
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MULTI_MEDIA_TIME, &item->base);
     time_mes.time = item->time;
     spice_marshall_msg_main_multi_media_time(m, &time_mes);
 }
@@ -701,72 +743,68 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
         main_channel_release_pipe_item(rcc, base, FALSE);
         return;
     }
-    red_channel_client_init_send_data(rcc, base->type, base);
+
     switch (base->type) {
-        case SPICE_MSG_MAIN_CHANNELS_LIST:
-            main_channel_marshall_channels(m);
+        case PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST:
+            main_channel_marshall_channels(rcc, m, base);
             break;
-        case SPICE_MSG_PING:
-            main_channel_marshall_ping(m,
-                SPICE_CONTAINEROF(base, PingPipeItem, base)->size, ++(mcc->ping_id));
+        case PIPE_ITEM_TYPE_MAIN_PING:
+            main_channel_marshall_ping(rcc, m,
+                SPICE_CONTAINEROF(base, PingPipeItem, base));
             break;
-        case SPICE_MSG_MAIN_MOUSE_MODE:
+        case PIPE_ITEM_TYPE_MAIN_MOUSE_MODE:
             {
                 MouseModePipeItem *item =
                     SPICE_CONTAINEROF(base, MouseModePipeItem, base);
-                main_channel_marshall_mouse_mode(m,
-                    item->current_mode, item->is_client_mouse_allowed);
+                main_channel_marshall_mouse_mode(rcc, m, item);
                 break;
             }
-        case SPICE_MSG_MAIN_AGENT_DISCONNECTED:
-            main_channel_marshall_agent_disconnected(m);
+        case PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED:
+            main_channel_marshall_agent_disconnected(rcc, m, base);
             break;
-        case SPICE_MSG_MAIN_AGENT_TOKEN:
-            main_channel_marshall_tokens(m,
-                SPICE_CONTAINEROF(base, TokensPipeItem, base)->tokens);
+        case PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN:
+            main_channel_marshall_tokens(rcc, m,
+                SPICE_CONTAINEROF(base, TokensPipeItem, base));
             break;
-        case SPICE_MSG_MAIN_AGENT_DATA:
-            main_channel_marshall_agent_data(m,
+        case PIPE_ITEM_TYPE_MAIN_AGENT_DATA:
+            main_channel_marshall_agent_data(rcc, m,
                 SPICE_CONTAINEROF(base, AgentDataPipeItem, base));
             break;
-        case SPICE_MSG_MIGRATE_DATA:
-            main_channel_marshall_migrate_data_item(m,
-                red_channel_client_get_message_serial(rcc),
-                mcc->ping_id);
+        case PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA:
+            main_channel_marshall_migrate_data_item(rcc, m, base);
             break;
-        case SPICE_MSG_MAIN_INIT:
+        case PIPE_ITEM_TYPE_MAIN_INIT:
             mcc->init_sent = TRUE;
-            main_channel_marshall_init(m,
+            main_channel_marshall_init(rcc, m,
                 SPICE_CONTAINEROF(base, InitPipeItem, base));
             break;
-        case SPICE_MSG_NOTIFY:
-            main_channel_marshall_notify(m,
+        case PIPE_ITEM_TYPE_MAIN_NOTIFY:
+            main_channel_marshall_notify(rcc, m,
                 SPICE_CONTAINEROF(base, NotifyPipeItem, base));
             break;
-        case SPICE_MSG_MIGRATE:
-            main_channel_marshall_migrate(m);
-            break;
-        case SPICE_MSG_MAIN_MIGRATE_BEGIN:
-            main_channel_marshall_migrate_begin(m, rcc);
+        case PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN:
+            main_channel_marshall_migrate_begin(m, rcc, base);
             break;
-        case SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS:
-            main_channel_marshall_migrate_begin_seamless(m, rcc);
+        case PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS:
+            main_channel_marshall_migrate_begin_seamless(m, rcc, base);
             break;
-        case SPICE_MSG_MAIN_MULTI_MEDIA_TIME:
-            main_channel_marshall_multi_media_time(m,
+        case PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME:
+            main_channel_marshall_multi_media_time(rcc, m,
                 SPICE_CONTAINEROF(base, MultiMediaTimePipeItem, base));
             break;
-        case SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST:
-            main_channel_marshall_migrate_switch(m, rcc);
+        case PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST:
+            main_channel_marshall_migrate_switch(m, rcc, base);
             break;
-        case SPICE_MSG_MAIN_NAME:
+        case PIPE_ITEM_TYPE_MAIN_NAME:
+            red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_NAME, base);
             spice_marshall_msg_main_name(m, &SPICE_CONTAINEROF(base, NamePipeItem, base)->msg);
             break;
-        case SPICE_MSG_MAIN_UUID:
+        case PIPE_ITEM_TYPE_MAIN_UUID:
+            red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_UUID, base);
             spice_marshall_msg_main_uuid(m, &SPICE_CONTAINEROF(base, UuidPipeItem, base)->msg);
             break;
-        case SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS:
-            main_channel_marshall_agent_connected(m);
+        case PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS:
+            main_channel_marshall_agent_connected(m, rcc, base);
             break;
         default:
             break;
@@ -778,7 +816,7 @@ static void main_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *base, int item_pushed)
 {
     switch (base->type) {
-        case SPICE_MSG_MAIN_AGENT_DATA: {
+        case PIPE_ITEM_TYPE_MAIN_AGENT_DATA: {
                 AgentDataPipeItem *data = (AgentDataPipeItem *)base;
 
                 data->free_data(data->data, data->opaque);
@@ -808,7 +846,7 @@ static void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
     } else {
         if (success) {
             spice_printerr("client %p MIGRATE_CANCEL", mcc->base.client);
-            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_CANCEL);
+            red_channel_client_pipe_add_empty_msg(&mcc->base, SPICE_MSG_MAIN_MIGRATE_CANCEL);
         }
     }
 }
@@ -817,11 +855,11 @@ void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
                                                         uint32_t src_version)
 {
     if (reds_on_migrate_dst_set_seamless(mcc, src_version)) {
-        red_channel_client_pipe_add_type(&mcc->base,
-                                         SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
+        red_channel_client_pipe_add_empty_msg(&mcc->base,
+                                             SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
     } else {
-        red_channel_client_pipe_add_type(&mcc->base,
-                                         SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK);
+        red_channel_client_pipe_add_empty_msg(&mcc->base,
+                                              SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK);
     }
 }
 
@@ -845,9 +883,10 @@ void main_channel_migrate_dst_complete(MainChannelClient *mcc)
     if (mcc->mig_wait_prev_complete) {
         if (mcc->mig_wait_prev_try_seamless) {
             spice_assert(mcc->base.channel->clients_num == 1);
-            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS);
+            red_channel_client_pipe_add_type(&mcc->base,
+                                             PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS);
         } else {
-            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
+            red_channel_client_pipe_add_type(&mcc->base, PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN);
         }
         mcc->mig_wait_connect = TRUE;
         mcc->mig_wait_prev_complete = FALSE;
@@ -1171,7 +1210,8 @@ static int main_channel_connect_semi_seamless(MainChannel *main_channel)
                 mcc->mig_wait_prev_complete = TRUE;
                 mcc->mig_wait_prev_try_seamless = FALSE;
             } else {
-                red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
+                red_channel_client_pipe_add_type(&mcc->base,
+                                                 PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN);
                 mcc->mig_wait_connect = TRUE;
             }
             mcc->mig_connect_ok = FALSE;
@@ -1197,7 +1237,8 @@ static int main_channel_connect_seamless(MainChannel *main_channel)
            mcc->mig_wait_prev_complete = TRUE;
            mcc->mig_wait_prev_try_seamless = TRUE;
         } else {
-            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS);
+            red_channel_client_pipe_add_type(&mcc->base,
+                                             PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS);
             mcc->mig_wait_connect = TRUE;
         }
         mcc->mig_connect_ok = FALSE;
@@ -1275,16 +1316,16 @@ int main_channel_migrate_src_complete(MainChannel *main_chan, int success)
         if (semi_seamless_support && mcc->mig_connect_ok) {
             if (success) {
                 spice_printerr("client %p MIGRATE_END", mcc->base.client);
-                red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_END);
+                red_channel_client_pipe_add_empty_msg(&mcc->base, SPICE_MSG_MAIN_MIGRATE_END);
                 semi_seamless_count++;
             } else {
                 spice_printerr("client %p MIGRATE_CANCEL", mcc->base.client);
-                red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_CANCEL);
+                red_channel_client_pipe_add_empty_msg(&mcc->base, SPICE_MSG_MAIN_MIGRATE_CANCEL);
             }
         } else {
             if (success) {
                 spice_printerr("client %p SWITCH_HOST", mcc->base.client);
-                red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST);
+                red_channel_client_pipe_add_type(&mcc->base, PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
             }
         }
         mcc->mig_connect_ok = FALSE;
diff --git a/server/main_channel.h b/server/main_channel.h
index 8cfe62b..cc73104 100644
--- a/server/main_channel.h
+++ b/server/main_channel.h
@@ -82,7 +82,6 @@ void main_channel_push_init(MainChannelClient *mcc, int display_channels_hint,
     int current_mouse_mode, int is_client_mouse_allowed, int multi_media_time,
     int ram_hint);
 void main_channel_push_notify(MainChannel *main_chan, uint8_t *mess, const int mess_len);
-void main_channel_push_migrate(MainChannel *main_chan);
 void main_channel_push_multi_media_time(MainChannel *main_chan, int time);
 int main_channel_getsockname(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen);
 int main_channel_getpeername(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen);
commit 157d459d4265e2141095fedc58469545bb0fc2f0
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 14:16:05 2012 +0300

    red_channel: introduce PIPE_ITEM_TYPE_EMPTY_MSG
    
    The pipe item is used for sending messages that don't have body.

diff --git a/server/red_channel.c b/server/red_channel.c
index 65ef2da..16335a3 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -38,6 +38,11 @@
 #include "reds.h"
 #include "main_dispatcher.h"
 
+typedef struct EmptyMsgPipeItem {
+    PipeItem base;
+    int msg;
+} EmptyMsgPipeItem;
+
 static void red_channel_client_event(int fd, int event, void *data);
 static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
 static void red_client_remove_channel(RedChannelClient *rcc);
@@ -467,6 +472,15 @@ static void red_channel_client_send_migrate(RedChannelClient *rcc)
     red_channel_client_begin_send_message(rcc);
 }
 
+
+static void red_channel_client_send_empty_msg(RedChannelClient *rcc, PipeItem *base)
+{
+    EmptyMsgPipeItem *msg_pipe_item = SPICE_CONTAINEROF(base, EmptyMsgPipeItem, base);
+
+    red_channel_client_init_send_data(rcc, msg_pipe_item->msg, NULL);
+    red_channel_client_begin_send_message(rcc);
+}
+
 static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
 {
     int handled = TRUE;
@@ -482,6 +496,10 @@ static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
             red_channel_client_send_migrate(rcc);
             free(item);
             break;
+        case PIPE_ITEM_TYPE_EMPTY_MSG:
+            red_channel_client_send_empty_msg(rcc, item);
+            free(item);
+            break;
         default:
             handled = FALSE;
     }
@@ -1329,6 +1347,27 @@ void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
     }
 }
 
+void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type)
+{
+    EmptyMsgPipeItem *item = spice_new(EmptyMsgPipeItem, 1);
+
+    red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_EMPTY_MSG);
+    item->msg = msg_type;
+    red_channel_client_pipe_add(rcc, &item->base);
+    red_channel_client_push(rcc);
+}
+
+void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type)
+{
+    RingItem *link;
+
+    RING_FOREACH(link, &channel->clients) {
+        red_channel_client_pipe_add_empty_msg(
+            SPICE_CONTAINEROF(link, RedChannelClient, channel_link),
+            msg_type);
+    }
+}
+
 int red_channel_client_is_connected(RedChannelClient *rcc)
 {
     return rcc->stream != NULL;
diff --git a/server/red_channel.h b/server/red_channel.h
index 8c8e1c8..de72fff 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -143,6 +143,7 @@ typedef struct MainChannelClient MainChannelClient;
 enum {
     PIPE_ITEM_TYPE_SET_ACK=1,
     PIPE_ITEM_TYPE_MIGRATE,
+    PIPE_ITEM_TYPE_EMPTY_MSG,
 
     PIPE_ITEM_TYPE_CHANNEL_BASE=101,
 };
@@ -438,6 +439,9 @@ void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item);
 void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type);
 void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type);
 
+void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type);
+void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type);
+
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
 void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
 void red_channel_client_push_set_ack(RedChannelClient *rcc);
commit fdab42cc41e1fcee34de564e80e16890c5d86882
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 13:32:08 2012 +0300

    smartcard: restore state after migration from migration data

diff --git a/server/smartcard.c b/server/smartcard.c
index 15f5324..0ec8a13 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -112,6 +112,17 @@ static SmartCardDeviceState *smartcard_device_state_new(SpiceCharDeviceInstance
 static void smartcard_device_state_free(SmartCardDeviceState* st);
 static void smartcard_init(void);
 
+static void smartcard_read_buf_prepare(SmartCardDeviceState *state, VSCMsgHeader *vheader)
+{
+    uint32_t msg_len;
+
+    msg_len = ntohl(vheader->length);
+    if (msg_len > state->buf_size) {
+        state->buf_size = MAX(state->buf_size * 2, msg_len + sizeof(VSCMsgHeader));
+        state->buf = spice_realloc(state->buf, state->buf_size);
+    }
+}
+
 SpiceCharDeviceMsgToClient *smartcard_read_msg_from_device(SpiceCharDeviceInstance *sin,
                                                            void *opaque)
 {
@@ -130,12 +141,8 @@ SpiceCharDeviceMsgToClient *smartcard_read_msg_from_device(SpiceCharDeviceInstan
         if (state->buf_used < sizeof(VSCMsgHeader)) {
             continue;
         }
+        smartcard_read_buf_prepare(state, vheader);
         actual_length = ntohl(vheader->length);
-        if (actual_length > state->buf_size) {
-            state->buf_size = MAX(state->buf_size*2, actual_length + sizeof(VSCMsgHeader));
-            state->buf = spice_realloc(state->buf, state->buf_size);
-            spice_assert(state->buf != NULL);
-        }
         if (state->buf_used - sizeof(VSCMsgHeader) < actual_length) {
             continue;
         }
@@ -663,6 +670,65 @@ static int smartcard_channel_client_handle_migrate_flush_mark(RedChannelClient *
     return TRUE;
 }
 
+static void smartcard_device_state_restore_partial_read(SmartCardDeviceState *state,
+                                                        SpiceMigrateDataSmartcard *mig_data)
+{
+    uint8_t *read_data;
+
+    spice_debug("read_size  %u", mig_data->read_size);
+    read_data = (uint8_t *)mig_data + mig_data->read_data_ptr - sizeof(SpiceMigrateDataHeader);
+    if (mig_data->read_size < sizeof(VSCMsgHeader)) {
+        spice_assert(state->buf_size >= mig_data->read_size);
+    } else {
+        smartcard_read_buf_prepare(state, (VSCMsgHeader *)read_data);
+    }
+    memcpy(state->buf, read_data, mig_data->read_size);
+    state->buf_used = mig_data->read_size;
+    state->buf_pos = state->buf + mig_data->read_size;
+}
+
+static int smartcard_channel_client_handle_migrate_data(RedChannelClient *rcc,
+                                                        uint32_t size, void *message)
+{
+    SmartCardChannelClient *scc;
+    SpiceMigrateDataHeader *header;
+    SpiceMigrateDataSmartcard *mig_data;
+
+    scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
+    header = (SpiceMigrateDataHeader *)message;
+    mig_data = (SpiceMigrateDataSmartcard *)(header + 1);
+    if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataSmartcard)) {
+        spice_error("bad message size");
+        return FALSE;
+    }
+    if (!migration_protocol_validate_header(header,
+                                            SPICE_MIGRATE_DATA_SMARTCARD_MAGIC,
+                                            SPICE_MIGRATE_DATA_SMARTCARD_VERSION)) {
+        spice_error("bad header");
+        return FALSE;
+    }
+
+    if (!mig_data->base.connected) { /* client wasn't attached to a smartcard */
+        return TRUE;
+    }
+
+    if (!scc->smartcard_state) {
+        SpiceCharDeviceInstance *char_device = smartcard_readers_get_unattached();
+
+        if (!char_device) {
+            spice_warning("no unattached device available");
+            return TRUE;
+        } else {
+            smartcard_char_device_attach_client(char_device, scc);
+        }
+    }
+    spice_debug("reader added %d partial read_size %u", mig_data->reader_added, mig_data->read_size);
+    scc->smartcard_state->reader_added = mig_data->reader_added;
+
+    smartcard_device_state_restore_partial_read(scc->smartcard_state, mig_data);
+    return spice_char_device_state_restore(scc->smartcard_state->chardev_st, &mig_data->base);
+}
+
 static int smartcard_channel_handle_message(RedChannelClient *rcc,
                                             uint16_t type,
                                             uint32_t size,
@@ -672,7 +738,8 @@ static int smartcard_channel_handle_message(RedChannelClient *rcc,
     SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
 
     if (type != SPICE_MSGC_SMARTCARD_DATA) {
-        /* handle ack's, spicy sends them while spicec does not */
+        /* Handles seamless migration protocol. Also handles ack's,
+         * spicy sends them while spicec does not */
         return red_channel_client_handle_message(rcc, size, type, msg);
     }
 
@@ -702,7 +769,7 @@ static int smartcard_channel_handle_message(RedChannelClient *rcc,
 
     /* todo: fix */
     if (vheader->reader_id >= g_smartcard_readers.num) {
-        spice_printerr("ERROR: received message for non existent reader: %d, %d, %d", vheader->reader_id,
+        spice_printerr("ERROR: received message for non existing reader: %d, %d, %d", vheader->reader_id,
             vheader->type, vheader->length);
         return FALSE;
     }
@@ -763,6 +830,7 @@ static void smartcard_init(void)
     channel_cbs.alloc_recv_buf = smartcard_channel_alloc_msg_rcv_buf;
     channel_cbs.release_recv_buf = smartcard_channel_release_msg_rcv_buf;
     channel_cbs.handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
+    channel_cbs.handle_migrate_data = smartcard_channel_client_handle_migrate_data;
 
     g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
                                              core, SPICE_CHANNEL_SMARTCARD, 0,
commit e07dd381ab8843b94f6ba958adc7a6a970d11b1f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 13:07:56 2012 +0300

    smartcard migration: send migration data

diff --git a/server/smartcard.c b/server/smartcard.c
index bc1c6e4..15f5324 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -26,6 +26,7 @@
 #include "char_device.h"
 #include "red_channel.h"
 #include "smartcard.h"
+#include "migration_protocol.h"
 
 /*
  * TODO: the code doesn't really support multiple readers.
@@ -67,7 +68,8 @@ struct SmartCardDeviceState {
 
 enum {
     PIPE_ITEM_TYPE_ERROR = PIPE_ITEM_TYPE_CHANNEL_BASE,
-    PIPE_ITEM_TYPE_MSG,
+    PIPE_ITEM_TYPE_SMARTCARD_DATA,
+    PIPE_ITEM_TYPE_SMARTCARD_MIGRATE_DATA,
 };
 
 typedef struct ErrorItem {
@@ -449,7 +451,6 @@ static void smartcard_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *
     if (vheader->length > 0) {
         spice_marshaller_add_ref(m, (uint8_t*)(vheader+1), vheader->length);
     }
-    red_channel_client_begin_send_message(rcc);
 }
 
 static void smartcard_channel_send_error(
@@ -468,6 +469,35 @@ static void smartcard_channel_send_msg(RedChannelClient *rcc,
     smartcard_channel_send_data(rcc, m, item, msg_item->vheader);
 }
 
+static void smartcard_channel_send_migrate_data(RedChannelClient *rcc,
+                                                SpiceMarshaller *m, PipeItem *item)
+{
+    SmartCardChannelClient *scc;
+    SmartCardDeviceState *state;
+    SpiceMarshaller *m2;
+
+    scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
+    state = scc->smartcard_state;
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SMARTCARD_MAGIC);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SMARTCARD_VERSION);
+
+    if (!state) {
+        spice_char_device_state_migrate_data_marshall_empty(m);
+        spice_marshaller_add_uint8(m, 0);
+        spice_marshaller_add_uint32(m, 0);
+        spice_marshaller_add_uint32(m, 0);
+        spice_debug("null char dev state");
+    } else {
+        spice_char_device_state_migrate_data_marshall(state->chardev_st, m);
+        spice_marshaller_add_uint8(m, state->reader_added);
+        spice_marshaller_add_uint32(m, state->buf_used);
+        m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
+        spice_marshaller_add_ref(m2, state->buf, state->buf_used);
+        spice_debug("reader added %d partial read size %u", state->reader_added, state->buf_used);
+    }
+}
+
 static void smartcard_channel_send_item(RedChannelClient *rcc, PipeItem *item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
@@ -476,15 +506,24 @@ static void smartcard_channel_send_item(RedChannelClient *rcc, PipeItem *item)
     case PIPE_ITEM_TYPE_ERROR:
         smartcard_channel_send_error(rcc, m, item);
         break;
-    case PIPE_ITEM_TYPE_MSG:
+    case PIPE_ITEM_TYPE_SMARTCARD_DATA:
         smartcard_channel_send_msg(rcc, m, item);
+        break;
+    case PIPE_ITEM_TYPE_SMARTCARD_MIGRATE_DATA:
+        smartcard_channel_send_migrate_data(rcc, m, item);
+        break;
+    default:
+        spice_error("bad pipe item %d", item->type);
+        free(item);
+        return;
     }
+    red_channel_client_begin_send_message(rcc);
 }
 
 static void smartcard_channel_release_pipe_item(RedChannelClient *rcc,
                                       PipeItem *item, int item_pushed)
 {
-    if (item->type == PIPE_ITEM_TYPE_MSG) {
+    if (item->type == PIPE_ITEM_TYPE_SMARTCARD_DATA) {
         smartcard_unref_vsc_msg_item((MsgItem *)item);
     } else {
         free(item);
@@ -531,7 +570,7 @@ static MsgItem *smartcard_get_vsc_msg_item(RedChannelClient *rcc, VSCMsgHeader *
     MsgItem *msg_item = spice_new0(MsgItem, 1);
 
     red_channel_pipe_item_init(rcc->channel, &msg_item->base,
-                               PIPE_ITEM_TYPE_MSG);
+                               PIPE_ITEM_TYPE_SMARTCARD_DATA);
     msg_item->refs = 1;
     msg_item->vheader = vheader;
     return msg_item;
@@ -618,6 +657,12 @@ static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_
     }
 }
 
+static int smartcard_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
+{
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_SMARTCARD_MIGRATE_DATA);
+    return TRUE;
+}
+
 static int smartcard_channel_handle_message(RedChannelClient *rcc,
                                             uint16_t type,
                                             uint32_t size,
@@ -717,6 +762,7 @@ static void smartcard_init(void)
     channel_cbs.release_item = smartcard_channel_release_pipe_item;
     channel_cbs.alloc_recv_buf = smartcard_channel_alloc_msg_rcv_buf;
     channel_cbs.release_recv_buf = smartcard_channel_release_msg_rcv_buf;
+    channel_cbs.handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
 
     g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
                                              core, SPICE_CHANNEL_SMARTCARD, 0,
commit 6ff73836cfe026877a27b07fb133e5d07c92811a
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 13:10:45 2012 +0300

    migration_protocol: add migration data for smartcard

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index 127ab0a..67ad1bf 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -62,6 +62,20 @@ typedef struct __attribute__ ((__packed__)) SpiceMigrateDataSpiceVmc {
     SpiceMigrateDataCharDevice base;
 } SpiceMigrateDataSpiceVmc;
 
+/* *********
+ * smartcard
+ * *********/
+
+#define SPICE_MIGRATE_DATA_SMARTCARD_VERSION 1 /* NOTE: increase version when CHAR_DEVICE_VERSION
+                                                  is increased */
+#define SPICE_MIGRATE_DATA_SMARTCARD_MAGIC (*(uint32_t *)"SCMD")
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataSmartcard {
+    SpiceMigrateDataCharDevice base;
+    uint8_t reader_added;
+    uint32_t read_size; /* partial data read from dev */
+    uint32_t read_data_ptr;
+} SpiceMigrateDataSmartcard;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit 2670fb9765e155d7930c045414c9915a80076159
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 12:59:38 2012 +0300

    smartcard: send MSG_MIGRATE upon vm migration completion
    
    The above is the default behaviour for red_channel_client, if
    client_cbs.migrate is not registered as part of red_channel_register_client_cbs

diff --git a/server/smartcard.c b/server/smartcard.c
index bbd6826..bc1c6e4 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -700,10 +700,6 @@ static void smartcard_connect_client(RedChannel *channel, RedClient *client,
     }
 }
 
-static void smartcard_migrate(RedChannelClient *rcc)
-{
-}
-
 SmartCardChannel *g_smartcard_channel;
 
 static void smartcard_init(void)
@@ -735,7 +731,6 @@ static void smartcard_init(void)
     }
 
     client_cbs.connect = smartcard_connect_client;
-    client_cbs.migrate = smartcard_migrate;
     red_channel_register_client_cbs(&g_smartcard_channel->base, &client_cbs);
 
     reds_register_channel(&g_smartcard_channel->base);
commit 6c9d1330afe1159a0acf4d9678ee77b41918dc5f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 12:34:47 2012 +0300

    smartcard: fix PIPE_ITEMs enum indexing
    
    The enum should start from PIPE_ITEM_TYPE_CHANNEL_BASE, otherwise,
    PIPE_ITEM_TYPE_ERROR is handled like PIPE_ITEM_TYPE_SET_ACK.

diff --git a/server/smartcard.c b/server/smartcard.c
index 44a3fae..bbd6826 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -66,7 +66,7 @@ struct SmartCardDeviceState {
 };
 
 enum {
-    PIPE_ITEM_TYPE_ERROR=1,
+    PIPE_ITEM_TYPE_ERROR = PIPE_ITEM_TYPE_CHANNEL_BASE,
     PIPE_ITEM_TYPE_MSG,
 };
 
commit b3c16d2ae7b392a72afe00b7c6e180c966340cf7
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 11:46:05 2012 +0300

    smartcard: change the timing of attaching a client to SpiceCharDeviceState
    
    Attach/detach a client to a SpiceCharDeviceState upon its
    connection/disconnection, instead of upon reader_add/remove messages.
    When the client is removed from a SpiceCharDeviceState, all the
    messages from this client are removed from the device write queue.
    This shouldn't happen when we only receive reader_remove and the
    client is still connected.

diff --git a/server/smartcard.c b/server/smartcard.c
index de86185..44a3fae 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -55,7 +55,6 @@ typedef struct SmartCardChannelClient {
 struct SmartCardDeviceState {
     SpiceCharDeviceState *chardev_st;
     uint32_t             reader_id;
-    uint32_t             attached;
     /* read_from_device buffer */
     uint8_t             *buf;
     uint32_t             buf_size;
@@ -63,6 +62,7 @@ struct SmartCardDeviceState {
     uint32_t             buf_used;
 
     SmartCardChannelClient    *scc; // client providing the remote card
+    int                  reader_added; // has reader_add been sent to the device
 };
 
 enum {
@@ -100,7 +100,7 @@ static struct Readers {
 static SpiceCharDeviceInstance* smartcard_readers_get_unattached(void);
 static SpiceCharDeviceInstance* smartcard_readers_get(uint32_t reader_id);
 static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *sin);
-static void smartcard_char_device_attach(
+static void smartcard_char_device_attach_client(
     SpiceCharDeviceInstance *char_device, SmartCardChannelClient *scc);
 static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_buf);
 
@@ -244,7 +244,7 @@ static SpiceCharDeviceInstance *smartcard_readers_get_unattached(void)
 
     for (i = 0; i < g_smartcard_readers.num; ++i) {
         state = spice_char_device_state_opaque_get(g_smartcard_readers.sin[i]->st);
-        if (!state->attached) {
+        if (!state->scc) {
             return g_smartcard_readers.sin[i];
         }
     }
@@ -270,7 +270,7 @@ static SmartCardDeviceState *smartcard_device_state_new(SpiceCharDeviceInstance
                                                     &chardev_cbs,
                                                     st);
     st->reader_id = VSCARD_UNDEFINED_READER_ID;
-    st->attached = FALSE;
+    st->reader_added = FALSE;
     st->buf_size = APDUBufSize + sizeof(VSCMsgHeader);
     st->buf = spice_malloc(st->buf_size);
     st->buf_pos = st->buf;
@@ -308,18 +308,30 @@ SpiceCharDeviceState *smartcard_device_connect(SpiceCharDeviceInstance *char_dev
     return st->chardev_st;
 }
 
-static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
-                                         SmartCardChannelClient *scc)
+static void smartcard_char_device_notify_reader_add(SmartCardDeviceState *st)
 {
-    SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st);
     SpiceCharDeviceWriteBuffer *write_buf;
     VSCMsgHeader *vheader;
 
-    spice_assert(!scc->smartcard_state);
-    if (st->attached == TRUE) {
+    write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
+    if (!write_buf) {
+        spice_error("failed to allocate write buffer");
         return;
     }
-    st->attached = TRUE;
+    st->reader_added = TRUE;
+    vheader = (VSCMsgHeader *)write_buf->buf;
+    vheader->type = VSC_ReaderAdd;
+    vheader->reader_id = st->reader_id;
+    vheader->length = 0;
+    smartcard_channel_write_to_reader(write_buf);
+}
+
+static void smartcard_char_device_attach_client(SpiceCharDeviceInstance *char_device,
+                                                SmartCardChannelClient *scc)
+{
+    SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st);
+
+    spice_assert(!scc->smartcard_state && !st->scc);
     st->scc = scc;
     spice_char_device_client_add(st->chardev_st,
                                  scc->base.client,
@@ -329,13 +341,25 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
                                  ~0,
                                  red_channel_client_waits_for_migrate_data(&scc->base));
     scc->smartcard_state = st;
+}
+
+static void smartcard_char_device_notify_reader_remove(SmartCardDeviceState *st)
+{
+    SpiceCharDeviceWriteBuffer *write_buf;
+    VSCMsgHeader *vheader;
+
+    if (!st->reader_added) {
+        spice_debug("reader add was never sent to the device");
+        return;
+    }
     write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
     if (!write_buf) {
         spice_error("failed to allocate write buffer");
         return;
     }
+    st->reader_added = FALSE;
     vheader = (VSCMsgHeader *)write_buf->buf;
-    vheader->type = VSC_ReaderAdd;
+    vheader->type = VSC_ReaderRemove;
     vheader->reader_id = st->reader_id;
     vheader->length = 0;
     smartcard_channel_write_to_reader(write_buf);
@@ -344,8 +368,6 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
 static void smartcard_char_device_detach_client(SmartCardChannelClient *scc)
 {
     SmartCardDeviceState *st;
-    SpiceCharDeviceWriteBuffer *write_buf;
-    VSCMsgHeader *vheader;
 
     if (!scc->smartcard_state) {
         return;
@@ -354,18 +376,7 @@ static void smartcard_char_device_detach_client(SmartCardChannelClient *scc)
     spice_assert(st->scc == scc);
     spice_char_device_client_remove(st->chardev_st, scc->base.client);
     scc->smartcard_state = NULL;
-    st->attached = FALSE;
     st->scc = NULL;
-    write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
-    if (!write_buf) {
-        spice_error("failed to allocate write buffer");
-        return;
-    }
-    vheader = (VSCMsgHeader *)write_buf->buf;
-    vheader->type = VSC_ReaderRemove;
-    vheader->reader_id = st->reader_id;
-    vheader->length = 0;
-    smartcard_channel_write_to_reader(write_buf);
 }
 
 static int smartcard_channel_client_config_socket(RedChannelClient *rcc)
@@ -482,7 +493,14 @@ static void smartcard_channel_release_pipe_item(RedChannelClient *rcc,
 
 static void smartcard_channel_on_disconnect(RedChannelClient *rcc)
 {
-    smartcard_char_device_detach_client(SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base));
+    SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
+
+    if (scc->smartcard_state) {
+        SmartCardDeviceState *st = scc->smartcard_state;
+
+        smartcard_char_device_detach_client(scc);
+        smartcard_char_device_notify_reader_remove(st);
+    }
 }
 
 /* this is called from both device input and client input. since the device is
@@ -545,30 +563,32 @@ static void smartcard_remove_reader(SmartCardChannelClient *scc, uint32_t reader
     }
 
     state = spice_char_device_state_opaque_get(char_device->st);
-    if (state->attached == FALSE) {
+    if (state->reader_added == FALSE) {
         smartcard_push_error(&scc->base, reader_id,
             VSC_GENERAL_ERROR);
         return;
     }
     spice_assert(scc->smartcard_state == state);
-    smartcard_char_device_detach_client(scc);
+    smartcard_char_device_notify_reader_remove(state);
 }
 
 static void smartcard_add_reader(SmartCardChannelClient *scc, uint8_t *name)
 {
-    // TODO - save name somewhere
-    SpiceCharDeviceInstance *char_device =
-            smartcard_readers_get_unattached();
+    if (!scc->smartcard_state) { /* we already tried to attach a reader to the client
+                                    when it connected */
+        SpiceCharDeviceInstance *char_device = smartcard_readers_get_unattached();
 
-    if (char_device != NULL) {
-        smartcard_char_device_attach(char_device, scc);
-        // The device sends a VSC_Error message, we will let it through, no
-        // need to send our own. We already set the correct reader_id, from
-        // our SmartCardDeviceState.
-    } else {
-        smartcard_push_error(&scc->base, VSCARD_UNDEFINED_READER_ID,
-            VSC_CANNOT_ADD_MORE_READERS);
+        if (!char_device) {
+            smartcard_push_error(&scc->base, VSCARD_UNDEFINED_READER_ID,
+                                VSC_CANNOT_ADD_MORE_READERS);
+            return;
+        }
+        smartcard_char_device_attach_client(char_device, scc);
     }
+    smartcard_char_device_notify_reader_add(scc->smartcard_state);
+    // The device sends a VSC_Error message, we will let it through, no
+    // need to send our own. We already set the correct reader_id, from
+    // our SmartCardDeviceState.
 }
 
 static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_buf)
@@ -584,7 +604,7 @@ static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_
     spice_assert(vheader->reader_id <= g_smartcard_readers.num);
     sin = g_smartcard_readers.sin[vheader->reader_id];
     st = (SmartCardDeviceState *)spice_char_device_state_opaque_get(sin->st);
-    spice_assert(!st->attached || st == st->scc->smartcard_state);
+    spice_assert(!st->scc || st == st->scc->smartcard_state);
     /* protocol requires messages to be in network endianess */
     vheader->type = htonl(vheader->type);
     vheader->length = htonl(vheader->length);
@@ -593,7 +613,7 @@ static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_
     /* pushing the buffer to the write queue; It will be released
      * when it will be fully consumed by the device */
     spice_char_device_write_buffer_add(sin->st, write_buf);
-    if (st->attached && write_buf == st->scc->write_buf) {
+    if (st->scc && write_buf == st->scc->write_buf) {
         st->scc->write_buf = NULL;
     }
 }
@@ -651,11 +671,14 @@ static void smartcard_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *it
 {
 }
 
-static void smartcard_connect(RedChannel *channel, RedClient *client,
-                        RedsStream *stream, int migration,
-                        int num_common_caps, uint32_t *common_caps,
-                        int num_caps, uint32_t *caps)
+static void smartcard_connect_client(RedChannel *channel, RedClient *client,
+                                     RedsStream *stream, int migration,
+                                     int num_common_caps, uint32_t *common_caps,
+                                     int num_caps, uint32_t *caps)
 {
+    SpiceCharDeviceInstance *char_device =
+            smartcard_readers_get_unattached();
+
     SmartCardChannelClient *scc;
 
     scc = (SmartCardChannelClient *)red_channel_client_create(sizeof(SmartCardChannelClient),
@@ -664,10 +687,17 @@ static void smartcard_connect(RedChannel *channel, RedClient *client,
                                                               stream,
                                                               num_common_caps, common_caps,
                                                               num_caps, caps);
+
     if (!scc) {
         return;
     }
     red_channel_client_ack_zero_messages_window(&scc->base);
+
+    if (char_device) {
+        smartcard_char_device_attach_client(char_device, scc);
+    } else {
+        spice_printerr("char dev unavailable");
+    }
 }
 
 static void smartcard_migrate(RedChannelClient *rcc)
@@ -704,7 +734,7 @@ static void smartcard_init(void)
         spice_error("failed to allocate Smartcard Channel");
     }
 
-    client_cbs.connect = smartcard_connect;
+    client_cbs.connect = smartcard_connect_client;
     client_cbs.migrate = smartcard_migrate;
     red_channel_register_client_cbs(&g_smartcard_channel->base, &client_cbs);
 
commit 733a804c992752a9e5a15b08ddadc370a21a6b24
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 10:46:40 2012 +0300

    spicevmc migration: restore migration dest state from migration data

diff --git a/server/spicevmc.c b/server/spicevmc.c
index b14ba63..1ce3169 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -206,12 +206,39 @@ static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
     }
 }
 
+static SpiceVmcState *spicevmc_red_channel_client_get_state(RedChannelClient *rcc)
+{
+    return SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel);
+}
+
 static int spicevmc_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
 {
     red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA);
     return TRUE;
 }
 
+static int spicevmc_channel_client_handle_migrate_data(RedChannelClient *rcc,
+                                                       uint32_t size, void *message)
+{
+    SpiceMigrateDataHeader *header;
+    SpiceMigrateDataSpiceVmc *mig_data;
+    SpiceVmcState *state;
+
+    state = spicevmc_red_channel_client_get_state(rcc);
+
+    header = (SpiceMigrateDataHeader *)message;
+    mig_data = (SpiceMigrateDataSpiceVmc *)(header + 1);
+    spice_assert(size >= sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataSpiceVmc));
+
+    if (!migration_protocol_validate_header(header,
+                                            SPICE_MIGRATE_DATA_SPICEVMC_MAGIC,
+                                            SPICE_MIGRATE_DATA_SPICEVMC_VERSION)) {
+        spice_error("bad header");
+        return FALSE;
+    }
+    return spice_char_device_state_restore(state->chardev_st, &mig_data->base);
+}
+
 static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
                                                       uint16_t type,
                                                       uint32_t size,
@@ -219,8 +246,7 @@ static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
 {
     SpiceVmcState *state;
 
-    state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel);
-
+    state = spicevmc_red_channel_client_get_state(rcc);
     if (type != SPICE_MSGC_SPICEVMC_DATA) {
         return red_channel_client_handle_message(rcc, size, type, msg);
     }
@@ -383,6 +409,7 @@ SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
     channel_cbs.alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
     channel_cbs.release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
     channel_cbs.handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
+    channel_cbs.handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
 
     state = (SpiceVmcState*)red_channel_create(sizeof(SpiceVmcState),
                                    core, channel_type, id[channel_type]++,
commit ef44c5eff9b25b990434db91a055ca9229f80593
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 10:45:02 2012 +0300

    spicevmc migration: send migration data

diff --git a/server/spicevmc.c b/server/spicevmc.c
index a1092d2..b14ba63 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -31,6 +31,7 @@
 #include "char_device.h"
 #include "red_channel.h"
 #include "reds.h"
+#include "migration_protocol.h"
 
 /* todo: add flow control. i.e.,
  * (a) limit the tokens available for the client
@@ -57,6 +58,11 @@ typedef struct SpiceVmcState {
     SpiceCharDeviceWriteBuffer *recv_from_client_buf;
 } SpiceVmcState;
 
+enum {
+    PIPE_ITEM_TYPE_SPICEVMC_DATA = PIPE_ITEM_TYPE_CHANNEL_BASE,
+    PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA,
+};
+
 static SpiceVmcPipeItem *spicevmc_pipe_item_ref(SpiceVmcPipeItem *item)
 {
     item->refs++;
@@ -100,7 +106,7 @@ static SpiceCharDeviceMsgToClient *spicevmc_chardev_read_msg_from_dev(SpiceCharD
         msg_item = spice_new0(SpiceVmcPipeItem, 1);
         msg_item->refs = 1;
         red_channel_pipe_item_init(&state->channel,
-                                       &msg_item->base, 0);
+                                   &msg_item->base, PIPE_ITEM_TYPE_SPICEVMC_DATA);
     } else {
         spice_assert(state->pipe_item->buf_used == 0);
         msg_item = state->pipe_item;
@@ -200,6 +206,12 @@ static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
     }
 }
 
+static int spicevmc_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
+{
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA);
+    return TRUE;
+}
+
 static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
                                                       uint16_t type,
                                                       uint32_t size,
@@ -261,21 +273,58 @@ static void spicevmc_red_channel_hold_pipe_item(RedChannelClient *rcc,
     /* NOOP */
 }
 
-static void spicevmc_red_channel_send_item(RedChannelClient *rcc,
-    PipeItem *item)
+static void spicevmc_red_channel_send_data(RedChannelClient *rcc,
+                                           SpiceMarshaller *m,
+                                           PipeItem *item)
 {
     SpiceVmcPipeItem *i = SPICE_CONTAINEROF(item, SpiceVmcPipeItem, base);
-    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_SPICEVMC_DATA, item);
     spice_marshaller_add_ref(m, i->buf, i->buf_used);
+}
+
+static void spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc,
+                                                   SpiceMarshaller *m,
+                                                   PipeItem *item)
+{
+    SpiceVmcState *state;
+
+    state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel);
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_MAGIC);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_VERSION);
+
+    spice_char_device_state_migrate_data_marshall(state->chardev_st, m);
+}
+
+static void spicevmc_red_channel_send_item(RedChannelClient *rcc,
+                                           PipeItem *item)
+{
+    SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+
+    switch (item->type) {
+    case PIPE_ITEM_TYPE_SPICEVMC_DATA:
+        spicevmc_red_channel_send_data(rcc, m, item);
+        break;
+    case PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA:
+        spicevmc_red_channel_send_migrate_data(rcc, m, item);
+        break;
+    default:
+        spice_error("bad pipe item %d", item->type);
+        free(item);
+        return;
+    }
     red_channel_client_begin_send_message(rcc);
 }
 
 static void spicevmc_red_channel_release_pipe_item(RedChannelClient *rcc,
     PipeItem *item, int item_pushed)
 {
-    spicevmc_pipe_item_unref((SpiceVmcPipeItem *)item);
+    if (item->type == PIPE_ITEM_TYPE_SPICEVMC_DATA) {
+        spicevmc_pipe_item_unref((SpiceVmcPipeItem *)item);
+    } else {
+        free(item);
+    }
 }
 
 static void spicevmc_connect(RedChannel *channel, RedClient *client,
@@ -333,6 +382,7 @@ SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
     channel_cbs.release_item = spicevmc_red_channel_release_pipe_item;
     channel_cbs.alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
     channel_cbs.release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
+    channel_cbs.handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
 
     state = (SpiceVmcState*)red_channel_create(sizeof(SpiceVmcState),
                                    core, channel_type, id[channel_type]++,
commit 15fe69e06b6840fe7416ae8c8a4afc81fea62c21
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 10:38:15 2012 +0300

    spicevmc: send MSG_MIGRATE upon vm migration completion
    
    The above is the default behaviour for red_channel_client, if
    client_cbs.migrate is not registered as part of red_channel_register_client_cbs

diff --git a/server/spicevmc.c b/server/spicevmc.c
index 8bc23fd..a1092d2 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -317,11 +317,6 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
     }
 }
 
-static void spicevmc_migrate(RedChannelClient *rcc)
-{
-    /* NOOP */
-}
-
 SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
                                               uint8_t channel_type)
 {
@@ -349,7 +344,6 @@ SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
     red_channel_init_outgoing_messages_window(&state->channel);
 
     client_cbs.connect = spicevmc_connect;
-    client_cbs.migrate = spicevmc_migrate;
     red_channel_register_client_cbs(&state->channel, &client_cbs);
 
     char_dev_cbs.read_one_msg_from_device = spicevmc_chardev_read_msg_from_dev;
commit 1f85f1de65301927cac1a053da91e08901d81c46
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Aug 5 10:12:48 2012 +0300

    migration_protocol: add migration data for spicevmc

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index 7a1cb1d..127ab0a 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -51,6 +51,17 @@ typedef struct __attribute__ ((__packed__)) SpiceMigrateDataCharDevice {
                                 SpiceMigrateDataCharDevice - sizeof(SpiceMigrateDataHeader) */
 } SpiceMigrateDataCharDevice;
 
+/* ********
+ * spicevmc
+ * ********/
+
+#define SPICE_MIGRATE_DATA_SPICEVMC_VERSION 1 /* NOTE: increase version when CHAR_DEVICE_VERSION
+                                                 is increased */
+#define SPICE_MIGRATE_DATA_SPICEVMC_MAGIC (*(uint32_t *)"SVMD")
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataSpiceVmc {
+    SpiceMigrateDataCharDevice base;
+} SpiceMigrateDataSpiceVmc;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit 99ea64ac5a5243e56acc5f1991780d675c98ccd7
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Fri Aug 3 00:22:29 2012 +0300

    char device migration: restore state at destination from migration data

diff --git a/server/char_device.c b/server/char_device.c
index d97c6dd..b85a24d 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -873,3 +873,52 @@ void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
                 dev, *write_to_dev_size_ptr, *write_to_dev_tokens_ptr);
 }
 
+int spice_char_device_state_restore(SpiceCharDeviceState *dev,
+                                    SpiceMigrateDataCharDevice *mig_data)
+{
+    SpiceCharDeviceClientState *client_state;
+    uint32_t client_tokens_window;
+
+    spice_assert(dev->num_clients == 1 && dev->wait_for_migrate_data);
+
+    client_state = SPICE_CONTAINEROF(ring_get_tail(&dev->clients),
+                                     SpiceCharDeviceClientState,
+                                     link);
+    if (mig_data->version > SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION) {
+        spice_error("dev %p error: migration data version %u is bigger than self %u",
+                    dev, mig_data->version, SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION);
+        return FALSE;
+    }
+    spice_assert(!dev->cur_write_buf && ring_is_empty(&dev->write_queue));
+    spice_assert(mig_data->connected);
+
+    client_tokens_window = client_state->num_client_tokens; /* initial state of tokens */
+    client_state->num_client_tokens = mig_data->num_client_tokens;
+    /* assumption: client_tokens_window stays the same across severs */
+    client_state->num_client_tokens_free = client_tokens_window -
+                                           mig_data->num_client_tokens -
+                                           mig_data->write_num_client_tokens;
+    client_state->num_send_tokens = mig_data->num_send_tokens;
+
+    if (mig_data->write_size > 0) {
+        if (mig_data->write_num_client_tokens) {
+            dev->cur_write_buf = __spice_char_device_write_buffer_get(dev, client_state->client,
+                                                                      mig_data->write_size,
+                                                                      mig_data->write_num_client_tokens);
+        } else {
+            dev->cur_write_buf = __spice_char_device_write_buffer_get(dev, NULL, mig_data->write_size,
+                                                                      0);
+        }
+        /* the first write buffer contains all the data that was saved for migration */
+        memcpy(dev->cur_write_buf->buf,
+               ((uint8_t *)mig_data) + mig_data->write_data_ptr - sizeof(SpiceMigrateDataHeader),
+               mig_data->write_size);
+        dev->cur_write_buf->buf_used = mig_data->write_size;
+        dev->cur_write_buf_pos = dev->cur_write_buf->buf;
+    }
+    dev->wait_for_migrate_data = FALSE;
+    spice_char_device_write_to_device(dev);
+    spice_char_device_read_from_device(dev);
+    return TRUE;
+}
+
diff --git a/server/char_device.h b/server/char_device.h
index f3278e3..6688e91 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -126,6 +126,9 @@ void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
                                                   SpiceMarshaller *m);
 void spice_char_device_state_migrate_data_marshall_empty(SpiceMarshaller *m);
 
+int spice_char_device_state_restore(SpiceCharDeviceState *dev,
+                                    SpiceMigrateDataCharDevice *mig_data);
+
 /*
  * Resets write/read queues, and moves that state to being stopped.
  * This routine is a workaround for a bad tokens management in the vdagent
commit cb767a83fda2b93b47de284719353b3d073120be
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 22:55:53 2012 +0300

    char device migration: don't read or write from/to the device while waiting for migraion data

diff --git a/server/char_device.c b/server/char_device.c
index 84121e6..d97c6dd 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -45,6 +45,8 @@ struct SpiceCharDeviceClientState {
 
 struct SpiceCharDeviceState {
     int running;
+    int active; /* has read/write been performed since the device was started */
+    int wait_for_migrate_data;
     uint32_t refs;
 
     Ring write_queue;
@@ -268,7 +270,7 @@ static int spice_char_device_read_from_device(SpiceCharDeviceState *dev)
     uint64_t max_send_tokens;
     int did_read = FALSE;
 
-    if (!dev->running) {
+    if (!dev->running || dev->wait_for_migrate_data) {
         return FALSE;
     }
 
@@ -307,6 +309,7 @@ static int spice_char_device_read_from_device(SpiceCharDeviceState *dev)
     }
     dev->during_read_from_device = 0;
     spice_char_device_state_unref(dev);
+    dev->active = dev->active || did_read;
     return did_read;
 }
 
@@ -415,7 +418,7 @@ static int spice_char_device_write_to_device(SpiceCharDeviceState *dev)
     int total = 0;
     int n;
 
-    if (!dev->running) {
+    if (!dev->running || dev->wait_for_migrate_data) {
         return 0;
     }
 
@@ -462,6 +465,7 @@ static int spice_char_device_write_to_device(SpiceCharDeviceState *dev)
         spice_assert(ring_is_empty(&dev->write_queue));
     }
     spice_char_device_state_unref(dev);
+    dev->active = dev->active || total;
     return total;
 }
 
@@ -682,13 +686,17 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
                                   int do_flow_control,
                                   uint32_t max_send_queue_size,
                                   uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens)
+                                  uint32_t num_send_tokens,
+                                  int wait_for_migrate_data)
 {
     SpiceCharDeviceClientState *dev_client;
 
     spice_assert(dev);
     spice_assert(client);
 
+    spice_assert(!wait_for_migrate_data || (dev->num_clients == 0 && !dev->active));
+    dev->wait_for_migrate_data = wait_for_migrate_data;
+
     spice_debug("dev_state %p client %p", dev, client);
     dev_client = spice_new0(SpiceCharDeviceClientState, 1);
     dev_client->dev = dev;
@@ -727,8 +735,12 @@ void spice_char_device_client_remove(SpiceCharDeviceState *dev,
         spice_error("client wasn't found");
         return;
     }
-
     spice_char_device_client_free(dev, dev_client);
+    if (dev->wait_for_migrate_data) {
+        spice_assert(dev->num_clients == 0);
+        dev->wait_for_migrate_data  = FALSE;
+        spice_char_device_read_from_device(dev);
+    }
 }
 
 int spice_char_device_client_exists(SpiceCharDeviceState *dev,
@@ -751,14 +763,16 @@ void spice_char_device_stop(SpiceCharDeviceState *dev)
 {
     spice_debug("dev_state %p", dev);
     dev->running = FALSE;
+    dev->active = FALSE;
     core->timer_cancel(dev->write_to_dev_timer);
 }
 
 void spice_char_device_reset(SpiceCharDeviceState *dev)
 {
     RingItem *client_item;
-    spice_char_device_stop(dev);
 
+    spice_char_device_stop(dev);
+    dev->wait_for_migrate_data = FALSE;
     spice_debug("dev_state %p", dev);
     while (!ring_is_empty(&dev->write_queue)) {
         RingItem *item = ring_get_tail(&dev->write_queue);
diff --git a/server/char_device.h b/server/char_device.h
index 186b1f1..f3278e3 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -150,7 +150,8 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
                                   int do_flow_control,
                                   uint32_t max_send_queue_size,
                                   uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens);
+                                  uint32_t num_send_tokens,
+                                  int wait_for_migrate_data);
 
 void spice_char_device_client_remove(SpiceCharDeviceState *dev,
                                      RedClient *client);
diff --git a/server/reds.c b/server/reds.c
index dc44de5..a5a5a75 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1090,13 +1090,13 @@ void reds_fill_channels(SpiceMsgChannels *channels_info)
 void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
 {
     SpiceCharDeviceState *dev_state = reds->agent_state.base;
-    RedClient *client;
+    RedChannelClient *rcc;
 
     if (!vdagent) {
         return;
     }
     spice_assert(vdagent->st && vdagent->st == dev_state);
-    client = main_channel_client_get_base(mcc)->client;
+    rcc = main_channel_client_get_base(mcc);
     /*
      * Note that in older releases, send_tokens were set to ~0 on both client
      * and server. The server ignored the client given tokens.
@@ -1104,16 +1104,17 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
      * and vice versa, the sending from the server to the client won't have
      * flow control, but will have no other problem.
      */
-    if (!spice_char_device_client_exists(dev_state, client)) {
+    if (!spice_char_device_client_exists(dev_state, rcc->client)) {
         spice_char_device_client_add(dev_state,
-                                     client,
+                                     rcc->client,
                                      TRUE, /* flow control */
                                      REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
                                      REDS_AGENT_WINDOW_SIZE,
-                                     num_tokens);
+                                     num_tokens,
+                                     red_channel_client_waits_for_migrate_data(rcc));
     } else {
         spice_char_device_send_to_client_tokens_set(dev_state,
-                                                    client,
+                                                    rcc->client,
                                                     num_tokens);
     }
     reds->agent_state.write_filter.discard_all = FALSE;
diff --git a/server/smartcard.c b/server/smartcard.c
index 2ed0bde..de86185 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -326,7 +326,8 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
                                  FALSE, /* no flow control yet */
                                  0, /* send queue size */
                                  ~0,
-                                 ~0);
+                                 ~0,
+                                 red_channel_client_waits_for_migrate_data(&scc->base));
     scc->smartcard_state = st;
     write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
     if (!write_buf) {
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 36d901f..8bc23fd 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -309,7 +309,8 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
     state->rcc = rcc;
     red_channel_client_ack_zero_messages_window(rcc);
 
-    spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0);
+    spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0,
+                                 red_channel_client_waits_for_migrate_data(rcc));
 
     if (sif->state) {
         sif->state(sin, 1);
commit b0264a5e37b308c8a5b268974aa9936014a9389f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 22:44:12 2012 +0300

    char device migration: marshall migration data

diff --git a/server/char_device.c b/server/char_device.c
index 419b7df..84121e6 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -790,3 +790,72 @@ void spice_char_device_wakeup(SpiceCharDeviceState *dev)
     spice_char_device_read_from_device(dev);
 }
 
+/*************
+ * Migration *
+ * **********/
+
+void spice_char_device_state_migrate_data_marshall_empty(SpiceMarshaller *m)
+{
+    SpiceMigrateDataCharDevice mig_data;
+
+    memset(&mig_data, 0, sizeof(mig_data));
+    mig_data.version = SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION;
+    mig_data.connected = FALSE;
+    spice_marshaller_add_ref(m, (uint8_t *)&mig_data, sizeof(SpiceMigrateDataCharDevice));
+}
+
+void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
+                                                   SpiceMarshaller *m)
+{
+    SpiceCharDeviceClientState *client_state;
+    RingItem *item;
+    uint32_t *write_to_dev_size_ptr;
+    uint32_t *write_to_dev_tokens_ptr;
+    SpiceMarshaller *m2;
+
+    /* multi-clients are not supported */
+    spice_assert(dev->num_clients == 1);
+    client_state = SPICE_CONTAINEROF(ring_get_tail(&dev->clients),
+                                     SpiceCharDeviceClientState,
+                                     link);
+    /* FIXME: if there were more than one client before the marshalling,
+     * it is possible that the send_queue_size > 0, and the send data
+     * should be migrated as well */
+    spice_assert(client_state->send_queue_size == 0);
+    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION);
+    spice_marshaller_add_uint8(m, 1); /* connected */
+    spice_marshaller_add_uint32(m, client_state->num_client_tokens);
+    spice_marshaller_add_uint32(m, client_state->num_send_tokens);
+    write_to_dev_size_ptr = (uint32_t *)spice_marshaller_reserve_space(m, sizeof(uint32_t));
+    write_to_dev_tokens_ptr = (uint32_t *)spice_marshaller_reserve_space(m, sizeof(uint32_t));
+    *write_to_dev_size_ptr = 0;
+    *write_to_dev_tokens_ptr = 0;
+
+    m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
+    if (dev->cur_write_buf) {
+        uint32_t buf_remaining = dev->cur_write_buf->buf + dev->cur_write_buf->buf_used -
+                                 dev->cur_write_buf_pos;
+
+        spice_marshaller_add_ref(m2, dev->cur_write_buf_pos, buf_remaining);
+        *write_to_dev_size_ptr += buf_remaining;
+        if (dev->cur_write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT) {
+            spice_assert(dev->cur_write_buf->client == client_state->client);
+            (*write_to_dev_tokens_ptr) += dev->cur_write_buf->token_price;
+        }
+    }
+
+    RING_FOREACH_REVERSED(item, &dev->write_queue) {
+        SpiceCharDeviceWriteBuffer *write_buf;
+
+        write_buf = SPICE_CONTAINEROF(item, SpiceCharDeviceWriteBuffer, link);
+        spice_marshaller_add_ref(m2, write_buf->buf, write_buf->buf_used);
+        *write_to_dev_size_ptr += write_buf->buf_used;
+        if (write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT) {
+            spice_assert(write_buf->client == client_state->client);
+            (*write_to_dev_tokens_ptr) += write_buf->token_price;
+        }
+    }
+    spice_debug("migration data dev %p: write_queue size %u tokens %u",
+                dev, *write_to_dev_size_ptr, *write_to_dev_tokens_ptr);
+}
+
diff --git a/server/char_device.h b/server/char_device.h
index 9b70219..186b1f1 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -3,6 +3,7 @@
 
 #include "spice.h"
 #include "red_channel.h"
+#include "migration_protocol.h"
 
 /*
  * Shared code for char devices, mainly for flow control.
@@ -120,6 +121,10 @@ void spice_char_device_state_destroy(SpiceCharDeviceState *dev);
 
 void *spice_char_device_state_opaque_get(SpiceCharDeviceState *dev);
 
+/* only one client is supported */
+void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
+                                                  SpiceMarshaller *m);
+void spice_char_device_state_migrate_data_marshall_empty(SpiceMarshaller *m);
 
 /*
  * Resets write/read queues, and moves that state to being stopped.
commit 520e2cd4f492be3e95b5d070437b3f0db1098d0b
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 23:07:10 2012 +0300

    char_device: variable token price for write buffers
    
    When restoring migration data, we also restore data that is addressed to
    the device, and that might have been originated from more than 1
    message. When the write buffer that is assoicated with this data is
    released, we need to free all the relevant tokens.

diff --git a/server/char_device.c b/server/char_device.c
index c28e548..419b7df 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -387,17 +387,24 @@ void spice_char_device_send_to_client_tokens_set(SpiceCharDeviceState *dev,
  * Writing to the device  *
 ***************************/
 
-static void spice_char_device_client_token_add(SpiceCharDeviceState *dev,
-                                               SpiceCharDeviceClientState *dev_client)
+static void spice_char_device_client_tokens_add(SpiceCharDeviceState *dev,
+                                                SpiceCharDeviceClientState *dev_client,
+                                                uint32_t num_tokens)
 {
     if (!dev_client->do_flow_control) {
         return;
     }
-    if (++dev_client->num_client_tokens_free == dev->client_tokens_interval) {
-        dev_client->num_client_tokens += dev->client_tokens_interval;
+    if (num_tokens > 1) {
+        spice_debug("#tokens > 1 (=%u)", num_tokens);
+    }
+    dev_client->num_client_tokens_free += num_tokens;
+    if (dev_client->num_client_tokens_free >= dev->client_tokens_interval) {
+        uint32_t tokens = dev_client->num_client_tokens_free;
+
+        dev_client->num_client_tokens += dev_client->num_client_tokens_free;
         dev_client->num_client_tokens_free = 0;
         dev->cbs.send_tokens_to_client(dev_client->client,
-                                       dev->client_tokens_interval,
+                                       tokens,
                                        dev->opaque);
     }
 }
@@ -466,8 +473,10 @@ static void spice_char_dev_write_retry(void *opaque)
     spice_char_device_write_to_device(dev);
 }
 
-SpiceCharDeviceWriteBuffer *spice_char_device_write_buffer_get(SpiceCharDeviceState *dev,
-                                                               RedClient *client, int size)
+static SpiceCharDeviceWriteBuffer *__spice_char_device_write_buffer_get(SpiceCharDeviceState *dev,
+                                                                        RedClient *client,
+                                                                        int size,
+                                                                        int migrated_data_tokens)
 {
     RingItem *item;
     SpiceCharDeviceWriteBuffer *ret;
@@ -494,14 +503,15 @@ SpiceCharDeviceWriteBuffer *spice_char_device_write_buffer_get(SpiceCharDeviceSt
     if (client) {
        SpiceCharDeviceClientState *dev_client = spice_char_device_client_find(dev, client);
        if (dev_client) {
-            if (dev_client->do_flow_control && !dev_client->num_client_tokens) {
+            if (!migrated_data_tokens &&
+                dev_client->do_flow_control && !dev_client->num_client_tokens) {
                 spice_printerr("token violation: dev %p client %p", dev, client);
                 spice_char_device_handle_client_overflow(dev_client);
                 goto error;
             }
             ret->origin = WRITE_BUFFER_ORIGIN_CLIENT;
             ret->client = client;
-            if (dev_client->do_flow_control) {
+            if (!migrated_data_tokens && dev_client->do_flow_control) {
                 dev_client->num_client_tokens--;
             }
         } else {
@@ -515,12 +525,19 @@ SpiceCharDeviceWriteBuffer *spice_char_device_write_buffer_get(SpiceCharDeviceSt
         dev->num_self_tokens--;
     }
 
+    ret->token_price = migrated_data_tokens ? migrated_data_tokens : 1;
     return ret;
 error:
     ring_add(&dev->write_bufs_pool, &ret->link);
     return NULL;
 }
 
+SpiceCharDeviceWriteBuffer *spice_char_device_write_buffer_get(SpiceCharDeviceState *dev,
+                                                               RedClient *client,
+                                                               int size)
+{
+   return  __spice_char_device_write_buffer_get(dev, client, size, 0);
+}
 void spice_char_device_write_buffer_add(SpiceCharDeviceState *dev,
                                         SpiceCharDeviceWriteBuffer *write_buf)
 {
@@ -541,6 +558,7 @@ void spice_char_device_write_buffer_release(SpiceCharDeviceState *dev,
                                             SpiceCharDeviceWriteBuffer *write_buf)
 {
     int buf_origin = write_buf->origin;
+    uint32_t buf_token_price = write_buf->token_price;
     RedClient *client = write_buf->client;
 
     spice_assert(!ring_item_is_linked(&write_buf->link));
@@ -561,17 +579,15 @@ void spice_char_device_write_buffer_release(SpiceCharDeviceState *dev,
         dev_client = spice_char_device_client_find(dev, client);
         /* when a client is removed, we remove all the buffers that are associated with it */
         spice_assert(dev_client);
-        spice_char_device_client_token_add(dev, dev_client);
+        spice_char_device_client_tokens_add(dev, dev_client, buf_token_price);
     } else if (buf_origin == WRITE_BUFFER_ORIGIN_SERVER) {
         dev->num_self_tokens++;
         if (dev->cbs.on_free_self_token) {
             dev->cbs.on_free_self_token(dev->opaque);
         }
     }
-
 }
 
-
 /********************************
  * char_device_state management *
  ********************************/
diff --git a/server/char_device.h b/server/char_device.h
index ef8ce3a..9b70219 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -71,6 +71,7 @@ typedef struct SpiceCharDeviceWriteBuffer {
     uint8_t *buf;
     uint32_t buf_size;
     uint32_t buf_used;
+    uint32_t token_price;
 } SpiceCharDeviceWriteBuffer;
 
 typedef void SpiceCharDeviceMsgToClient;
commit 1d2b071d15cb873d0a55cbf04359e2e6a0227ac2
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 22:23:04 2012 +0300

    migration_protocol: add migration data for char devices

diff --git a/server/migration_protocol.h b/server/migration_protocol.h
index 2b7f4c2..7a1cb1d 100644
--- a/server/migration_protocol.h
+++ b/server/migration_protocol.h
@@ -31,6 +31,26 @@ typedef struct __attribute__ ((__packed__)) SpiceMigrateDataHeader {
     uint32_t version;
 } SpiceMigrateDataHeader;
 
+/* ********************
+ * Char device base
+ * *******************/
+
+/* increase the version of descendent char devices when this
+ * version is increased */
+#define SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION 1
+
+/* Should be the first field of any of the char_devices migration data (see write_data_ptr) */
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataCharDevice {
+    uint32_t version;
+    uint8_t connected;
+    uint32_t num_client_tokens;
+    uint32_t num_send_tokens;
+    uint32_t write_size; /* write to dev */
+    uint32_t write_num_client_tokens; /* how many messages from the client are part of the write_data */
+    uint32_t write_data_ptr; /* offset from
+                                SpiceMigrateDataCharDevice - sizeof(SpiceMigrateDataHeader) */
+} SpiceMigrateDataCharDevice;
+
 static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
                                                      uint32_t magic,
                                                      uint32_t version)
commit 8875e1da453c59ff6e9377bcae6eed0f0d8b4d34
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Aug 14 14:50:39 2012 +0300

    replace some migration related spice_error calls with info/warning

diff --git a/server/reds.c b/server/reds.c
index c957b5d..dc44de5 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4111,7 +4111,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char*
     } else {
         if (reds->num_clients == 0) {
             reds_mig_release();
-            spice_error("no client connected");
+            spice_info("no client connected");
         }
         sif->migrate_connect_complete(migration_interface);
     }
@@ -4169,7 +4169,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_end(SpiceServer *s, int completed)
 
     sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
     if (completed && !reds->expect_migrate && reds->num_clients) {
-        spice_error("spice_server_migrate_info was not called, disconnecting clients");
+        spice_warning("spice_server_migrate_info was not called, disconnecting clients");
         reds_disconnect();
         ret = -1;
         goto complete;
commit 275e4312df6c0f13ca2253ceac3976cee7d700e9
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Aug 14 14:47:49 2012 +0300

    seamless migration: migration completion on the destination side
    
    Tracking the channels that wait for migration data. If there
    is a new migration process pending, when all the channels have
    restored their state, we begin the new migration.

diff --git a/server/main_channel.c b/server/main_channel.c
index 6398965..e06bb05 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -837,10 +837,14 @@ void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
                    "client does not support semi-seamless migration");
             return;
     }
-    red_client_migrate_complete(mcc->base.client);
-    if (mcc->mig_wait_prev_complete) {
+    red_client_semi_seamless_migrate_complete(mcc->base.client);
+}
 
+void main_channel_migrate_dst_complete(MainChannelClient *mcc)
+{
+    if (mcc->mig_wait_prev_complete) {
         if (mcc->mig_wait_prev_try_seamless) {
+            spice_assert(mcc->base.channel->clients_num == 1);
             red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS);
         } else {
             red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
@@ -849,6 +853,7 @@ void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
         mcc->mig_wait_prev_complete = FALSE;
     }
 }
+
 static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
                                       void *message)
 {
@@ -1248,7 +1253,7 @@ void main_channel_migrate_cancel_wait(MainChannel *main_chan)
     main_chan->num_clients_mig_wait = 0;
 }
 
-int main_channel_migrate_complete(MainChannel *main_chan, int success)
+int main_channel_migrate_src_complete(MainChannel *main_chan, int success)
 {
     RingItem *client_link;
     int semi_seamless_count = 0;
diff --git a/server/main_channel.h b/server/main_channel.h
index 40d2215..8cfe62b 100644
--- a/server/main_channel.h
+++ b/server/main_channel.h
@@ -104,7 +104,8 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
                                  int try_seamless);
 void main_channel_migrate_cancel_wait(MainChannel *main_chan);
 /* returns the number of clients for which SPICE_MSG_MAIN_MIGRATE_END was sent*/
-int main_channel_migrate_complete(MainChannel *main_chan, int success);
+int main_channel_migrate_src_complete(MainChannel *main_chan, int success);
+void main_channel_migrate_dst_complete(MainChannelClient *mcc);
 void main_channel_push_name(MainChannelClient *mcc, const char *name);
 void main_channel_push_uuid(MainChannelClient *mcc, const uint8_t uuid[16]);
 
diff --git a/server/main_dispatcher.c b/server/main_dispatcher.c
index f5b8b4c..1126ec0 100644
--- a/server/main_dispatcher.c
+++ b/server/main_dispatcher.c
@@ -7,6 +7,8 @@
 #include "red_common.h"
 #include "dispatcher.h"
 #include "main_dispatcher.h"
+#include "red_channel.h"
+#include "reds.h"
 
 /*
  * Main Dispatcher
@@ -37,6 +39,7 @@ MainDispatcher main_dispatcher;
 
 enum {
     MAIN_DISPATCHER_CHANNEL_EVENT = 0,
+    MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
 
     MAIN_DISPATCHER_NUM_MESSAGES
 };
@@ -46,6 +49,10 @@ typedef struct MainDispatcherChannelEventMessage {
     SpiceChannelEventInfo *info;
 } MainDispatcherChannelEventMessage;
 
+typedef struct MainDispatcherMigrateSeamlessDstCompleteMessage {
+    RedClient *client;
+} MainDispatcherMigrateSeamlessDstCompleteMessage;
+
 /* channel_event - calls core->channel_event, must be done in main thread */
 static void main_dispatcher_self_handle_channel_event(
                                                 int event,
@@ -80,6 +87,28 @@ void main_dispatcher_channel_event(int event, SpiceChannelEventInfo *info)
                             &msg);
 }
 
+
+static void main_dispatcher_handle_migrate_complete(void *opaque,
+                                                    void *payload)
+{
+    MainDispatcherMigrateSeamlessDstCompleteMessage *mig_complete = payload;
+
+    reds_on_client_seamless_migrate_complete(mig_complete->client);
+}
+
+void main_dispatcher_seamless_migrate_dst_complete(RedClient *client)
+{
+    MainDispatcherMigrateSeamlessDstCompleteMessage msg;
+
+    if (pthread_self() == main_dispatcher.base.self) {
+        reds_on_client_seamless_migrate_complete(client);
+        return;
+    }
+
+    msg.client = client;
+    dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
+                            &msg);
+}
 static void dispatcher_handle_read(int fd, int event, void *opaque)
 {
     Dispatcher *dispatcher = opaque;
@@ -97,4 +126,7 @@ void main_dispatcher_init(SpiceCoreInterface *core)
     dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_CHANNEL_EVENT,
                                 main_dispatcher_handle_channel_event,
                                 sizeof(MainDispatcherChannelEventMessage), 0 /* no ack */);
+    dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
+                                main_dispatcher_handle_migrate_complete,
+                                sizeof(MainDispatcherMigrateSeamlessDstCompleteMessage), 0 /* no ack */);
 }
diff --git a/server/main_dispatcher.h b/server/main_dispatcher.h
index 2c201c7..ec4a6b4 100644
--- a/server/main_dispatcher.h
+++ b/server/main_dispatcher.h
@@ -4,6 +4,7 @@
 #include <spice.h>
 
 void main_dispatcher_channel_event(int event, SpiceChannelEventInfo *info);
+void main_dispatcher_seamless_migrate_dst_complete(RedClient *client);
 void main_dispatcher_init(SpiceCoreInterface *core);
 
 #endif //MAIN_DISPATCHER_H
diff --git a/server/red_channel.c b/server/red_channel.c
index d715ce8..65ef2da 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -36,6 +36,7 @@
 #include "stat.h"
 #include "red_channel.h"
 #include "reds.h"
+#include "main_dispatcher.h"
 
 static void red_channel_client_event(int fd, int event, void *data);
 static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
@@ -688,6 +689,45 @@ error:
     return NULL;
 }
 
+static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
+{
+    rcc->wait_migrate_data = FALSE;
+
+    pthread_mutex_lock(&rcc->client->lock);
+    rcc->client->num_migrated_channels--;
+
+    /* we assume we always have at least one channel who has migration data transfer,
+     * otherwise, this flag will never be set back to FALSE*/
+    if (!rcc->client->num_migrated_channels) {
+        rcc->client->during_target_migrate = FALSE;
+        rcc->client->seamless_migrate = FALSE;
+        /* migration completion might have been triggered from a different thread
+         * than the main thread */
+        main_dispatcher_seamless_migrate_dst_complete(rcc->client);
+    }
+    pthread_mutex_unlock(&rcc->client->lock);
+}
+
+int red_channel_client_waits_for_migrate_data(RedChannelClient *rcc)
+{
+    return rcc->wait_migrate_data;
+}
+
+int red_channel_waits_for_migrate_data(RedChannel *channel)
+{
+    RedChannelClient *rcc;
+    if (!red_channel_is_connected(channel)) {
+        return FALSE;
+    }
+
+    if (channel->clients_num > 1) {
+        return FALSE;
+    }
+    spice_assert(channel->clients_num == 1);
+    rcc = SPICE_CONTAINEROF(ring_get_head(&channel->clients), RedChannelClient, channel_link);
+    return red_channel_client_waits_for_migrate_data(rcc);
+}
+
 static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
                                                RedsStream *stream,
                                                int migration,
@@ -1085,13 +1125,21 @@ static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
 // So need to make all the handlers work with per channel/client data (what data exactly?)
 static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
+    spice_debug("channel type %d id %d rcc %p size %u",
+                rcc->channel->type, rcc->channel->id, rcc, size);
     if (!rcc->channel->channel_cbs.handle_migrate_data) {
         return;
     }
-    spice_assert(red_channel_client_get_message_serial(rcc) == 0);
-    red_channel_client_set_message_serial(rcc,
-        rcc->channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
+    if (!red_channel_client_waits_for_migrate_data(rcc)) {
+        spice_error("unexcpected");
+        return;
+    }
+    if (rcc->channel->channel_cbs.handle_migrate_data_get_serial) {
+        red_channel_client_set_message_serial(rcc,
+            rcc->channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
+    }
     rcc->channel->channel_cbs.handle_migrate_data(rcc, size, message);
+    red_channel_client_seamless_migration_done(rcc);
 }
 
 int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
@@ -1555,11 +1603,38 @@ RedClient *red_client_new(int migrated)
     ring_init(&client->channels);
     pthread_mutex_init(&client->lock, NULL);
     client->thread_id = pthread_self();
-    client->migrated = migrated;
+    client->during_target_migrate = migrated;
 
     return client;
 }
 
+/* client mutex should be locked before this call */
+static void red_channel_client_set_migration_seamless(RedChannelClient *rcc)
+{
+    spice_assert(rcc->client->during_target_migrate && rcc->client->seamless_migrate);
+
+    if (rcc->channel->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
+        rcc->wait_migrate_data = TRUE;
+        rcc->client->num_migrated_channels++;
+    }
+    spice_debug("channel type %d id %d rcc %p wait data %d", rcc->channel->type, rcc->channel->id, rcc,
+        rcc->wait_migrate_data);
+}
+
+void red_client_set_migration_seamless(RedClient *client) // dest
+{
+    RingItem *link;
+    pthread_mutex_lock(&client->lock);
+    client->seamless_migrate = TRUE;
+    /* update channel clients that got connected before the migration
+     * type was set. red_client_add_channel will handle newer channel clients */
+    RING_FOREACH(link, &client->channels) {
+        RedChannelClient *rcc = SPICE_CONTAINEROF(link, RedChannelClient, client_link);
+        red_channel_client_set_migration_seamless(rcc);
+    }
+    pthread_mutex_unlock(&client->lock);
+}
+
 void red_client_migrate(RedClient *client)
 {
     RingItem *link, *next;
@@ -1625,6 +1700,9 @@ static void red_client_add_channel(RedClient *client, RedChannelClient *rcc)
 {
     spice_assert(rcc && client);
     ring_add(&client->channels, &rcc->client_link);
+    if (client->during_target_migrate && client->seamless_migrate) {
+        red_channel_client_set_migration_seamless(rcc);
+    }
     client->channels_num++;
 }
 
@@ -1636,16 +1714,27 @@ void red_client_set_main(RedClient *client, MainChannelClient *mcc) {
     client->mcc = mcc;
 }
 
-void red_client_migrate_complete(RedClient *client)
+void red_client_semi_seamless_migrate_complete(RedClient *client)
 {
-    spice_assert(client->migrated);
-    client->migrated = FALSE;
-    reds_on_client_migrate_complete(client);
+    pthread_mutex_lock(&client->lock);
+    if (!client->during_target_migrate || client->seamless_migrate) {
+        spice_error("unexpected");
+        pthread_mutex_unlock(&client->lock);
+        return;
+    }
+    client->during_target_migrate = FALSE;
+    pthread_mutex_unlock(&client->lock);
+    reds_on_client_semi_seamless_migrate_complete(client);
 }
 
+/* should be called only from the main thread */
 int red_client_during_migrate_at_target(RedClient *client)
 {
-    return client->migrated;
+    int ret;
+    pthread_mutex_lock(&client->lock);
+    ret = client->during_target_migrate;
+    pthread_mutex_unlock(&client->lock);
+    return ret;
 }
 
 /*
diff --git a/server/red_channel.h b/server/red_channel.h
index 35d11a6..8c8e1c8 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -267,6 +267,8 @@ struct RedChannelClient {
     RedChannelCapabilities remote_caps;
     int is_mini_header;
     int destroying;
+
+    int wait_migrate_data;
     int wait_migrate_flush_mark;
 };
 
@@ -357,6 +359,11 @@ int red_channel_is_connected(RedChannel *channel);
 int red_channel_client_is_connected(RedChannelClient *rcc);
 
 void red_channel_client_default_migrate(RedChannelClient *rcc);
+int red_channel_client_waits_for_migrate_data(RedChannelClient *rcc);
+/* seamless migration is supported for only one client. This routine
+ * checks if the only channel client associated with channel is
+ * waiting for migration data */
+int red_channel_waits_for_migrate_data(RedChannel *channel);
 
 /*
  * the disconnect callback is called from the channel's thread,
@@ -513,14 +520,31 @@ struct RedClient {
     pthread_t thread_id;
 
     int disconnecting;
-    int migrated;
+    /* Note that while semi-seamless migration is conducted by the main thread, seamless migration
+     * involves all channels, and thus the related varaibles can be accessed from different
+     * threads */
+    int during_target_migrate; /* if seamless=TRUE, migration_target is turned off when all
+                                  the clients received their migration data. Otherwise (semi-seamless),
+                                  it is turned off, when red_client_semi_seamless_migrate_complete
+                                  is called */
+    int seamless_migrate;
+    int num_migrated_channels; /* for seamless - number of channels that wait for migrate data*/
 };
 
 RedClient *red_client_new(int migrated);
+
 MainChannelClient *red_client_get_main(RedClient *client);
 // main should be set once before all the other channels are created
 void red_client_set_main(RedClient *client, MainChannelClient *mcc);
-void red_client_migrate_complete(RedClient *client);
+
+/* called when the migration handshake results in seamless migration (dst side).
+ * By default we assume semi-seamless */
+void red_client_set_migration_seamless(RedClient *client);
+void red_client_semi_seamless_migrate_complete(RedClient *client); /* dst side */
+/* TRUE if the migration is seamless and there are still channels that wait from migration data.
+ * Or, during semi-seamless migration, and the main channel still waits for MIGRATE_END
+ * from the client.
+ * Note: Call it only from the main thread */
 int red_client_during_migrate_at_target(RedClient *client);
 
 void red_client_migrate(RedClient *client);
diff --git a/server/reds.c b/server/reds.c
index 19e72bd..c957b5d 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1440,6 +1440,21 @@ static void reds_mig_target_client_disconnect_all(void)
     }
 }
 
+static int reds_find_client(RedClient *client)
+{
+    RingItem *item;
+
+    RING_FOREACH(item, &reds->clients) {
+        RedClient *list_client;
+
+        list_client = SPICE_CONTAINEROF(item, RedClient, link);
+        if (list_client == client) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
 // TODO: now that main is a separate channel this should
 // actually be joined with reds_handle_other_links, become reds_handle_link
 static void reds_handle_main_link(RedLinkInfo *link)
@@ -1625,18 +1640,26 @@ int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_versio
     if (reds->allow_multiple_clients  || src_version > SPICE_MIGRATION_PROTOCOL_VERSION) {
         reds->dst_do_seamless_migrate = FALSE;
     } else {
-        RedClient *client;
+        RedChannelClient *rcc = main_channel_client_get_base(mcc);
 
-        client = main_channel_client_get_base(mcc)->client;
-        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
+        red_client_set_migration_seamless(rcc->client);
         /* linking all the channels that have been connected before migration handshake */
-        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
+        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(rcc->client);
     }
     return reds->dst_do_seamless_migrate;
 }
 
-/* semi seamless */
-void reds_on_client_migrate_complete(RedClient *client)
+void reds_on_client_seamless_migrate_complete(RedClient *client)
+{
+    spice_debug(NULL);
+    if (!reds_find_client(client)) {
+        spice_info("client no longer exists");
+        return;
+    }
+    main_channel_migrate_dst_complete(red_client_get_main(client));
+}
+
+void reds_on_client_semi_seamless_migrate_complete(RedClient *client)
 {
     MainChannelClient *mcc;
 
@@ -1649,6 +1672,7 @@ void reds_on_client_migrate_complete(RedClient *client)
                            reds_get_mm_time() - MM_TIME_DELTA,
                            red_dispatcher_qxl_ram_size());
     reds_link_mig_target_channels(client);
+    main_channel_migrate_dst_complete(mcc);
 }
 
 static void reds_handle_other_links(RedLinkInfo *link)
@@ -3202,7 +3226,7 @@ static void reds_mig_finished(int completed)
     if (reds->src_do_seamless_migrate && completed) {
         reds_migrate_channels_seamless();
     } else {
-        main_channel_migrate_complete(reds->main_channel, completed);
+        main_channel_migrate_src_complete(reds->main_channel, completed);
     }
 
     if (completed) {
@@ -4067,8 +4091,8 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char*
     spice_assert(reds == s);
 
     if (reds->expect_migrate) {
-        spice_error("consecutive calls without migration. Canceling previous call");
-        main_channel_migrate_complete(reds->main_channel, FALSE);
+        spice_info("consecutive calls without migration. Canceling previous call");
+        main_channel_migrate_src_complete(reds->main_channel, FALSE);
     }
 
     sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
diff --git a/server/reds.h b/server/reds.h
index 71a0173..779d0db 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -157,7 +157,8 @@ void reds_on_main_mouse_mode_request(void *message, size_t size);
 /* migration dest side: returns whether it can support seamless migration
  * with the given src migration protocol version */
 int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version);
-void reds_on_client_migrate_complete(RedClient *client);
+void reds_on_client_semi_seamless_migrate_complete(RedClient *client);
+void reds_on_client_seamless_migrate_complete(RedClient *client);
 void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
 #endif
commit eb4c95b08b6848ee604497bb66392636341ad1fe
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 13:20:20 2012 +0300

    red_channel: handle sending SPICE_MSG_MIGRATE
    
    The relevant code is common to all channels.
    
    The patch also contains a fix to the return value for
    handle_migrate_data callback: s/uint64_t/int

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index e14e995..269e2dc 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -551,7 +551,8 @@ void inputs_init(void)
                                     FALSE, /* handle_acks */
                                     spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL),
                                     inputs_channel_handle_parsed,
-                                    &channel_cbs);
+                                    &channel_cbs,
+                                    0);
 
     if (!g_inputs_channel) {
         spice_error("failed to allocate Inputs Channel");
diff --git a/server/main_channel.c b/server/main_channel.c
index 6123068..6398965 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -475,7 +475,7 @@ static uint64_t main_channel_handle_migrate_data_get_serial(RedChannelClient *ba
     return data->serial;
 }
 
-static uint64_t main_channel_handle_migrate_data(RedChannelClient *base,
+static int main_channel_handle_migrate_data(RedChannelClient *base,
     uint32_t size, void *message)
 {
     MainChannelClient *mcc = SPICE_CONTAINEROF(base, MainChannelClient, base);
@@ -1138,7 +1138,8 @@ MainChannel* main_channel_init(void)
                                         FALSE, FALSE, /* handle_acks */
                                         spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL),
                                         main_channel_handle_parsed,
-                                        &channel_cbs);
+                                        &channel_cbs,
+                                        SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
     spice_assert(channel);
     red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
 
diff --git a/server/red_channel.c b/server/red_channel.c
index a108bc2..d715ce8 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -452,6 +452,20 @@ static void red_channel_client_send_set_ack(RedChannelClient *rcc)
     red_channel_client_begin_send_message(rcc);
 }
 
+static void red_channel_client_send_migrate(RedChannelClient *rcc)
+{
+    SpiceMsgMigrate migrate;
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
+    migrate.flags = rcc->channel->migration_flags;
+    spice_marshall_msg_migrate(rcc->send_data.marshaller, &migrate);
+    if (rcc->channel->migration_flags & SPICE_MIGRATE_NEED_FLUSH) {
+        rcc->wait_migrate_flush_mark = TRUE;
+    }
+
+    red_channel_client_begin_send_message(rcc);
+}
+
 static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
 {
     int handled = TRUE;
@@ -463,6 +477,10 @@ static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
             red_channel_client_send_set_ack(rcc);
             free(item);
             break;
+        case PIPE_ITEM_TYPE_MIGRATE:
+            red_channel_client_send_migrate(rcc);
+            free(item);
+            break;
         default:
             handled = FALSE;
     }
@@ -684,8 +702,9 @@ static void red_channel_client_default_disconnect(RedChannelClient *base)
     red_channel_client_disconnect(base);
 }
 
-static void red_channel_client_default_migrate(RedChannelClient *base)
+void red_channel_client_default_migrate(RedChannelClient *rcc)
 {
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_MIGRATE);
 }
 
 RedChannel *red_channel_create(int size,
@@ -693,7 +712,8 @@ RedChannel *red_channel_create(int size,
                                uint32_t type, uint32_t id,
                                int migrate, int handle_acks,
                                channel_handle_message_proc handle_message,
-                               ChannelCbs *channel_cbs)
+                               ChannelCbs *channel_cbs,
+                               uint32_t migration_flags)
 {
     RedChannel *channel;
     ClientCbs client_cbs = { NULL, };
@@ -701,11 +721,14 @@ RedChannel *red_channel_create(int size,
     spice_assert(size >= sizeof(*channel));
     spice_assert(channel_cbs->config_socket && channel_cbs->on_disconnect && handle_message &&
            channel_cbs->alloc_recv_buf && channel_cbs->release_item);
+    spice_assert(channel_cbs->handle_migrate_data ||
+                 !(migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
     channel = spice_malloc0(size);
     channel->type = type;
     channel->id = id;
     channel->refs = 1;
     channel->handle_acks = handle_acks;
+    channel->migration_flags = migration_flags;
     memcpy(&channel->channel_cbs, channel_cbs, sizeof(ChannelCbs));
 
     channel->core = core;
@@ -801,12 +824,14 @@ RedChannel *red_channel_create_parser(int size,
                                int migrate, int handle_acks,
                                spice_parse_channel_func_t parser,
                                channel_handle_parsed_proc handle_parsed,
-                               ChannelCbs *channel_cbs)
+                               ChannelCbs *channel_cbs,
+                               uint32_t migration_flags)
 {
     RedChannel *channel = red_channel_create(size, core, type, id,
                                              migrate, handle_acks,
                                              do_nothing_handle_message,
-                                             channel_cbs);
+                                             channel_cbs,
+                                             migration_flags);
 
     if (channel == NULL) {
         return NULL;
@@ -1089,7 +1114,12 @@ int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
     case SPICE_MSGC_DISCONNECTING:
         break;
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
+        if (!rcc->wait_migrate_flush_mark) {
+            spice_error("unexpected flush mark");
+            return FALSE;
+        }
         red_channel_handle_migrate_flush_mark(rcc);
+        rcc->wait_migrate_flush_mark = FALSE;
         break;
     case SPICE_MSGC_MIGRATE_DATA:
         red_channel_handle_migrate_data(rcc, size, message);
diff --git a/server/red_channel.h b/server/red_channel.h
index acb49cd..35d11a6 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -142,6 +142,8 @@ typedef struct MainChannelClient MainChannelClient;
  * */
 enum {
     PIPE_ITEM_TYPE_SET_ACK=1,
+    PIPE_ITEM_TYPE_MIGRATE,
+
     PIPE_ITEM_TYPE_CHANNEL_BASE=101,
 };
 
@@ -168,7 +170,7 @@ typedef void (*channel_on_incoming_error_proc)(RedChannelClient *rcc);
 typedef void (*channel_on_outgoing_error_proc)(RedChannelClient *rcc);
 
 typedef int (*channel_handle_migrate_flush_mark_proc)(RedChannelClient *base);
-typedef uint64_t (*channel_handle_migrate_data_proc)(RedChannelClient *base,
+typedef int (*channel_handle_migrate_data_proc)(RedChannelClient *base,
                                                 uint32_t size, void *message);
 typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannelClient *base,
                                             uint32_t size, void *message);
@@ -265,6 +267,7 @@ struct RedChannelClient {
     RedChannelCapabilities remote_caps;
     int is_mini_header;
     int destroying;
+    int wait_migrate_flush_mark;
 };
 
 struct RedChannel {
@@ -296,6 +299,7 @@ struct RedChannel {
     ClientCbs client_cbs;
 
     RedChannelCapabilities local_caps;
+    uint32_t migration_flags;
 
     void *data;
 
@@ -313,7 +317,8 @@ RedChannel *red_channel_create(int size,
                                uint32_t type, uint32_t id,
                                int migrate, int handle_acks,
                                channel_handle_message_proc handle_message,
-                               ChannelCbs *channel_cbs);
+                               ChannelCbs *channel_cbs,
+                               uint32_t migration_flags);
 
 /* alternative constructor, meant for marshaller based (inputs,main) channels,
  * will become default eventually */
@@ -323,7 +328,8 @@ RedChannel *red_channel_create_parser(int size,
                                int migrate, int handle_acks,
                                spice_parse_channel_func_t parser,
                                channel_handle_parsed_proc handle_parsed,
-                               ChannelCbs *channel_cbs);
+                               ChannelCbs *channel_cbs,
+                               uint32_t migration_flags);
 
 void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs);
 // caps are freed when the channel is destroyed
@@ -350,6 +356,8 @@ void red_channel_client_destroy_dummy(RedChannelClient *rcc);
 int red_channel_is_connected(RedChannel *channel);
 int red_channel_client_is_connected(RedChannelClient *rcc);
 
+void red_channel_client_default_migrate(RedChannelClient *rcc);
+
 /*
  * the disconnect callback is called from the channel's thread,
  * i.e., for display channels - red worker thread, for all the other - from the main thread.
diff --git a/server/red_worker.c b/server/red_worker.c
index bd6de1c..69cd9af 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -253,7 +253,8 @@ enum {
     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_DISPLAY_MIGRATE, /* tmp. It will be substituted with
+                                       red_channel/PIPE_ITEM_TYPE_MIGRATE */
     PIPE_ITEM_TYPE_CURSOR_INIT,
     PIPE_ITEM_TYPE_IMAGE,
     PIPE_ITEM_TYPE_STREAM_CREATE,
@@ -8909,7 +8910,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
     case PIPE_ITEM_TYPE_VERB:
         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         break;
-    case PIPE_ITEM_TYPE_MIGRATE:
+    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
         spice_info("PIPE_ITEM_TYPE_MIGRATE");
         display_channel_marshall_migrate(rcc, m);
         break;
@@ -8974,7 +8975,7 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
     case PIPE_ITEM_TYPE_VERB:
         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
         break;
-    case PIPE_ITEM_TYPE_MIGRATE:
+    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
         spice_info("PIPE_ITEM_TYPE_MIGRATE");
         cursor_channel_marshall_migrate(rcc, m);
         break;
@@ -9122,7 +9123,7 @@ static void red_migrate_display(RedWorker *worker, RedChannelClient *rcc)
     // TODO: replace all worker->display_channel tests with
     // is_connected
     if (red_channel_client_is_connected(rcc)) {
-        red_pipe_add_verb(rcc, PIPE_ITEM_TYPE_MIGRATE);
+        red_pipe_add_verb(rcc, PIPE_ITEM_TYPE_DISPLAY_MIGRATE);
 //        red_pipes_add_verb(&worker->display_channel->common.base,
 //                           SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
 //        red_channel_pipes_add_type(&worker->display_channel->common.base,
@@ -9767,7 +9768,7 @@ static uint64_t display_channel_handle_migrate_data_get_serial(
     return migrate_data->message_serial;
 }
 
-static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size,
+static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size,
                                                     void *message)
 {
     DisplayChannelMigrateData *migrate_data;
@@ -10016,6 +10017,7 @@ CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
 }
 
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type, int migrate,
+                                 int migration_flags,
                                  channel_disconnect_proc on_disconnect,
                                  channel_send_pipe_item_proc send_item,
                                  channel_hold_pipe_item_proc hold_item,
@@ -10046,7 +10048,8 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_t
                                         TRUE /* handle_acks */,
                                         spice_get_client_channel_parser(channel_type, NULL),
                                         handle_parsed,
-                                        &channel_cbs);
+                                        &channel_cbs,
+                                        migration_flags);
     common = (CommonChannel *)channel;
     if (!channel) {
         goto error;
@@ -10167,7 +10170,7 @@ static void display_channel_client_release_item_before_push(DisplayChannelClient
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
     case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_MIGRATE:
+    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
     case PIPE_ITEM_TYPE_MIGRATE_DATA:
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
@@ -10204,6 +10207,7 @@ static void display_channel_create(RedWorker *worker, int migrate)
     if (!(worker->display_channel = (DisplayChannel *)__new_channel(
             worker, sizeof(*display_channel),
             SPICE_CHANNEL_DISPLAY, migrate,
+            SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
             display_channel_client_on_disconnect,
             display_channel_send_item,
             display_channel_hold_pipe_item,
@@ -10324,7 +10328,7 @@ static void red_migrate_cursor(RedWorker *worker, RedChannelClient *rcc)
         red_channel_client_pipe_add_type(rcc,
                                          PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         red_channel_client_pipe_add_type(rcc,
-                                         PIPE_ITEM_TYPE_MIGRATE);
+                                         PIPE_ITEM_TYPE_DISPLAY_MIGRATE);
     }
 }
 
@@ -10363,7 +10367,7 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient *
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
     case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_MIGRATE:
+    case PIPE_ITEM_TYPE_DISPLAY_MIGRATE:
     case PIPE_ITEM_TYPE_CURSOR_INIT:
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
         free(item);
@@ -10410,6 +10414,7 @@ static void cursor_channel_create(RedWorker *worker, int migrate)
     worker->cursor_channel = (CursorChannel *)__new_channel(
         worker, sizeof(*worker->cursor_channel),
         SPICE_CHANNEL_CURSOR, migrate,
+        0,
         cursor_channel_client_on_disconnect,
         cursor_channel_send_item,
         cursor_channel_hold_pipe_item,
diff --git a/server/smartcard.c b/server/smartcard.c
index 7ec44cb..2ed0bde 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -679,6 +679,7 @@ static void smartcard_init(void)
 {
     ChannelCbs channel_cbs = { NULL, };
     ClientCbs client_cbs = { NULL, };
+    uint32_t migration_flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
 
     spice_assert(!g_smartcard_channel);
 
@@ -695,7 +696,8 @@ static void smartcard_init(void)
                                              FALSE /* migration - TODO?*/,
                                              FALSE /* handle_acks */,
                                              smartcard_channel_handle_message,
-                                             &channel_cbs);
+                                             &channel_cbs,
+                                             migration_flags);
 
     if (!g_smartcard_channel) {
         spice_error("failed to allocate Smartcard Channel");
diff --git a/server/spicevmc.c b/server/spicevmc.c
index b96bf9f..36d901f 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -343,7 +343,8 @@ SpiceCharDeviceState *spicevmc_device_connect(SpiceCharDeviceInstance *sin,
                                    FALSE /* migration - TODO? */,
                                    FALSE /* handle_acks */,
                                    spicevmc_red_channel_client_handle_message,
-                                   &channel_cbs);
+                                   &channel_cbs,
+                                   SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
     red_channel_init_outgoing_messages_window(&state->channel);
 
     client_cbs.connect = spicevmc_connect;
commit 4f551a3550cf0d54e682e50ccddb446d15732bbe
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 13:12:58 2012 +0300

    red_channel: fix pipe item leak

diff --git a/server/red_channel.c b/server/red_channel.c
index 1cad9eb..a108bc2 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -461,6 +461,7 @@ static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
     switch (item->type) {
         case PIPE_ITEM_TYPE_SET_ACK:
             red_channel_client_send_set_ack(rcc);
+            free(item);
             break;
         default:
             handled = FALSE;
commit bb8c90d8c21729abd7c87f81fb6f3a855e501814
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Jul 5 11:50:18 2012 +0300

    seamleass migration: manage post migration phase in the src side
    
    In semi-seamless, SPICE_MSG_MAIN_MIGRATE_END is sent.
    In seamless, each channel migrates separately.
    
    The src waits till all the clients are disconnected (or a timeout), and
    then it notifies qemu that spice migration has completed.
    
    The patch doesn't include the per-channel logic for seamless migration
    (sending MSG_MIGRATE, MIGRATE_DATA, etc.).

diff --git a/server/reds.c b/server/reds.c
index 08836fd..19e72bd 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -221,6 +221,11 @@ typedef struct RedsMigTargetClient {
     Ring pending_links;
 } RedsMigTargetClient;
 
+typedef struct RedsMigWaitDisconnectClient {
+    RingItem link;
+    RedClient *client;
+} RedsMigWaitDisconnectClient;
+
 typedef struct SpiceCharDeviceStateItem {
     RingItem link;
     SpiceCharDeviceState *st;
@@ -237,8 +242,12 @@ typedef struct RedsState {
     int num_clients;
     MainChannel *main_channel;
 
-    int mig_wait_connect;
-    int mig_wait_disconnect;
+    int mig_wait_connect; /* src waits for clients to establish connection to dest
+                             (before migration starts) */
+    int mig_wait_disconnect; /* src waits for clients to disconnect (after migration completes) */
+    Ring mig_wait_disconnect_clients; /* List of RedsMigWaitDisconnectClient. Holds the clients
+                                         which the src waits for their disconnection */
+
     int mig_inprogress;
     int expect_migrate;
     int src_do_seamless_migrate; /* per migration. Updated after the migration handshake
@@ -248,6 +257,7 @@ typedef struct RedsState {
     Ring mig_target_clients;
     int num_mig_target_clients;
     RedsMigSpice *mig_spice;
+
     int num_of_channels;
     Ring channels;
     int mouse_mode;
@@ -314,6 +324,8 @@ struct ChannelSecurityOptions {
 static void migrate_timeout(void *opaque);
 static RedsMigTargetClient* reds_mig_target_client_find(RedClient *client);
 static void reds_mig_target_client_free(RedsMigTargetClient *mig_client);
+static void reds_mig_cleanup_wait_disconnect(void);
+static void reds_mig_remove_wait_disconnect_client(RedClient *client);
 static void reds_char_device_add_state(SpiceCharDeviceState *st);
 static void reds_char_device_remove_state(SpiceCharDeviceState *st);
 
@@ -583,16 +595,24 @@ static RedChannel *reds_find_channel(uint32_t type, uint32_t id)
 static void reds_mig_cleanup(void)
 {
     if (reds->mig_inprogress) {
-        if (reds->mig_wait_connect) {
+
+        if (reds->mig_wait_connect || reds->mig_wait_disconnect) {
             SpiceMigrateInterface *sif;
             spice_assert(migration_interface);
             sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
-            sif->migrate_connect_complete(migration_interface);
+            if (reds->mig_wait_connect) {
+                sif->migrate_connect_complete(migration_interface);
+            } else {
+                if (sif->migrate_end_complete) {
+                    sif->migrate_end_complete(migration_interface);
+                }
+            }
         }
         reds->mig_inprogress = FALSE;
         reds->mig_wait_connect = FALSE;
         reds->mig_wait_disconnect = FALSE;
         core->timer_cancel(reds->mig_timer);
+        reds_mig_cleanup_wait_disconnect();
     }
 }
 
@@ -669,6 +689,10 @@ void reds_client_disconnect(RedClient *client)
         reds_mig_target_client_free(mig_client);
     }
 
+    if (reds->mig_wait_disconnect) {
+        reds_mig_remove_wait_disconnect_client(client);
+    }
+
     if (reds->agent_state.base) {
         /* note that vdagent might be NULL, if the vdagent was once
          * up and than was removed */
@@ -3104,19 +3128,85 @@ static void reds_mig_started(void)
     core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 }
 
+static void reds_mig_fill_wait_disconnect(void)
+{
+    RingItem *client_item;
+
+    spice_assert(reds->num_clients > 0);
+    /* tracking the clients, in order to ignore disconnection
+     * of clients that got connected to the src after migration completion.*/
+    RING_FOREACH(client_item, &reds->clients) {
+        RedClient *client = SPICE_CONTAINEROF(client_item, RedClient, link);
+        RedsMigWaitDisconnectClient *wait_client;
+
+        wait_client = spice_new0(RedsMigWaitDisconnectClient, 1);
+        wait_client->client = client;
+        ring_add(&reds->mig_wait_disconnect_clients, &wait_client->link);
+    }
+    reds->mig_wait_disconnect = TRUE;
+    core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
+}
+
+static void reds_mig_cleanup_wait_disconnect(void)
+{
+    RingItem *wait_client_item;
+
+    while ((wait_client_item = ring_get_tail(&reds->mig_wait_disconnect_clients))) {
+        RedsMigWaitDisconnectClient *wait_client;
+
+        wait_client = SPICE_CONTAINEROF(wait_client_item, RedsMigWaitDisconnectClient, link);
+        ring_remove(wait_client_item);
+        free(wait_client);
+    }
+    reds->mig_wait_disconnect = FALSE;
+}
+
+static void reds_mig_remove_wait_disconnect_client(RedClient *client)
+{
+    RingItem *wait_client_item;
+
+    RING_FOREACH(wait_client_item, &reds->mig_wait_disconnect_clients) {
+        RedsMigWaitDisconnectClient *wait_client;
+
+        wait_client = SPICE_CONTAINEROF(wait_client_item, RedsMigWaitDisconnectClient, link);
+        if (wait_client->client == client) {
+            ring_remove(wait_client_item);
+            free(wait_client);
+            if (ring_is_empty(&reds->mig_wait_disconnect_clients)) {
+                reds_mig_cleanup();
+            }
+            return;
+        }
+    }
+    spice_warning("client not found %p", client);
+}
+
+static void reds_migrate_channels_seamless(void)
+{
+    RingItem *client_item;
+    RedClient *client;
+
+    /* seamless migration is supported for only one client for now */
+    spice_assert(reds->num_clients == 1);
+    client_item = ring_get_head(&reds->clients);
+    client = SPICE_CONTAINEROF(client_item, RedClient, link);
+    red_client_migrate(client);
+}
+
 static void reds_mig_finished(int completed)
 {
     spice_info(NULL);
 
-    if (!reds_main_channel_connected()) {
-        spice_warning("no peer connected");
-        return;
-    }
     reds->mig_inprogress = TRUE;
 
-    if (main_channel_migrate_complete(reds->main_channel, completed)) {
-        reds->mig_wait_disconnect = TRUE;
-        core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
+    if (reds->src_do_seamless_migrate && completed) {
+        reds_migrate_channels_seamless();
+    } else {
+        main_channel_migrate_complete(reds->main_channel, completed);
+    }
+
+    if (completed) {
+        reds_mig_fill_wait_disconnect();
     } else {
         reds_mig_cleanup();
     }
@@ -3532,6 +3622,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     ring_init(&reds->channels);
     ring_init(&reds->mig_target_clients);
     ring_init(&reds->char_devs_states);
+    ring_init(&reds->mig_wait_disconnect_clients);
     reds->vm_running = TRUE; /* for backward compatibility */
 
     if (!(reds->mig_timer = core->timer_add(migrate_timeout, NULL))) {
@@ -4053,7 +4144,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_end(SpiceServer *s, int completed)
     spice_assert(reds == s);
 
     sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
-    if (!reds->expect_migrate && reds->num_clients) {
+    if (completed && !reds->expect_migrate && reds->num_clients) {
         spice_error("spice_server_migrate_info was not called, disconnecting clients");
         reds_disconnect();
         ret = -1;
@@ -4061,8 +4152,12 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_end(SpiceServer *s, int completed)
     }
 
     reds->expect_migrate = FALSE;
+    if (!reds_main_channel_connected()) {
+        spice_info("no peer connected");
+        goto complete;
+    }
     reds_mig_finished(completed);
-    ret = 0;
+    return 0;
 complete:
     if (sif->migrate_end_complete) {
         sif->migrate_end_complete(migration_interface);
commit 8e2576d5ab2f0c2089a74edbb5e3a9c2bfbfb06a
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 11:19:30 2012 +0300

    seamless migration: pre migration phase on the destination side
    
    - handle SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS
    - reply with SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK/NACK
    - prepare the channels for migration according to the migration
       type (semi/seamless)
    
    see spice-protocol for more details:
    commit 3838ad140a046c4ddf42fef58c9727ecfdc09f9f

diff --git a/server/main_channel.c b/server/main_channel.c
index 2d7cb02..6123068 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -790,9 +790,9 @@ static void main_channel_release_pipe_item(RedChannelClient *rcc,
     free(base);
 }
 
-void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
-                                                  int success,
-                                                  int seamless)
+static void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
+                                                         int success,
+                                                         int seamless)
 {
     spice_printerr("client %p connected: %d seamless %d", mcc->base.client, success, seamless);
     if (mcc->mig_wait_connect) {
@@ -813,6 +813,18 @@ void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
     }
 }
 
+void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
+                                                        uint32_t src_version)
+{
+    if (reds_on_migrate_dst_set_seamless(mcc, src_version)) {
+        red_channel_client_pipe_add_type(&mcc->base,
+                                         SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
+    } else {
+        red_channel_client_pipe_add_type(&mcc->base,
+                                         SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK);
+    }
+}
+
 void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
 {
     if (!red_client_during_migrate_at_target(mcc->base.client)) {
@@ -882,6 +894,10 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
     case SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR:
         main_channel_client_handle_migrate_connected(mcc, FALSE, FALSE);
         break;
+    case SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS:
+        main_channel_client_handle_migrate_dst_do_seamless(mcc,
+            ((SpiceMsgcMainMigrateDstDoSeamless *)message)->src_version);
+        break;
     case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
         reds_on_main_mouse_mode_request(message, size);
         break;
@@ -1125,6 +1141,7 @@ MainChannel* main_channel_init(void)
                                         &channel_cbs);
     spice_assert(channel);
     red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
+
     return (MainChannel *)channel;
 }
 
diff --git a/server/reds.c b/server/reds.c
index 074a19d..08836fd 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -67,6 +67,7 @@
 #include "stat.h"
 #include "demarshallers.h"
 #include "char_device.h"
+#include "migration_protocol.h"
 #ifdef USE_TUNNEL
 #include "red_tunnel_worker.h"
 #endif
@@ -242,6 +243,8 @@ typedef struct RedsState {
     int expect_migrate;
     int src_do_seamless_migrate; /* per migration. Updated after the migration handshake
                                     between the 2 servers */
+    int dst_do_seamless_migrate; /* per migration. Updated after the migration handshake
+                                    between the 2 servers */
     Ring mig_target_clients;
     int num_mig_target_clients;
     RedsMigSpice *mig_spice;
@@ -256,7 +259,7 @@ typedef struct RedsState {
 
     int vm_running;
     Ring char_devs_states; /* list of SpiceCharDeviceStateItem */
-    int seamless_migration_enabled;
+    int seamless_migration_enabled; /* command line arg */
 
     SSL_CTX *ctx;
 
@@ -1548,26 +1551,28 @@ static void reds_channel_do_link(RedChannel *channel, RedClient *client,
                                 caps + link_msg->num_common_caps : NULL);
 }
 
-void reds_on_client_migrate_complete(RedClient *client)
+/*
+ * migration target side:
+ * In semi-seamless migration, we activate the channels only
+ * after migration is completed.
+ * In seamless migration, in order to keep the continuousness, and
+ * not lose any data, we activate the target channels before
+ * migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS
+ */
+static int reds_link_mig_target_channels(RedClient *client)
 {
     RedsMigTargetClient *mig_client;
-    MainChannelClient *mcc;
     RingItem *item;
 
     spice_info("%p", client);
-    mcc = red_client_get_main(client);
     mig_client = reds_mig_target_client_find(client);
     if (!mig_client) {
-        spice_warning("mig target client was not found");
-        return;
+        spice_info("Error: mig target client was not found");
+        return FALSE;
     }
 
-    // TODO: not doing net test. consider doing it on client_migrate_info
-    main_channel_push_init(mcc, red_dispatcher_count(),
-                           reds->mouse_mode, reds->is_client_mouse_allowed,
-                           reds_get_mm_time() - MM_TIME_DELTA,
-                           red_dispatcher_qxl_ram_size());
-
+    /* Each channel should check if we are during migration, and
+     * act accordingly. */
     RING_FOREACH(item, &mig_client->pending_links) {
         RedsMigPendingLink *mig_link;
         RedChannel *channel;
@@ -1586,6 +1591,40 @@ void reds_on_client_migrate_complete(RedClient *client)
     }
 
     reds_mig_target_client_free(mig_client);
+
+    return TRUE;
+}
+
+int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version)
+{
+    /* seamless migration is not supported with multiple clients*/
+    if (reds->allow_multiple_clients  || src_version > SPICE_MIGRATION_PROTOCOL_VERSION) {
+        reds->dst_do_seamless_migrate = FALSE;
+    } else {
+        RedClient *client;
+
+        client = main_channel_client_get_base(mcc)->client;
+        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
+        /* linking all the channels that have been connected before migration handshake */
+        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
+    }
+    return reds->dst_do_seamless_migrate;
+}
+
+/* semi seamless */
+void reds_on_client_migrate_complete(RedClient *client)
+{
+    MainChannelClient *mcc;
+
+    spice_info("%p", client);
+    mcc = red_client_get_main(client);
+
+    // TODO: not doing net test. consider doing it on client_migrate_info
+    main_channel_push_init(mcc, red_dispatcher_count(),
+                           reds->mouse_mode, reds->is_client_mouse_allowed,
+                           reds_get_mm_time() - MM_TIME_DELTA,
+                           red_dispatcher_qxl_ram_size());
+    reds_link_mig_target_channels(client);
 }
 
 static void reds_handle_other_links(RedLinkInfo *link)
@@ -1623,7 +1662,17 @@ static void reds_handle_other_links(RedLinkInfo *link)
     reds_stream_remove_watch(link->stream);
 
     mig_client = reds_mig_target_client_find(client);
-    if (red_client_during_migrate_at_target(client)) {
+    /*
+     * In semi-seamless migration, we activate the channels only
+     * after migration is completed. Since, the session starts almost from
+     * scratch we don't mind if we skip some messages in between the src session end and
+     * dst session start.
+     * In seamless migration, in order to keep the continuousness of the session, and
+     * in order not to lose any data, we activate the target channels before
+     * migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS.
+     * If a channel connects before receiving SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS,
+     * reds_on_migrate_dst_set_seamless will take care of activating it */
+    if (red_client_during_migrate_at_target(client) && !reds->dst_do_seamless_migrate) {
         spice_assert(mig_client);
         reds_mig_target_client_add_pending_link(mig_client, link_mess, link->stream);
     } else {
diff --git a/server/reds.h b/server/reds.h
index b3a3155..71a0173 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -154,6 +154,9 @@ void reds_on_main_migrate_connected(int seamless); //should be called when all t
                                                    // are connected to the target
 void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end);
 void reds_on_main_mouse_mode_request(void *message, size_t size);
+/* migration dest side: returns whether it can support seamless migration
+ * with the given src migration protocol version */
+int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version);
 void reds_on_client_migrate_complete(RedClient *client);
 void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
commit 43e0897da5dd880fa9c2df5dd34d9de1ab13b862
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Jul 4 16:23:58 2012 +0300

    seamless migration: pre migration phase on the src side
    
    sending SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS and handling
    SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS
    
    The src side signals the client to establish a connection
    to the destination.
    In seamless migration, the client is also used to perform
    a sort of handshake with the destination, for verifying
    if seamless migration can be supported.
    
    see spice-protocol for more details:
    commit 3838ad140a046c4ddf42fef58c9727ecfdc09f9f

diff --git a/server/main_channel.c b/server/main_channel.c
index 25eaf18..2d7cb02 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -45,6 +45,7 @@
 #include "red_channel.h"
 #include "red_common.h"
 #include "reds.h"
+#include "migration_protocol.h"
 
 #define ZERO_BUF_SIZE 4096
 
@@ -135,6 +136,7 @@ struct MainChannelClient {
     int mig_wait_connect;
     int mig_connect_ok;
     int mig_wait_prev_complete;
+    int mig_wait_prev_try_seamless;
     int init_sent;
 };
 
@@ -576,26 +578,45 @@ static void main_channel_marshall_notify(SpiceMarshaller *m, NotifyPipeItem *ite
     spice_marshaller_add(m, item->mess, item->mess_len + 1);
 }
 
+static void main_channel_fill_migrate_dst_info(MainChannel *main_channel,
+                                               SpiceMigrationDstInfo *dst_info)
+{
+    RedsMigSpice *mig_dst = &main_channel->mig_target;
+    dst_info->port = mig_dst->port;
+    dst_info->sport = mig_dst->sport;
+    dst_info->host_size = strlen(mig_dst->host) + 1;
+    dst_info->host_data = (uint8_t *)mig_dst->host;
+    if (mig_dst->cert_subject) {
+        dst_info->cert_subject_size = strlen(mig_dst->cert_subject) + 1;
+        dst_info->cert_subject_data = (uint8_t *)mig_dst->cert_subject;
+    } else {
+        dst_info->cert_subject_size = 0;
+        dst_info->cert_subject_data = NULL;
+    }
+}
+
 static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelClient *rcc)
 {
     SpiceMsgMainMigrationBegin migrate;
     MainChannel *main_ch;
 
     main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
-    migrate.dst_info.port = main_ch->mig_target.port;
-    migrate.dst_info.sport = main_ch->mig_target.sport;
-    migrate.dst_info.host_size = strlen(main_ch->mig_target.host) + 1;
-    migrate.dst_info.host_data = (uint8_t *)main_ch->mig_target.host;
-    if (main_ch->mig_target.cert_subject) {
-        migrate.dst_info.cert_subject_size = strlen(main_ch->mig_target.cert_subject) + 1;
-        migrate.dst_info.cert_subject_data = (uint8_t *)main_ch->mig_target.cert_subject;
-    } else {
-        migrate.dst_info.cert_subject_size = 0;
-        migrate.dst_info.cert_subject_data = NULL;
-    }
+    main_channel_fill_migrate_dst_info(main_ch, &migrate.dst_info);
     spice_marshall_msg_main_migrate_begin(m, &migrate);
 }
 
+static void main_channel_marshall_migrate_begin_seamless(SpiceMarshaller *m,
+                                                         RedChannelClient *rcc)
+{
+    SpiceMsgMainMigrateBeginSeamless migrate_seamless;
+    MainChannel *main_ch;
+
+    main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
+    main_channel_fill_migrate_dst_info(main_ch, &migrate_seamless.dst_info);
+    migrate_seamless.src_mig_version = SPICE_MIGRATION_PROTOCOL_VERSION;
+    spice_marshall_msg_main_migrate_begin_seamless(m, &migrate_seamless);
+}
+
 void main_channel_push_migrate(MainChannel *main_chan)
 {
     red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MIGRATE);
@@ -728,6 +749,9 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
         case SPICE_MSG_MAIN_MIGRATE_BEGIN:
             main_channel_marshall_migrate_begin(m, rcc);
             break;
+        case SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS:
+            main_channel_marshall_migrate_begin_seamless(m, rcc);
+            break;
         case SPICE_MSG_MAIN_MULTI_MEDIA_TIME:
             main_channel_marshall_multi_media_time(m,
                 SPICE_CONTAINEROF(base, MultiMediaTimePipeItem, base));
@@ -766,17 +790,20 @@ static void main_channel_release_pipe_item(RedChannelClient *rcc,
     free(base);
 }
 
-void main_channel_client_handle_migrate_connected(MainChannelClient *mcc, int success)
+void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
+                                                  int success,
+                                                  int seamless)
 {
-    spice_printerr("client %p connected: %d", mcc->base.client, success);
+    spice_printerr("client %p connected: %d seamless %d", mcc->base.client, success, seamless);
     if (mcc->mig_wait_connect) {
         MainChannel *main_channel = SPICE_CONTAINEROF(mcc->base.channel, MainChannel, base);
 
         mcc->mig_wait_connect = FALSE;
         mcc->mig_connect_ok = success;
         spice_assert(main_channel->num_clients_mig_wait);
+        spice_assert(!seamless || main_channel->num_clients_mig_wait == 1);
         if (!--main_channel->num_clients_mig_wait) {
-            reds_on_main_migrate_connected();
+            reds_on_main_migrate_connected(seamless && success);
         }
     } else {
         if (success) {
@@ -800,7 +827,12 @@ void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
     }
     red_client_migrate_complete(mcc->base.client);
     if (mcc->mig_wait_prev_complete) {
-        red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
+
+        if (mcc->mig_wait_prev_try_seamless) {
+            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS);
+        } else {
+            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
+        }
         mcc->mig_wait_connect = TRUE;
         mcc->mig_wait_prev_complete = FALSE;
     }
@@ -838,10 +870,17 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
         main_channel_push_channels(mcc);
         break;
     case SPICE_MSGC_MAIN_MIGRATE_CONNECTED:
-        main_channel_client_handle_migrate_connected(mcc, TRUE);
+        main_channel_client_handle_migrate_connected(mcc,
+                                                     TRUE /* success */,
+                                                     FALSE /* seamless */);
+        break;
+    case SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS:
+        main_channel_client_handle_migrate_connected(mcc,
+                                                     TRUE /* success */,
+                                                     TRUE /* seamless */);
         break;
     case SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR:
-        main_channel_client_handle_migrate_connected(mcc, FALSE);
+        main_channel_client_handle_migrate_connected(mcc, FALSE, FALSE);
         break;
     case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
         reds_on_main_mouse_mode_request(message, size);
@@ -1095,13 +1134,10 @@ RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc)
     return &mcc->base;
 }
 
-int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_target)
+static int main_channel_connect_semi_seamless(MainChannel *main_channel)
 {
     RingItem *client_link;
 
-    main_channel_fill_mig_target(main_channel, mig_target);
-    main_channel->num_clients_mig_wait = 0;
-
     RING_FOREACH(client_link, &main_channel->base.clients) {
         MainChannelClient * mcc = SPICE_CONTAINEROF(client_link, MainChannelClient,
                                                     base.channel_link);
@@ -1110,6 +1146,7 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
             if (red_client_during_migrate_at_target(mcc->base.client)) {
                 spice_printerr("client %p: wait till previous migration completes", mcc->base.client);
                 mcc->mig_wait_prev_complete = TRUE;
+                mcc->mig_wait_prev_try_seamless = FALSE;
             } else {
                 red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
                 mcc->mig_wait_connect = TRUE;
@@ -1121,6 +1158,60 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
     return main_channel->num_clients_mig_wait;
 }
 
+static int main_channel_connect_seamless(MainChannel *main_channel)
+{
+    RingItem *client_link;
+
+    spice_assert(main_channel->base.clients_num == 1);
+
+    RING_FOREACH(client_link, &main_channel->base.clients) {
+        MainChannelClient * mcc = SPICE_CONTAINEROF(client_link, MainChannelClient,
+                                                    base.channel_link);
+        spice_assert(red_channel_client_test_remote_cap(&mcc->base,
+                                                        SPICE_MAIN_CAP_SEAMLESS_MIGRATE));
+        if (red_client_during_migrate_at_target(mcc->base.client)) {
+           spice_printerr("client %p: wait till previous migration completes", mcc->base.client);
+           mcc->mig_wait_prev_complete = TRUE;
+           mcc->mig_wait_prev_try_seamless = TRUE;
+        } else {
+            red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS);
+            mcc->mig_wait_connect = TRUE;
+        }
+        mcc->mig_connect_ok = FALSE;
+        main_channel->num_clients_mig_wait++;
+    }
+    return main_channel->num_clients_mig_wait;
+}
+
+int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_target,
+                                 int try_seamless)
+{
+    main_channel_fill_mig_target(main_channel, mig_target);
+    main_channel->num_clients_mig_wait = 0;
+
+    if (!main_channel_is_connected(main_channel)) {
+        return 0;
+    }
+
+    if (!try_seamless) {
+        return main_channel_connect_semi_seamless(main_channel);
+    } else {
+        RingItem *client_item;
+        MainChannelClient *mcc;
+
+        client_item = ring_get_head(&main_channel->base.clients);
+        mcc = SPICE_CONTAINEROF(client_item, MainChannelClient, base.channel_link);
+
+        if (!red_channel_client_test_remote_cap(&mcc->base,
+                                                SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
+            return main_channel_connect_semi_seamless(main_channel);
+        } else {
+            return main_channel_connect_seamless(main_channel);
+        }
+    }
+
+}
+
 void main_channel_migrate_cancel_wait(MainChannel *main_chan)
 {
     RingItem *client_link;
diff --git a/server/main_channel.h b/server/main_channel.h
index b69dcfe..40d2215 100644
--- a/server/main_channel.h
+++ b/server/main_channel.h
@@ -98,8 +98,10 @@ void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_targe
 
 /* semi seamless migration */
 
-/* returns the number of clients that we are waiting for their connection */
-int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_target);
+/* returns the number of clients that we are waiting for their connection.
+ * try_seamless = 'true' when the seamless-migration=on in qemu command line */
+int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_target,
+                                 int try_seamless);
 void main_channel_migrate_cancel_wait(MainChannel *main_chan);
 /* returns the number of clients for which SPICE_MSG_MAIN_MIGRATE_END was sent*/
 int main_channel_migrate_complete(MainChannel *main_chan, int success);
diff --git a/server/reds.c b/server/reds.c
index 6397b41..074a19d 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -240,6 +240,8 @@ typedef struct RedsState {
     int mig_wait_disconnect;
     int mig_inprogress;
     int expect_migrate;
+    int src_do_seamless_migrate; /* per migration. Updated after the migration handshake
+                                    between the 2 servers */
     Ring mig_target_clients;
     int num_mig_target_clients;
     RedsMigSpice *mig_spice;
@@ -1163,8 +1165,9 @@ void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size)
     spice_char_device_write_buffer_add(reds->agent_state.base, dev_state->recv_from_client_buf);
 }
 
-void reds_on_main_migrate_connected(void)
+void reds_on_main_migrate_connected(int seamless)
 {
+    reds->src_do_seamless_migrate = seamless;
     if (reds->mig_wait_connect) {
         reds_mig_cleanup();
     }
@@ -3938,7 +3941,8 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char*
     reds->expect_migrate = TRUE;
 
     /* main channel will take care of clients that are still during migration (at target)*/
-    if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice)) {
+    if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice,
+                                     reds->seamless_migration_enabled)) {
         reds_mig_started();
     } else {
         if (reds->num_clients == 0) {
diff --git a/server/reds.h b/server/reds.h
index 87125d2..b3a3155 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -150,8 +150,8 @@ void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens);
 uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size);
 void reds_release_agent_data_buffer(uint8_t *buf);
 void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size);
-void reds_on_main_migrate_connected(void); //should be called when all the clients
-                                           // are connected to the target
+void reds_on_main_migrate_connected(int seamless); //should be called when all the clients
+                                                   // are connected to the target
 void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end);
 void reds_on_main_mouse_mode_request(void *message, size_t size);
 void reds_on_client_migrate_complete(RedClient *client);
commit 35cf65a45e5327966d19cd5db0cb2c91bb828abe
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 09:54:46 2012 +0300

    seamless-migration: update spice-common submodule
    
    Also Update server and client according to the change of
    SpiceMsgMainMigrationBegin: it now holds all the fields inside
    SpiceMigrationDstInfo.

diff --git a/client/red_client.cpp b/client/red_client.cpp
index 8f86d3e..6a71291 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -291,20 +291,20 @@ void Migrate::start(const SpiceMsgMainMigrationBegin* migrate)
         _sport = old_migrate->sport ? old_migrate->sport : -1;;
         _auth_options = _client.get_host_auth_options();
     } else {
-        _host.assign((char *)migrate->host_data);
-        _port = migrate->port ? migrate->port : -1;
-        _sport = migrate->sport ? migrate->sport : -1;
+        _host.assign((char *)migrate->dst_info.host_data);
+        _port = migrate->dst_info.port ? migrate->dst_info.port : -1;
+        _sport = migrate->dst_info.sport ? migrate->dst_info.sport : -1;
         if ((peer_major == 1) || (peer_major == 2 && peer_minor < 1)) {
             _auth_options.type_flags = SPICE_SSL_VERIFY_OP_PUBKEY;
-            _auth_options.host_pubkey.assign(migrate->pub_key_data, migrate->pub_key_data +
-                                             migrate->pub_key_size);
+            _auth_options.host_pubkey.assign(migrate->dst_info.pub_key_data, migrate->dst_info.pub_key_data +
+                                             migrate->dst_info.pub_key_size);
         } else {
             _auth_options.type_flags = SPICE_SSL_VERIFY_OP_SUBJECT;
             _auth_options.CA_file =  _client.get_host_auth_options().CA_file;
-            if (migrate->cert_subject_size != 0) {
-                _auth_options.host_subject.assign(migrate->cert_subject_data,
-                                                  migrate->cert_subject_data +
-                                                  migrate->cert_subject_size);
+            if (migrate->dst_info.cert_subject_size != 0) {
+                _auth_options.host_subject.assign(migrate->dst_info.cert_subject_data,
+                                                  migrate->dst_info.cert_subject_data +
+                                                  migrate->dst_info.cert_subject_size);
             }
         }
     }
diff --git a/server/main_channel.c b/server/main_channel.c
index 0d948de..25eaf18 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -582,16 +582,16 @@ static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelCl
     MainChannel *main_ch;
 
     main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
-    migrate.port = main_ch->mig_target.port;
-    migrate.sport = main_ch->mig_target.sport;
-    migrate.host_size = strlen(main_ch->mig_target.host) + 1;
-    migrate.host_data = (uint8_t *)main_ch->mig_target.host;
+    migrate.dst_info.port = main_ch->mig_target.port;
+    migrate.dst_info.sport = main_ch->mig_target.sport;
+    migrate.dst_info.host_size = strlen(main_ch->mig_target.host) + 1;
+    migrate.dst_info.host_data = (uint8_t *)main_ch->mig_target.host;
     if (main_ch->mig_target.cert_subject) {
-        migrate.cert_subject_size = strlen(main_ch->mig_target.cert_subject) + 1;
-        migrate.cert_subject_data = (uint8_t *)main_ch->mig_target.cert_subject;
+        migrate.dst_info.cert_subject_size = strlen(main_ch->mig_target.cert_subject) + 1;
+        migrate.dst_info.cert_subject_data = (uint8_t *)main_ch->mig_target.cert_subject;
     } else {
-        migrate.cert_subject_size = 0;
-        migrate.cert_subject_data = NULL;
+        migrate.dst_info.cert_subject_size = 0;
+        migrate.dst_info.cert_subject_data = NULL;
     }
     spice_marshall_msg_main_migrate_begin(m, &migrate);
 }
diff --git a/spice-common b/spice-common
index c6bd210..c2f5849 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit c6bd210ad0b6eb485fda25426ab9d75253439f54
+Subproject commit c2f58492ad2df22c4eb4e6c04750010113dce567
commit 70f820ded2817b754947631e542e648e3f7d1d23
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Aug 2 09:21:20 2012 +0300

    seamless-migration: add migration_protocol.h
    
    The file will hold the declarations of the different migration
    data messages (depending on the channel), that will be passed
    from the src server to the dst server, via the client, using
    SPICE_MSG_MIGRATE_DATA.

diff --git a/server/Makefile.am b/server/Makefile.am
index e7b4977..16c8b6d 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -72,6 +72,7 @@ libspice_server_la_SOURCES =			\
 	red_dispatcher.h			\
 	main_dispatcher.c			\
 	main_dispatcher.h			\
+	migration_protocol.h		\
 	red_memslots.c				\
 	red_memslots.h				\
 	red_parse_qxl.c				\
diff --git a/server/migration_protocol.h b/server/migration_protocol.h
new file mode 100644
index 0000000..2b7f4c2
--- /dev/null
+++ b/server/migration_protocol.h
@@ -0,0 +1,49 @@
+/*
+   Copyright (C) 2012 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_MIGRATION_PROTOCOL
+#define _H_MIGRATION_PROTOCOL
+
+/* ************************************************
+ * src-server to dst-server migration data messages
+ * ************************************************/
+
+/* increase the version when the version of any
+ * of the migration data messages is increased */
+#define SPICE_MIGRATION_PROTOCOL_VERSION ~0
+
+typedef struct __attribute__ ((__packed__)) SpiceMigrateDataHeader {
+    uint32_t magic;
+    uint32_t version;
+} SpiceMigrateDataHeader;
+
+static inline int migration_protocol_validate_header(SpiceMigrateDataHeader *header,
+                                                     uint32_t magic,
+                                                     uint32_t version)
+{
+    if (header->magic != magic) {
+        spice_error("bad magic %u (!= %u)", header->magic, magic);
+        return FALSE;
+    }
+    if (header->version > version) {
+        spice_error("unsupported version %u (> %u)", header->version, version);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+#endif
commit 92f3ee6ed8cf8b6694a2216f30004a3e09445a20
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Aug 1 21:45:14 2012 +0300

    bump version to 0.11.2
    
    New api entries:
        spice_server_vm_start
        spice_server_vm_stop
        spice_server_set_seamless_migration

diff --git a/configure.ac b/configure.ac
index bed0464..7bd4313 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@ AC_PREREQ([2.57])
 
 m4_define([SPICE_MAJOR], 0)
 m4_define([SPICE_MINOR], 11)
-m4_define([SPICE_MICRO], 1)
+m4_define([SPICE_MICRO], 2)
 m4_define([SPICE_CURRENT], [3])
 m4_define([SPICE_REVISION], [0])
 m4_define([SPICE_AGE], [2])
diff --git a/server/spice-server.syms b/server/spice-server.syms
index a45951c..359791c 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -116,3 +116,10 @@ SPICE_SERVER_0.10.3 {
 SPICE_SERVER_0.10.4 {
     spice_qxl_monitors_config_async;
 } SPICE_SERVER_0.10.3;
+
+SPICE_SERVER_0.11.2 {
+global:
+    spice_server_vm_start;
+    spice_server_vm_stop;
+    spice_server_set_seamless_migration;
+} SPICE_SERVER_0.10.4;
diff --git a/server/spice.h b/server/spice.h
index ab1caed..0dc9d05 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -22,7 +22,7 @@
 #include <sys/socket.h>
 #include <spice/qxl_dev.h>
 
-#define SPICE_SERVER_VERSION 0x000b01 /* release 0.11.1 */
+#define SPICE_SERVER_VERSION 0x000b02 /* release 0.11.2 */
 
 /* interface base type */
 
commit f45fb9e1b66f691da7432377e0ff4000bccc1aa9
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Jul 2 10:49:19 2012 +0300

    spice.h: add spice_server_set_seamless_migration
    
    This new call is used in order to identify whether qemu, or
    the management (e.g. libvirt), support seamless migration.
    If it is supported, qemu spice cmd-line configuration should have
    seamless-migration=on.
    
    In addition, we disable seamless migration support if multiple clients
    are allowed. Currently, only one client is supported.

diff --git a/server/reds.c b/server/reds.c
index 416dff4..6397b41 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -254,6 +254,7 @@ typedef struct RedsState {
 
     int vm_running;
     Ring char_devs_states; /* list of SpiceCharDeviceStateItem */
+    int seamless_migration_enabled;
 
     SSL_CTX *ctx;
 
@@ -4059,6 +4060,14 @@ SPICE_GNUC_VISIBLE void spice_server_vm_stop(SpiceServer *s)
     red_dispatcher_on_vm_stop();
 }
 
+SPICE_GNUC_VISIBLE void spice_server_set_seamless_migration(SpiceServer *s, int enable)
+{
+    spice_assert(s == reds);
+    /* seamless migration is not supported with multiple clients */
+    reds->seamless_migration_enabled = enable && !reds->allow_multiple_clients;
+    spice_debug("seamless migration enabled=%d", enable);
+}
+
 ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
 {
     ssize_t ret;
diff --git a/server/spice.h b/server/spice.h
index fb51a47..ab1caed 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -527,6 +527,8 @@ int spice_server_migrate_connect(SpiceServer *s, const char* dest,
 int spice_server_migrate_start(SpiceServer *s);
 int spice_server_migrate_end(SpiceServer *s, int completed);
 
+void spice_server_set_seamless_migration(SpiceServer *s, int enable);
+
 void spice_server_set_name(SpiceServer *s, const char *name);
 void spice_server_set_uuid(SpiceServer *s, const uint8_t uuid[16]);
 
commit 2a1369c91966450424910d51f39e4b57a7c8973f
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Aug 20 13:49:00 2012 +0300

    spice_server_vm_start/stop: notify red_dispatcher on vm start/stop
    
    Till now, red_worker was notfied about vm status changes via QXLWorker->start/stop
    (or spice_qxl_start/stop).
    Newer qemu, that supports calling spice_server_vm_start/stop, will call only
    these routines, and won't call QXLWorker->start/stop.

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 8d9c073..69d4f0a 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -762,6 +762,28 @@ void red_dispatcher_set_mouse_mode(uint32_t mode)
     }
 }
 
+void red_dispatcher_on_vm_stop(void)
+{
+    RedDispatcher *now = dispatchers;
+
+    spice_debug(NULL);
+    while (now) {
+        red_dispatcher_stop(now);
+        now = now->next;
+    }
+}
+
+void red_dispatcher_on_vm_start(void)
+{
+    RedDispatcher *now = dispatchers;
+
+    spice_debug(NULL);
+    while (now) {
+        red_dispatcher_start(now);
+        now = now->next;
+    }
+}
+
 int red_dispatcher_count(void)
 {
     RedDispatcher *now = dispatchers;
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 98f8cea..7e9ffe6 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -27,6 +27,8 @@ void red_dispatcher_set_mm_time(uint32_t);
 void red_dispatcher_on_ic_change(void);
 void red_dispatcher_on_sv_change(void);
 void red_dispatcher_set_mouse_mode(uint32_t mode);
+void red_dispatcher_on_vm_stop(void);
+void red_dispatcher_on_vm_start(void);
 int red_dispatcher_count(void);
 int red_dispatcher_add_renderer(const char *name);
 uint32_t red_dispatcher_qxl_ram_size(void);
diff --git a/server/reds.c b/server/reds.c
index b0c609f..416dff4 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4041,6 +4041,7 @@ SPICE_GNUC_VISIBLE void spice_server_vm_start(SpiceServer *s)
         st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
         spice_char_device_start(st_item->st);
     }
+    red_dispatcher_on_vm_start();
 }
 
 SPICE_GNUC_VISIBLE void spice_server_vm_stop(SpiceServer *s)
@@ -4055,6 +4056,7 @@ SPICE_GNUC_VISIBLE void spice_server_vm_stop(SpiceServer *s)
         st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
         spice_char_device_stop(st_item->st);
     }
+    red_dispatcher_on_vm_stop();
 }
 
 ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
diff --git a/server/spice.h b/server/spice.h
index 5f82ed5..fb51a47 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -134,8 +134,10 @@ struct QXLWorker {
 
 void spice_qxl_wakeup(QXLInstance *instance);
 void spice_qxl_oom(QXLInstance *instance);
-void spice_qxl_start(QXLInstance *instance);
-void spice_qxl_stop(QXLInstance *instance);
+void spice_qxl_start(QXLInstance *instance); /* deprecated since 0.11.2
+                                                spice_server_vm_start replaces it */
+void spice_qxl_stop(QXLInstance *instance);  /* deprecated since 0.11.2
+                                                spice_server_vm_stop replaces it */
 void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
                    struct QXLRect *area, struct QXLRect *dirty_rects,
                    uint32_t num_dirty_rects, uint32_t clear_dirty_region);
commit c302e12c78acc24461e19691119557945e0c2dc8
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Jun 28 14:22:43 2012 +0300

    spice.h: add entries for tracking vm state
    
    When vm state changes (started/stopped), we notify all the
    attached SpiceCharDeviceStates about the change. This is mainly required
    for avoiding writing/reading to/from the device during the non-live
    stage of migration.
    
    spice version will be bumped in one of the following patches.

diff --git a/server/reds.c b/server/reds.c
index 4e8a008..b0c609f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -252,6 +252,7 @@ typedef struct RedsState {
     SpiceTimer *mig_timer;
     SpiceTimer *mm_timer;
 
+    int vm_running;
     Ring char_devs_states; /* list of SpiceCharDeviceStateItem */
 
     SSL_CTX *ctx;
@@ -3260,7 +3261,9 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
         spice_assert(char_device->st);
         /* setting the char_device state to "started" for backward compatibily with
          * qemu releases that don't call spice api for start/stop (not implemented yet) */
-        spice_char_device_start(char_device->st);
+        if (reds->vm_running) {
+            spice_char_device_start(char_device->st);
+        }
         reds_char_device_add_state(char_device->st);
     } else {
         spice_warning("failed to create device state for %s", char_device->subtype);
@@ -3476,6 +3479,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     ring_init(&reds->channels);
     ring_init(&reds->mig_target_clients);
     ring_init(&reds->char_devs_states);
+    reds->vm_running = TRUE; /* for backward compatibility */
 
     if (!(reds->mig_timer = core->timer_add(migrate_timeout, NULL))) {
         spice_error("migration timer create failed");
@@ -4025,6 +4029,34 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_switch(SpiceServer *s)
     return 0;
 }
 
+SPICE_GNUC_VISIBLE void spice_server_vm_start(SpiceServer *s)
+{
+    RingItem *item;
+
+    spice_assert(s == reds);
+    reds->vm_running = TRUE;
+    RING_FOREACH(item, &reds->char_devs_states) {
+        SpiceCharDeviceStateItem *st_item;
+
+        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
+        spice_char_device_start(st_item->st);
+    }
+}
+
+SPICE_GNUC_VISIBLE void spice_server_vm_stop(SpiceServer *s)
+{
+    RingItem *item;
+
+    spice_assert(s == reds);
+    reds->vm_running = FALSE;
+    RING_FOREACH(item, &reds->char_devs_states) {
+        SpiceCharDeviceStateItem *st_item;
+
+        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
+        spice_char_device_stop(st_item->st);
+    }
+}
+
 ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
 {
     ssize_t ret;
diff --git a/server/spice.h b/server/spice.h
index 3d70ec7..5f82ed5 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -528,4 +528,7 @@ int spice_server_migrate_end(SpiceServer *s, int completed);
 void spice_server_set_name(SpiceServer *s, const char *name);
 void spice_server_set_uuid(SpiceServer *s, const uint8_t uuid[16]);
 
+void spice_server_vm_start(SpiceServer *s);
+void spice_server_vm_stop(SpiceServer *s);
+
 #endif
commit 11033ca5dcb031fea37b44dbcd07ebabc22288b8
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Jun 28 13:59:26 2012 +0300

    reds: add tracking for char devices
    
    The list of attached char_devices will be used in the next patch
    for notifying each instance of SpiceCharDeviceState when the vm
    is started or stopped.

diff --git a/server/char_device.c b/server/char_device.c
index e87c029..c28e548 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -644,6 +644,7 @@ static void spice_char_device_state_unref(SpiceCharDeviceState *char_dev)
 
 void spice_char_device_state_destroy(SpiceCharDeviceState *char_dev)
 {
+    reds_on_char_device_state_destroy(char_dev);
     core->timer_remove(char_dev->write_to_dev_timer);
     write_buffers_queue_free(&char_dev->write_queue);
     write_buffers_queue_free(&char_dev->write_bufs_pool);
diff --git a/server/reds.c b/server/reds.c
index 53f0a39..4e8a008 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -220,6 +220,11 @@ typedef struct RedsMigTargetClient {
     Ring pending_links;
 } RedsMigTargetClient;
 
+typedef struct SpiceCharDeviceStateItem {
+    RingItem link;
+    SpiceCharDeviceState *st;
+} SpiceCharDeviceStateItem;
+
 typedef struct RedsState {
     int listen_socket;
     int secure_listen_socket;
@@ -247,6 +252,8 @@ typedef struct RedsState {
     SpiceTimer *mig_timer;
     SpiceTimer *mm_timer;
 
+    Ring char_devs_states; /* list of SpiceCharDeviceStateItem */
+
     SSL_CTX *ctx;
 
 #ifdef RED_STATISTICS
@@ -300,6 +307,8 @@ struct ChannelSecurityOptions {
 static void migrate_timeout(void *opaque);
 static RedsMigTargetClient* reds_mig_target_client_find(RedClient *client);
 static void reds_mig_target_client_free(RedsMigTargetClient *mig_client);
+static void reds_char_device_add_state(SpiceCharDeviceState *st);
+static void reds_char_device_remove_state(SpiceCharDeviceState *st);
 
 static ChannelSecurityOptions *channels_security = NULL;
 static int default_channel_security =
@@ -3189,6 +3198,37 @@ SPICE_GNUC_VISIBLE const char** spice_server_char_device_recognized_subtypes(voi
     return spice_server_char_device_recognized_subtypes_list;
 }
 
+static void reds_char_device_add_state(SpiceCharDeviceState *st)
+{
+    SpiceCharDeviceStateItem *item = spice_new0(SpiceCharDeviceStateItem, 1);
+
+    item->st = st;
+
+    ring_add(&reds->char_devs_states, &item->link);
+}
+
+static void reds_char_device_remove_state(SpiceCharDeviceState *st)
+{
+    RingItem *item;
+
+    RING_FOREACH(item, &reds->char_devs_states) {
+        SpiceCharDeviceStateItem *st_item;
+
+        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
+        if (st_item->st == st) {
+            ring_remove(item);
+            free(st_item);
+            return;
+        }
+    }
+    spice_error("char dev state not found %p", st);
+}
+
+void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev)
+{
+    reds_char_device_remove_state(dev);
+}
+
 static int spice_server_char_device_add_interface(SpiceServer *s,
                                            SpiceBaseInstance *sin)
 {
@@ -3196,6 +3236,8 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
             SPICE_CONTAINEROF(sin, SpiceCharDeviceInstance, base);
     SpiceCharDeviceState *dev_state = NULL;
 
+    spice_assert(s == reds);
+
     spice_info("CHAR_DEVICE %s", char_device->subtype);
     if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
         if (vdagent) {
@@ -3219,6 +3261,7 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
         /* setting the char_device state to "started" for backward compatibily with
          * qemu releases that don't call spice api for start/stop (not implemented yet) */
         spice_char_device_start(char_device->st);
+        reds_char_device_add_state(char_device->st);
     } else {
         spice_warning("failed to create device state for %s", char_device->subtype);
     }
@@ -3432,6 +3475,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     main_dispatcher_init(core);
     ring_init(&reds->channels);
     ring_init(&reds->mig_target_clients);
+    ring_init(&reds->char_devs_states);
 
     if (!(reds->mig_timer = core->timer_add(migrate_timeout, NULL))) {
         spice_error("migration timer create failed");
diff --git a/server/reds.h b/server/reds.h
index f3d2ffa..87125d2 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -155,5 +155,6 @@ void reds_on_main_migrate_connected(void); //should be called when all the clien
 void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end);
 void reds_on_main_mouse_mode_request(void *message, size_t size);
 void reds_on_client_migrate_complete(RedClient *client);
+void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
 #endif
commit 8d02c14d20f95148a65e86fbb2ec97a223fa5c24
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sat Aug 11 23:41:22 2012 +0300

    agent: don't attempt to read from the device if it was released
    
    if vdi_port_read_buf_process failes, we detach the agent and also release
    the read buffer. We shouldn't try reading from the device afterwards.

diff --git a/server/reds.c b/server/reds.c
index 8d6dbfb..53f0a39 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -831,7 +831,9 @@ static void vdi_port_read_buf_unref(VDIReadBuf *buf)
         ring was empty. So we call it again so it can complete its work if
         necessary. Note that since we can be called from spice_char_device_wakeup
         this can cause recursion, but we have protection for that */
-        spice_char_device_wakeup(reds->agent_state.base);
+        if (reds->agent_state.base) {
+            spice_char_device_wakeup(reds->agent_state.base);
+        }
     }
 }
 
commit 56c9548f6471878a16cad90cc028defdae2cc7c4
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Aug 8 12:14:23 2012 +0300

    agent: reset client tokens when notifying on agent connection
    
    send SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS

diff --git a/server/main_channel.c b/server/main_channel.c
index 00a6b0f..0d948de 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -388,7 +388,19 @@ static void main_channel_marshall_mouse_mode(SpiceMarshaller *m, int current_mod
 
 void main_channel_push_agent_connected(MainChannel *main_chan)
 {
-    red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
+    if (red_channel_test_remote_cap(&main_chan->base, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
+        red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS);
+    } else {
+        red_channel_pipes_add_type(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
+    }
+}
+
+static void main_channel_marshall_agent_connected(SpiceMarshaller *m)
+{
+    SpiceMsgMainAgentConnectedTokens connected;
+
+    connected.num_tokens = REDS_AGENT_WINDOW_SIZE;
+    spice_marshall_msg_main_agent_connected_tokens(m, &connected);
 }
 
 void main_channel_push_agent_disconnected(MainChannel *main_chan)
@@ -729,6 +741,9 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
         case SPICE_MSG_MAIN_UUID:
             spice_marshall_msg_main_uuid(m, &SPICE_CONTAINEROF(base, UuidPipeItem, base)->msg);
             break;
+        case SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS:
+            main_channel_marshall_agent_connected(m);
+            break;
         default:
             break;
     };
diff --git a/server/reds.c b/server/reds.c
index e3ea154..8d6dbfb 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -605,15 +605,19 @@ static void reds_reset_vdp(void)
      *  The client tokens' are set only once, when the main channel is initialized.
      *  Instead, it would have been more appropriate to reset them upon AGEN_CONNECT.
      *  The client tokens are tracked as part of the SpiceCharDeviceClientState. Thus,
-     *  in order to be backwartd compatible with the client, we need to track the tokens
-     *  event when the agent is detached. We don't destroy the the char_device state, and
+     *  in order to be backward compatible with the client, we need to track the tokens
+     *  even if the agent is detached. We don't destroy the the char_device state, and
      *  instead we just reset it.
-     *  In addition, there is a misshandling of AGENT_TOKENS message in spice-gtk: it
+     *  In addition, there used to be a misshandling of AGENT_TOKENS message in spice-gtk: it
      *  overrides the amount of tokens, instead of adding the given amount.
-     *
-     *  TODO: change AGENT_CONNECT msg to contain tokens count.
      */
-    spice_char_device_reset(state->base);
+    if (red_channel_test_remote_cap(&reds->main_channel->base,
+                                    SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
+        spice_char_device_state_destroy(state->base);
+        state->base = NULL;
+    } else {
+        spice_char_device_reset(state->base);
+    }
 
     sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
     if (sif->state) {
diff --git a/spice-common b/spice-common
index c0b048e..c6bd210 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit c0b048ebef41b3a79d42e96c0ecaef65e1bb7599
+Subproject commit c6bd210ad0b6eb485fda25426ab9d75253439f54
commit 49a8d68303f3d8681a9c61d74e0675279649d480
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Aug 8 12:13:25 2012 +0300

    red_channel: add red_channel_test_remote_cap
    
    for checking if all the channel clients connected support the cap

diff --git a/server/red_channel.c b/server/red_channel.c
index 2a7acbf..1cad9eb 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -560,6 +560,34 @@ int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap)
                           cap);
 }
 
+int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap)
+{
+    RingItem *link;
+
+    RING_FOREACH(link, &channel->clients) {
+        RedChannelClient *rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+
+        if (!red_channel_client_test_remote_common_cap(rcc, cap)) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+int red_channel_test_remote_cap(RedChannel *channel, uint32_t cap)
+{
+    RingItem *link;
+
+    RING_FOREACH(link, &channel->clients) {
+        RedChannelClient *rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+
+        if (!red_channel_client_test_remote_cap(rcc, cap)) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
 static int red_channel_client_pre_create_validate(RedChannel *channel, RedClient  *client)
 {
     if (red_client_get_channel(client, channel->type, channel->id)) {
diff --git a/server/red_channel.h b/server/red_channel.h
index e77e484..acb49cd 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -363,6 +363,10 @@ void red_channel_destroy(RedChannel *channel);
 int red_channel_client_test_remote_common_cap(RedChannelClient *rcc, uint32_t cap);
 int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap);
 
+/* return true if all the channel clients support the cap */
+int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap);
+int red_channel_test_remote_cap(RedChannel *channel, uint32_t cap);
+
 /* shutdown is the only safe thing to do out of the client/channel
  * thread. It will not touch the rings, just shutdown the socket.
  * It should be followed by some way to gurantee a disconnection. */


More information about the Spice-commits mailing list