diff options
Diffstat (limited to 'client/red_client.cpp')
-rw-r--r-- | client/red_client.cpp | 107 |
1 files changed, 96 insertions, 11 deletions
diff --git a/client/red_client.cpp b/client/red_client.cpp index afde7d27..84440c10 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -26,6 +26,7 @@ #include "utils.h" #include "debug.h" #include "marshallers.h" +#include <algorithm> #ifndef INFINITY #define INFINITY HUGE @@ -123,6 +124,11 @@ void ClipboardReleaseEvent::response(AbstractProcessLoop& events_loop) VD_AGENT_CLIPBOARD_RELEASE, 0, NULL); } +void MigrateEndEvent::response(AbstractProcessLoop& events_loop) +{ + static_cast<RedClient*>(events_loop.get_owner())->send_migrate_end(); +} + Migrate::Migrate(RedClient& client) : _client (client) , _running (false) @@ -395,6 +401,7 @@ RedClient::RedClient(Application& application) , _agent_caps(NULL) , _migrate (*this) , _glz_window (_glz_debug) + , _during_migration (false) { Platform::set_clipboard_listener(this); MainChannelLoop* message_loop = static_cast<MainChannelLoop*>(get_message_handler()); @@ -413,6 +420,7 @@ RedClient::RedClient(Application& application) message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel); + message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_END, &RedClient::handle_migrate_end); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, &RedClient::handle_migrate_switch_host); message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init); @@ -424,6 +432,8 @@ RedClient::RedClient(Application& application) message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DISCONNECTED, &RedClient::handle_agent_disconnected); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DATA, &RedClient::handle_agent_data); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_TOKEN, &RedClient::handle_agent_tokens); + + set_capability(SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); start(); } @@ -491,6 +501,7 @@ void RedClient::on_disconnect() void RedClient::delete_channels() { Lock lock(_channels_lock); + _pending_mig_disconnect_channels.clear(); while (!_channels.empty()) { RedChannel *channel = *_channels.begin(); _channels.pop_front(); @@ -618,7 +629,7 @@ bool RedClient::abort() void RedClient::handle_migrate_begin(RedPeer::InMessage* message) { - DBG(0, ""); + LOG_INFO(""); SpiceMsgMainMigrationBegin* migrate = (SpiceMsgMainMigrationBegin*)message->data(); //add mig channels _migrate.start(migrate); @@ -626,9 +637,59 @@ void RedClient::handle_migrate_begin(RedPeer::InMessage* message) void RedClient::handle_migrate_cancel(RedPeer::InMessage* message) { + LOG_INFO(""); _migrate.abort(); } +void RedClient::handle_migrate_end(RedPeer::InMessage* message) +{ + LOG_INFO(""); + + Lock lock(_channels_lock); + ASSERT(_pending_mig_disconnect_channels.empty()); + Channels::iterator iter = _channels.begin(); + for (; iter != _channels.end(); ++iter) { + (*iter)->disconnect_migration_src(); + _pending_mig_disconnect_channels.push_back(*iter); + } + RedChannel::disconnect_migration_src(); + _pending_mig_disconnect_channels.push_back(this); + _during_migration = true; +} + +void RedClient::on_channel_disconnect_mig_src_completed(RedChannel& channel) +{ + Lock lock(_channels_lock); + Channels::iterator pending_iter = std::find(_pending_mig_disconnect_channels.begin(), + _pending_mig_disconnect_channels.end(), + &channel); + + LOG_INFO(""); + if (pending_iter == _pending_mig_disconnect_channels.end()) { + THROW("unexpected channel"); + } + + _pending_mig_disconnect_channels.erase(pending_iter); + /* clean shared data when all channels have disconnected */ + if (_pending_mig_disconnect_channels.empty()) { + _pixmap_cache.clear(); + _glz_window.clear(); + memset(_sync_info, 0, sizeof(_sync_info)); + + LOG_INFO("calling main to connect and wait for handle_init to tell all the other channels to connect"); + RedChannel::connect_migration_target(); + + AutoRef<MigrateEndEvent> mig_end_event(new MigrateEndEvent()); + get_process_loop().push_event(*mig_end_event); + } +} + +void RedClient::send_migrate_end() +{ + Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_END); + post_message(message); +} + ChannelFactory* RedClient::find_factory(uint32_t type) { Factorys::iterator iter = _factorys.begin(); @@ -973,12 +1034,37 @@ void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode) } } +/* returns true if we should wait for a response from the agent */ +bool RedClient::init_guest_display() +{ + if (_agent_connected) { + if (_auto_display_res) { + send_agent_monitors_config(); + } + + if (_auto_display_res || !_display_setting.is_empty()) { + _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT); + } else { + return false; + } + } else { + if (_auto_display_res || !_display_setting.is_empty()) { + LOG_WARN("no agent running, display options have been ignored"); + } + return false; + } + return true; +} + void RedClient::handle_init(RedPeer::InMessage* message) { SpiceMsgMainInit *init = (SpiceMsgMainInit *)message->data(); + LOG_INFO(""); _connection_id = init->session_id; set_mm_time(init->multi_media_time); - calc_pixmap_cach_and_glz_window_size(init->display_channels_hint, init->ram_hint); + if (!_during_migration) { + calc_pixmap_cach_and_glz_window_size(init->display_channels_hint, init->ram_hint); + } set_mouse_mode(init->supported_mouse_modes, init->current_mouse_mode); _agent_tokens = init->agent_tokens; _agent_connected = !!init->agent_connected; @@ -989,20 +1075,19 @@ void RedClient::handle_init(RedPeer::InMessage* message) _marshallers->msgc_main_agent_start(msg->marshaller(), &agent_start); post_message(msg); send_agent_announce_capabilities(true); - if (_auto_display_res) { - send_agent_monitors_config(); - } + } - if (_auto_display_res || !_display_setting.is_empty()) { - _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT); - } else { + if (!_during_migration) { + if (!init_guest_display()) { send_main_attach_channels(); } } else { - if (_auto_display_res || !_display_setting.is_empty()) { - LOG_WARN("no agent running, display options have been ignored"); + LOG_INFO("connecting all channels after migration"); + Channels::iterator iter = _channels.begin(); + for (; iter != _channels.end(); ++iter) { + (*iter)->connect_migration_target(); } - send_main_attach_channels(); + _during_migration = false; } } |