mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-08-15 13:57:13 +00:00
client: handling SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST
disconnecting from the current host and connecting to the target host.
This commit is contained in:
parent
91bc0e8625
commit
88aa56045a
@ -86,6 +86,22 @@ void MonitorsQuery::do_response(AbstractProcessLoop& events_loop)
|
||||
}
|
||||
}
|
||||
|
||||
SwitchHostEvent::SwitchHostEvent(const char* host, int port, int sport, const char* cert_subject)
|
||||
{
|
||||
_host = host;
|
||||
_port = port;
|
||||
_sport = sport;
|
||||
if (cert_subject) {
|
||||
_cert_subject = cert_subject;
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchHostEvent::response(AbstractProcessLoop& events_loop)
|
||||
{
|
||||
Application* app = static_cast<Application*>(events_loop.get_owner());
|
||||
app->switch_host(_host, _port, _sport, _cert_subject);
|
||||
}
|
||||
|
||||
//todo: add inactive visual appearance
|
||||
class GUIBarrier: public ScreenLayer {
|
||||
public:
|
||||
@ -337,6 +353,7 @@ Application::Application()
|
||||
, _title (L"SPICEc:%d")
|
||||
, _sys_key_intercept_mode (false)
|
||||
, _gui_mode (GUI_MODE_FULL)
|
||||
, _during_host_switch(false)
|
||||
, _state (DISCONNECTED)
|
||||
{
|
||||
DBG(0, "");
|
||||
@ -536,6 +553,20 @@ void Application::connect()
|
||||
_client.connect();
|
||||
}
|
||||
|
||||
void Application::switch_host(const std::string& host, int port, int sport,
|
||||
const std::string& cert_subject)
|
||||
{
|
||||
LOG_INFO("host=%s port=%d sport=%d", host.c_str(), port, sport);
|
||||
_during_host_switch = true;
|
||||
// we will try to connect to the new host when DiconnectedEvent occurs
|
||||
do_disconnect();
|
||||
_client.set_target(host.c_str(), port, sport);
|
||||
|
||||
if (!cert_subject.empty()) {
|
||||
set_host_cert_subject(cert_subject.c_str(), "spicec");
|
||||
}
|
||||
}
|
||||
|
||||
int Application::run()
|
||||
{
|
||||
if (_gui_mode != GUI_MODE_FULL) {
|
||||
@ -751,17 +782,26 @@ void Application::set_state(State state)
|
||||
|
||||
void Application::on_connected()
|
||||
{
|
||||
_during_host_switch = false;
|
||||
|
||||
set_state(CONNECTED);
|
||||
}
|
||||
|
||||
void Application::on_disconnected(int error_code)
|
||||
{
|
||||
if (_gui_mode != GUI_MODE_FULL) {
|
||||
bool host_switch = _during_host_switch && (error_code == SPICEC_ERROR_CODE_SUCCESS);
|
||||
if (_gui_mode != GUI_MODE_FULL && !host_switch) {
|
||||
_during_host_switch = false;
|
||||
ProcessLoop::quit(error_code);
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: display special notification for host switch (during migration)
|
||||
set_state(DISCONNECTED);
|
||||
show_gui();
|
||||
if (host_switch) {
|
||||
_client.connect(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::on_visibility_start(int screen_id)
|
||||
|
||||
@ -86,6 +86,18 @@ private:
|
||||
std::vector<MonitorInfo> _monitors;
|
||||
};
|
||||
|
||||
class SwitchHostEvent: public Event {
|
||||
public:
|
||||
SwitchHostEvent(const char* host, int port, int sport, const char* cert_subject);
|
||||
virtual void response(AbstractProcessLoop& events_loop);
|
||||
|
||||
private:
|
||||
std::string _host;
|
||||
int _port;
|
||||
int _sport;
|
||||
std::string _cert_subject;
|
||||
};
|
||||
|
||||
enum CanvasOption {
|
||||
CANVAS_OPTION_INVALID,
|
||||
CANVAS_OPTION_CAIRO,
|
||||
@ -186,6 +198,8 @@ public:
|
||||
void show();
|
||||
void external_show();
|
||||
void connect();
|
||||
void switch_host(const std::string& host, int port, int sport, const std::string& cert_subject);
|
||||
|
||||
const PeerConnectionOptMap& get_con_opt_map() {return _peer_con_opt;}
|
||||
const RedPeer::HostAuthOptions& get_host_auth_opt() { return _host_auth_opt;}
|
||||
const std::string& get_connection_ciphers() { return _con_ciphers;}
|
||||
@ -317,6 +331,7 @@ private:
|
||||
#ifdef GUI_DEMO
|
||||
AutoRef<TestTimer> _gui_test_timer;
|
||||
#endif
|
||||
bool _during_host_switch;
|
||||
|
||||
State _state;
|
||||
};
|
||||
|
||||
@ -178,7 +178,7 @@ void Migrate::run()
|
||||
for (++iter; iter != _channels.end(); ++iter) {
|
||||
conn_type = _client.get_connection_options((*iter)->get_type());
|
||||
con_opt = RedPeer::ConnectionOptions(conn_type, _port, _sport,
|
||||
_auth_options, _con_ciphers);
|
||||
_auth_options, _con_ciphers);
|
||||
connect_one(**iter, con_opt, connection_id);
|
||||
}
|
||||
_connected = true;
|
||||
@ -332,6 +332,9 @@ RedClient::RedClient(Application& application)
|
||||
message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin,
|
||||
sizeof(SpiceMsgMainMigrationBegin));
|
||||
message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel, 0);
|
||||
message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST,
|
||||
&RedClient::handle_migrate_switch_host,
|
||||
sizeof(SpiceMsgMainMigrationSwitchHost));
|
||||
message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init, sizeof(SpiceMsgMainInit));
|
||||
message_loop->set_handler(SPICE_MSG_MAIN_CHANNELS_LIST, &RedClient::handle_channels,
|
||||
sizeof(SpiceMsgChannels));
|
||||
@ -437,11 +440,19 @@ RedPeer::ConnectionOptions::Type RedClient::get_connection_options(uint32_t chan
|
||||
|
||||
void RedClient::connect()
|
||||
{
|
||||
connect(false);
|
||||
}
|
||||
|
||||
void RedClient::connect(bool wait_main_disconnect)
|
||||
{
|
||||
// assumption: read _connection_id is atomic
|
||||
if (_connection_id) {
|
||||
return;
|
||||
if (!wait_main_disconnect) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (!abort_channels()) {
|
||||
while (!abort_channels() || _connection_id) {
|
||||
_application.process_events_queue();
|
||||
Platform::msleep(100);
|
||||
}
|
||||
@ -837,6 +848,31 @@ void RedClient::handle_agent_tokens(RedPeer::InMessage* message)
|
||||
_agent_tokens += token->num_tokens;
|
||||
}
|
||||
|
||||
void RedClient::handle_migrate_switch_host(RedPeer::InMessage* message)
|
||||
{
|
||||
SpiceMsgMainMigrationSwitchHost* migrate = (SpiceMsgMainMigrationSwitchHost*)message->data();
|
||||
char* host = ((char*)migrate) + migrate->host_offset;
|
||||
char* subject = NULL;
|
||||
|
||||
if (host[migrate->host_size - 1] != '\0') {
|
||||
THROW("host is not a null-terminated string");
|
||||
}
|
||||
|
||||
if (migrate->cert_subject_size) {
|
||||
subject = ((char*)migrate)+ migrate->cert_subject_offset;
|
||||
if (subject[migrate->cert_subject_size - 1] != '\0') {
|
||||
THROW("cert subject is not a null-terminated string");
|
||||
}
|
||||
}
|
||||
|
||||
AutoRef<SwitchHostEvent> switch_event(new SwitchHostEvent(host,
|
||||
migrate->port,
|
||||
migrate->sport,
|
||||
subject));
|
||||
push_event(*switch_event);
|
||||
}
|
||||
|
||||
|
||||
void RedClient::migrate_channel(RedChannel& channel)
|
||||
{
|
||||
DBG(0, "channel type %u id %u", channel.get_type(), channel.get_id());
|
||||
|
||||
@ -139,6 +139,8 @@ public:
|
||||
virtual void disconnect();
|
||||
virtual bool abort();
|
||||
|
||||
void connect(bool wait_main_disconnect);
|
||||
|
||||
void push_event(Event* event);
|
||||
void activate_interval_timer(Timer* timer, unsigned int millisec);
|
||||
void deactivate_interval_timer(Timer* timer);
|
||||
@ -194,6 +196,7 @@ private:
|
||||
void handle_agent_disconnected(RedPeer::InMessage* message);
|
||||
void handle_agent_data(RedPeer::InMessage* message);
|
||||
void handle_agent_tokens(RedPeer::InMessage* message);
|
||||
void handle_migrate_switch_host(RedPeer::InMessage* message);
|
||||
|
||||
void on_agent_reply(VDAgentReply* reply);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user