summaryrefslogtreecommitdiff
path: root/client/red_client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/red_client.cpp')
-rw-r--r--client/red_client.cpp107
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;
}
}