> > Preparation for converting to GObject > --- > server/Makefile.am | 2 + > server/inputs-channel.c | 2 +- > server/main-channel-client.c | 549 ++++++++++++++++++++++++++++++++++++++ > server/main-channel-client.h | 153 +++++++++++ > server/main-channel.c | 616 > +++---------------------------------------- > server/main-channel.h | 27 +- > 6 files changed, 747 insertions(+), 602 deletions(-) > create mode 100644 server/main-channel-client.c > create mode 100644 server/main-channel-client.h > > diff --git a/server/Makefile.am b/server/Makefile.am > index fbf4638..5a5c7e8 100644 > --- a/server/Makefile.am > +++ b/server/Makefile.am > @@ -86,6 +86,8 @@ libserver_la_SOURCES = \ > lz4-encoder.h \ > main-channel.c \ > main-channel.h \ > + main-channel-client.c \ > + main-channel-client.h \ > mjpeg-encoder.c \ > red-channel.c \ > red-channel.h \ > diff --git a/server/inputs-channel.c b/server/inputs-channel.c > index 0ce12de..584204f 100644 > --- a/server/inputs-channel.c > +++ b/server/inputs-channel.c > @@ -39,7 +39,7 @@ > #include "reds.h" > #include "reds-stream.h" > #include "red-channel.h" > -#include "main-channel.h" > +#include "main-channel-client.h" > #include "inputs-channel.h" > #include "migration-protocol.h" > #include "utils.h" > diff --git a/server/main-channel-client.c b/server/main-channel-client.c > new file mode 100644 > index 0000000..bac5316 > --- /dev/null > +++ b/server/main-channel-client.c > @@ -0,0 +1,549 @@ > +/* > + Copyright (C) 2009-2015 Red Hat, Inc. > + Wouldn't be good to update to 2016? > + 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/>. > +*/ > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include <inttypes.h> > +#include "main-channel-client.h" replace above line with an empty one, its duplicated > +#include "main-channel-client.h" > +#include "main-channel.h" > +#include "reds.h" > + > +#define NET_TEST_WARMUP_BYTES 0 > +#define NET_TEST_BYTES (1024 * 250) > + > +enum NetTestStage { > + NET_TEST_STAGE_INVALID, > + NET_TEST_STAGE_WARMUP, > + NET_TEST_STAGE_LATENCY, > + NET_TEST_STAGE_RATE, > + NET_TEST_STAGE_COMPLETE, > +}; > + > +#define CLIENT_CONNECTIVITY_TIMEOUT (MSEC_PER_SEC * 30) > +#define PING_INTERVAL (MSEC_PER_SEC * 10) > + > +struct MainChannelClient { > + RedChannelClient base; > + uint32_t connection_id; > + uint32_t ping_id; > + uint32_t net_test_id; > + int net_test_stage; > + uint64_t latency; > + uint64_t bitrate_per_sec; > +#ifdef RED_STATISTICS > + SpiceTimer *ping_timer; > + int ping_interval; > +#endif > + int mig_wait_connect; > + int mig_connect_ok; > + int mig_wait_prev_complete; > + int mig_wait_prev_try_seamless; > + int init_sent; > + int seamless_mig_dst; > +}; > + > +static int main_channel_client_push_ping(MainChannelClient *mcc, int size); > + > +static RedPipeItem *main_notify_item_new(void *data, int num) > +{ > + RedNotifyPipeItem *item = spice_malloc(sizeof(RedNotifyPipeItem)); > + const char *msg = data; > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NOTIFY); > + item->msg = spice_strdup(msg); > + return &item->base; > +} > + > +void main_channel_client_start_net_test(MainChannelClient *mcc, int > test_rate) > +{ > + if (!mcc || mcc->net_test_id) { > + return; > + } > + if (test_rate) { > + if (main_channel_client_push_ping(mcc, NET_TEST_WARMUP_BYTES) > + && main_channel_client_push_ping(mcc, 0) > + && main_channel_client_push_ping(mcc, NET_TEST_BYTES)) { > + mcc->net_test_id = mcc->ping_id - 2; > + mcc->net_test_stage = NET_TEST_STAGE_WARMUP; > + } > + } else { > + red_channel_client_start_connectivity_monitoring(&mcc->base, > CLIENT_CONNECTIVITY_TIMEOUT); > + } > +} > + > +static RedPipeItem *red_ping_item_new(int size) > +{ > + RedPingPipeItem *item = spice_malloc(sizeof(RedPingPipeItem)); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_PING); > + item->size = size; > + return &item->base; > +} > + > +static int main_channel_client_push_ping(MainChannelClient *mcc, int size) > +{ > + RedPipeItem *item; > + > + if (mcc == NULL) { > + return FALSE; > + } > + item = red_ping_item_new(size); > + red_channel_client_pipe_add_push(&mcc->base, item); > + return TRUE; > +} > + > +static RedPipeItem *main_agent_tokens_item_new(uint32_t num_tokens) > +{ > + RedTokensPipeItem *item = spice_malloc(sizeof(RedTokensPipeItem)); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN); > + item->tokens = num_tokens; > + return &item->base; > +} > + > + > +void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t > num_tokens) > +{ > + RedPipeItem *item = main_agent_tokens_item_new(num_tokens); > + > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +static RedPipeItem *main_agent_data_item_new(uint8_t* data, size_t len, > + spice_marshaller_item_free_func > free_data, > + void *opaque) > +{ > + RedAgentDataPipeItem *item = spice_malloc(sizeof(RedAgentDataPipeItem)); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA); > + item->data = data; > + item->len = len; > + item->free_data = free_data; > + item->opaque = opaque; > + return &item->base; > +} > + > +void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* > data, size_t len, > + spice_marshaller_item_free_func free_data, void *opaque) > +{ > + RedPipeItem *item; > + > + item = main_agent_data_item_new(data, len, free_data, opaque); > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +static RedPipeItem *main_init_item_new(int connection_id, > + int display_channels_hint, > + int current_mouse_mode, > + int is_client_mouse_allowed, > + int multi_media_time, > + int ram_hint) > +{ > + RedInitPipeItem *item = spice_malloc(sizeof(RedInitPipeItem)); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_INIT); > + item->connection_id = connection_id; > + item->display_channels_hint = display_channels_hint; > + item->current_mouse_mode = current_mouse_mode; > + item->is_client_mouse_allowed = is_client_mouse_allowed; > + item->multi_media_time = multi_media_time; > + item->ram_hint = ram_hint; > + return &item->base; > +} > + > +void main_channel_client_push_init(MainChannelClient *mcc, > + int display_channels_hint, > + int current_mouse_mode, > + int is_client_mouse_allowed, > + int multi_media_time, > + int ram_hint) > +{ > + RedPipeItem *item; > + > + item = main_init_item_new(mcc->connection_id, display_channels_hint, > + current_mouse_mode, is_client_mouse_allowed, > + multi_media_time, ram_hint); > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +static RedPipeItem *main_name_item_new(const char *name) > +{ > + RedNamePipeItem *item = spice_malloc(sizeof(RedNamePipeItem) + > strlen(name) + 1); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NAME); > + item->msg.name_len = strlen(name) + 1; > + memcpy(&item->msg.name, name, item->msg.name_len); > + > + return &item->base; > +} > + > +void main_channel_client_push_name(MainChannelClient *mcc, const char *name) > +{ > + RedPipeItem *item; > + > + if (!red_channel_client_test_remote_cap(&mcc->base, > + SPICE_MAIN_CAP_NAME_AND_UUID)) > + return; > + > + item = main_name_item_new(name); > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +static RedPipeItem *main_uuid_item_new(const uint8_t uuid[16]) > +{ > + RedUuidPipeItem *item = spice_malloc(sizeof(RedUuidPipeItem)); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_UUID); > + memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid)); > + > + return &item->base; > +} > + > +void main_channel_client_push_uuid(MainChannelClient *mcc, const uint8_t > uuid[16]) > +{ > + RedPipeItem *item; > + > + if (!red_channel_client_test_remote_cap(&mcc->base, > + SPICE_MAIN_CAP_NAME_AND_UUID)) > + return; > + > + item = main_uuid_item_new(uuid); > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +void main_channel_client_push_notify(MainChannelClient *mcc, const char > *msg) > +{ > + RedPipeItem *item = main_notify_item_new((void *)msg, 1); > + red_channel_client_pipe_add_push(&mcc->base, item); > +} > + > +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) { > + 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(mcc->base.channel->reds, seamless > && success); > + } > + } else { > + if (success) { > + spice_printerr("client %p MIGRATE_CANCEL", mcc->base.client); > + red_channel_client_pipe_add_empty_msg(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_CANCEL); > + } > + } > +} > + > +void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient > *mcc, > + uint32_t > src_version) > +{ > + if (reds_on_migrate_dst_set_seamless(mcc->base.channel->reds, 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 { > + red_channel_client_pipe_add_empty_msg(&mcc->base, > + > SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK); > + } > +} > +void main_channel_client_handle_pong(MainChannelClient *mcc, SpiceMsgPing > *ping, uint32_t size) > +{ > + uint64_t roundtrip; > + RedChannelClient* rcc = (RedChannelClient*)mcc; > + > + roundtrip = g_get_monotonic_time() - ping->timestamp; > + > + if (ping->id == mcc->net_test_id) { > + switch (mcc->net_test_stage) { > + case NET_TEST_STAGE_WARMUP: > + mcc->net_test_id++; > + mcc->net_test_stage = NET_TEST_STAGE_LATENCY; > + mcc->latency = roundtrip; > + break; > + case NET_TEST_STAGE_LATENCY: > + mcc->net_test_id++; > + mcc->net_test_stage = NET_TEST_STAGE_RATE; > + mcc->latency = MIN(mcc->latency, roundtrip); > + break; > + case NET_TEST_STAGE_RATE: > + mcc->net_test_id = 0; > + if (roundtrip <= mcc->latency) { > + // probably high load on client or server result with > incorrect values > + spice_printerr("net test: invalid values, latency %" > PRIu64 > + " roundtrip %" PRIu64 ". assuming high" > + "bandwidth", mcc->latency, roundtrip); > + mcc->latency = 0; > + mcc->net_test_stage = NET_TEST_STAGE_INVALID; > + > red_channel_client_start_connectivity_monitoring(&mcc->base, > + > CLIENT_CONNECTIVITY_TIMEOUT); > + break; > + } > + mcc->bitrate_per_sec = (uint64_t)(NET_TEST_BYTES * 8) * > 1000000 > + / (roundtrip - mcc->latency); > + mcc->net_test_stage = NET_TEST_STAGE_COMPLETE; > + spice_printerr("net test: latency %f ms, bitrate %"PRIu64" > bps (%f Mbps)%s", > + (double)mcc->latency / 1000, > + mcc->bitrate_per_sec, > + (double)mcc->bitrate_per_sec / 1024 / 1024, > + main_channel_client_is_low_bandwidth(mcc) ? " > LOW BANDWIDTH" : ""); > + red_channel_client_start_connectivity_monitoring(&mcc->base, > + > CLIENT_CONNECTIVITY_TIMEOUT); > + break; > + default: > + spice_printerr("invalid net test stage, ping id %d test id > %d stage %d", > + ping->id, > + mcc->net_test_id, > + mcc->net_test_stage); > + mcc->net_test_stage = NET_TEST_STAGE_INVALID; > + } > + return; > + } else { > + /* > + * channel client monitors the connectivity using ping-pong messages > + */ > + red_channel_client_handle_message(rcc, size, SPICE_MSGC_PONG, ping); > + } > +#ifdef RED_STATISTICS > + stat_update_value(rcc->channel->reds, roundtrip); > +#endif > +} > + > +gboolean main_channel_client_get_seamless_migration(MainChannelClient *mcc) > +{ > + return mcc->seamless_mig_dst; > +} > + > +void main_channel_client_handle_migrate_end(MainChannelClient *mcc) > +{ > + if (!red_client_during_migrate_at_target(mcc->base.client)) { > + spice_printerr("unexpected SPICE_MSGC_MIGRATE_END"); > + return; > + } > + if (!red_channel_client_test_remote_cap(&mcc->base, > + > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) > { > + spice_printerr("unexpected SPICE_MSGC_MIGRATE_END, " > + "client does not support semi-seamless migration"); > + return; > + } > + red_client_semi_seamless_migrate_complete(mcc->base.client); > +} > + > +void main_channel_client_migrate_cancel_wait(MainChannelClient *mcc) > +{ > + if (mcc->mig_wait_connect) { > + spice_printerr("client %p cancel wait connect", mcc->base.client); > + mcc->mig_wait_connect = FALSE; > + mcc->mig_connect_ok = FALSE; > + } > + mcc->mig_wait_prev_complete = FALSE; > +} > + > +void main_channel_client_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, > + > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS); > + } else { > + red_channel_client_pipe_add_type(&mcc->base, > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN); > + } > + mcc->mig_wait_connect = TRUE; > + mcc->mig_wait_prev_complete = FALSE; > + } > +} > + > +gboolean main_channel_client_migrate_src_complete(MainChannelClient *mcc, > + gboolean success) > +{ > + gboolean ret = FALSE; > + int semi_seamless_support = > red_channel_client_test_remote_cap(&mcc->base, > + > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); > + if (semi_seamless_support && mcc->mig_connect_ok) { > + if (success) { > + spice_printerr("client %p MIGRATE_END", mcc->base.client); > + red_channel_client_pipe_add_empty_msg(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_END); > + ret = TRUE; > + } else { > + spice_printerr("client %p MIGRATE_CANCEL", mcc->base.client); > + 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, > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST); > + } > + } > + mcc->mig_connect_ok = FALSE; > + mcc->mig_wait_connect = FALSE; > + > + return ret; > +} > + > +#ifdef RED_STATISTICS > +static void do_ping_client(MainChannelClient *mcc, > + const char *opt, int has_interval, int interval) > +{ > + spice_printerr(""); > + if (!opt) { > + main_channel_client_push_ping(mcc, 0); > + } else if (!strcmp(opt, "on")) { > + if (has_interval && interval > 0) { > + mcc->ping_interval = interval * MSEC_PER_SEC; > + } > + reds_core_timer_start(mcc->base.channel->reds, mcc->ping_timer, > mcc->ping_interval); > + } else if (!strcmp(opt, "off")) { > + reds_core_timer_cancel(mcc->base.channel->reds, mcc->ping_timer); > + } else { > + return; > + } > +} > + > +static void ping_timer_cb(void *opaque) > +{ > + MainChannelClient *mcc = opaque; > + > + if (!red_channel_client_is_connected(&mcc->base)) { > + spice_printerr("not connected to peer, ping off"); > + reds_core_timer_cancel(mcc->base.channel->reds, mcc->ping_timer); > + return; > + } > + do_ping_client(mcc, NULL, 0, 0); > + reds_core_timer_start(mcc->base.channel->reds, mcc->ping_timer, > mcc->ping_interval); > +} > +#endif /* RED_STATISTICS */ > + > +MainChannelClient *main_channel_client_create(MainChannel *main_chan, > RedClient *client, > + RedsStream *stream, uint32_t > connection_id, > + int num_common_caps, uint32_t > *common_caps, > + int num_caps, uint32_t *caps) > +{ > + MainChannelClient *mcc = (MainChannelClient*) > + > red_channel_client_create(sizeof(MainChannelClient), > &main_chan->base, > + client, stream, > FALSE, num_common_caps, > + common_caps, > num_caps, caps); > + spice_assert(mcc != NULL); > + mcc->connection_id = connection_id; > + mcc->bitrate_per_sec = ~0; > +#ifdef RED_STATISTICS > + if (!(mcc->ping_timer = > reds_core_timer_add(red_channel_get_server(&main_chan->base), ping_timer_cb, > mcc))) { > + spice_error("ping timer create failed"); > + } > + mcc->ping_interval = PING_INTERVAL; > +#endif > + return mcc; > +} > + > +int main_channel_client_is_network_info_initialized(MainChannelClient *mcc) > +{ > + return mcc->net_test_stage == NET_TEST_STAGE_COMPLETE; > +} > + > +int main_channel_client_is_low_bandwidth(MainChannelClient *mcc) > +{ > + // TODO: configurable? > + return mcc->bitrate_per_sec < 10 * 1024 * 1024; > +} > + > +uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc) > +{ > + return mcc->bitrate_per_sec; > +} > + > +uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc) > +{ > + return mcc->latency / 1000; > +} > + > +void main_channel_client_migrate(RedChannelClient *rcc) > +{ > + reds_on_main_channel_migrate(rcc->channel->reds, SPICE_CONTAINEROF(rcc, > MainChannelClient, base)); > + red_channel_client_default_migrate(rcc); > +} > + > +gboolean main_channel_client_connect_semi_seamless(MainChannelClient *mcc) > +{ > + RedChannelClient *rcc = main_channel_client_get_base(mcc); > + MainChannel* main_channel = SPICE_CONTAINEROF(rcc->channel, MainChannel, > base); > + if (red_channel_client_test_remote_cap(rcc, > + > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) > { > + RedClient *client = red_channel_client_get_client(rcc); > + if (red_client_during_migrate_at_target(client)) { > + spice_printerr("client %p: wait till previous migration > completes", client); > + mcc->mig_wait_prev_complete = TRUE; > + mcc->mig_wait_prev_try_seamless = FALSE; > + } else { > + red_channel_client_pipe_add_type(rcc, > + > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN); > + mcc->mig_wait_connect = TRUE; > + } > + mcc->mig_connect_ok = FALSE; > + main_channel->num_clients_mig_wait++; > + return TRUE; > + } > + return FALSE; > +} > + > +void main_channel_client_connect_seamless(MainChannelClient *mcc) > +{ > + 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, > + > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS); > + mcc->mig_wait_connect = TRUE; > + } > + mcc->mig_connect_ok = FALSE; > +} > + > +RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc) > +{ > + spice_assert(mcc); > + return &mcc->base; > +} > + > +uint32_t main_channel_client_get_connection_id(MainChannelClient *mcc) > +{ > + return mcc->connection_id; > +} > + > +uint32_t main_channel_client_next_ping_id(MainChannelClient *mcc) > +{ > + return ++mcc->ping_id; > +} > + > +void main_channel_client_on_send_init(MainChannelClient *mcc) > +{ > + mcc->init_sent = TRUE; > +} > + > +gboolean main_channel_client_get_init_sent(MainChannelClient *mcc) > +{ > + return mcc->init_sent; > +} > diff --git a/server/main-channel-client.h b/server/main-channel-client.h > new file mode 100644 > index 0000000..7e4daf9 > --- /dev/null > +++ b/server/main-channel-client.h > @@ -0,0 +1,153 @@ > +/* > + Copyright (C) 2009-2015 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 __MAIN_CHANNEL_CLIENT_H__ > +#define __MAIN_CHANNEL_CLIENT_H__ > + > +#include "red-channel.h" > + > +typedef struct MainChannel MainChannel; > +typedef struct MainChannelClient MainChannelClient; > + > +MainChannelClient *main_channel_client_create(MainChannel *main_chan, > RedClient *client, > + RedsStream *stream, uint32_t > connection_id, > + int num_common_caps, uint32_t > *common_caps, > + int num_caps, uint32_t *caps); > + > +void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t > num_tokens); > +void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* > data, size_t len, > + spice_marshaller_item_free_func > free_data, void *opaque); > +void main_channel_client_start_net_test(MainChannelClient *mcc, int > test_rate); > +// TODO: huge. Consider making a reds_* interface for these functions > +// and calling from main. > +void main_channel_client_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_client_push_notify(MainChannelClient *mcc, const char > *msg); > +void main_channel_client_migrate(RedChannelClient *rcc); > +gboolean main_channel_client_connect_semi_seamless(MainChannelClient *mcc); > +void main_channel_client_connect_seamless(MainChannelClient *mcc); > +void main_channel_client_handle_migrate_connected(MainChannelClient *mcc, > + int success, > + int seamless); > +void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient > *mcc, > + uint32_t > src_version); > +void main_channel_client_handle_migrate_end(MainChannelClient *mcc); > +void main_channel_client_migrate_cancel_wait(MainChannelClient *mcc); > +void main_channel_client_migrate_dst_complete(MainChannelClient *mcc); > +gboolean main_channel_client_migrate_src_complete(MainChannelClient *mcc, > + gboolean success); > + > +void main_channel_client_handle_pong(MainChannelClient *mcc, SpiceMsgPing > *ping, uint32_t size); > + > +/* > + * return TRUE if network test had been completed successfully. > + * If FALSE, bitrate_per_sec is set to MAX_UINT64 and the roundtrip is set > to 0 > + */ > +int main_channel_client_is_network_info_initialized(MainChannelClient *mcc); > +int main_channel_client_is_low_bandwidth(MainChannelClient *mcc); > +uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc); > +uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc); > + > +RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc); > + > +void main_channel_client_push_name(MainChannelClient *mcc, const char > *name); > +void main_channel_client_push_uuid(MainChannelClient *mcc, const uint8_t > uuid[16]); > + > +uint32_t main_channel_client_get_connection_id(MainChannelClient *mcc); > +uint32_t main_channel_client_next_ping_id(MainChannelClient *mcc); > + > +gboolean main_channel_client_get_seamless_migration(MainChannelClient *mcc); > +void main_channel_client_on_send_init(MainChannelClient *mcc); > +gboolean main_channel_client_get_init_sent(MainChannelClient *mcc); > + > +enum { > + RED_PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, > + RED_PIPE_ITEM_TYPE_MAIN_PING, > + RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE, > + RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED, > + RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN, > + RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA, > + RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA, > + RED_PIPE_ITEM_TYPE_MAIN_INIT, > + RED_PIPE_ITEM_TYPE_MAIN_NOTIFY, > + RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN, > + RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS, > + RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST, > + RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME, > + RED_PIPE_ITEM_TYPE_MAIN_NAME, > + RED_PIPE_ITEM_TYPE_MAIN_UUID, > + RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS, > +}; > + > +typedef struct RedPingPipeItem { > + RedPipeItem base; > + int size; > +} RedPingPipeItem; > + > +typedef struct RedMouseModePipeItem { > + RedPipeItem base; > + int current_mode; > + int is_client_mouse_allowed; > +} RedMouseModePipeItem; > + > +typedef struct RedTokensPipeItem { > + RedPipeItem base; > + int tokens; > +} RedTokensPipeItem; > + > +typedef struct RedAgentDataPipeItem { > + RedPipeItem base; > + uint8_t* data; > + size_t len; > + spice_marshaller_item_free_func free_data; > + void *opaque; > +} RedAgentDataPipeItem; > + > +typedef struct RedInitPipeItem { > + RedPipeItem base; > + int connection_id; > + int display_channels_hint; > + int current_mouse_mode; > + int is_client_mouse_allowed; > + int multi_media_time; > + int ram_hint; > +} RedInitPipeItem; > + > +typedef struct RedNamePipeItem { > + RedPipeItem base; > + SpiceMsgMainName msg; > +} RedNamePipeItem; > + > +typedef struct RedUuidPipeItem { > + RedPipeItem base; > + SpiceMsgMainUuid msg; > +} RedUuidPipeItem; > + > +typedef struct RedNotifyPipeItem { > + RedPipeItem base; > + char *msg; > +} RedNotifyPipeItem; > + > +typedef struct RedMultiMediaTimePipeItem { > + RedPipeItem base; > + int time; > +} RedMultiMediaTimePipeItem; > + > +#endif /* __MAIN_CHANNEL_CLIENT_H__ */ > diff --git a/server/main-channel.c b/server/main-channel.c > index 98ce660..7ec8b55 100644 > --- a/server/main-channel.c > +++ b/server/main-channel.c > @@ -41,6 +41,7 @@ > > #include "demarshallers.h" > #include "main-channel.h" > +#include "main-channel-client.h" > #include "red-channel.h" > #include "red-common.h" > #include "reds.h" > @@ -50,121 +51,8 @@ > > #define ZERO_BUF_SIZE 4096 > > -#define NET_TEST_WARMUP_BYTES 0 > -#define NET_TEST_BYTES (1024 * 250) > - > -#define PING_INTERVAL (MSEC_PER_SEC * 10) > - > -#define CLIENT_CONNECTIVITY_TIMEOUT (MSEC_PER_SEC * 30) > - > static const uint8_t zero_page[ZERO_BUF_SIZE] = {0}; > > -enum { > - RED_PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, > - RED_PIPE_ITEM_TYPE_MAIN_PING, > - RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE, > - RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED, > - RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN, > - RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA, > - RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA, > - RED_PIPE_ITEM_TYPE_MAIN_INIT, > - RED_PIPE_ITEM_TYPE_MAIN_NOTIFY, > - RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN, > - RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS, > - RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST, > - RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME, > - RED_PIPE_ITEM_TYPE_MAIN_NAME, > - RED_PIPE_ITEM_TYPE_MAIN_UUID, > - RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS, > -}; > - > -typedef struct RedRefsPipeItem { > - RedPipeItem base; > - int *refs; > -} RedRefsPipeItem; > - > -typedef struct RedPingPipeItem { > - RedPipeItem base; > - int size; > -} RedPingPipeItem; > - > -typedef struct RedMouseModePipeItem { > - RedPipeItem base; > - int current_mode; > - int is_client_mouse_allowed; > -} RedMouseModePipeItem; > - > -typedef struct RedTokensPipeItem { > - RedPipeItem base; > - int tokens; > -} RedTokensPipeItem; > - > -typedef struct RedAgentDataPipeItem { > - RedPipeItem base; > - uint8_t* data; > - size_t len; > - spice_marshaller_item_free_func free_data; > - void *opaque; > -} RedAgentDataPipeItem; > - > -typedef struct RedInitPipeItem { > - RedPipeItem base; > - int connection_id; > - int display_channels_hint; > - int current_mouse_mode; > - int is_client_mouse_allowed; > - int multi_media_time; > - int ram_hint; > -} RedInitPipeItem; > - > -typedef struct RedNamePipeItem { > - RedPipeItem base; > - SpiceMsgMainName msg; > -} RedNamePipeItem; > - > -typedef struct RedUuidPipeItem { > - RedPipeItem base; > - SpiceMsgMainUuid msg; > -} RedUuidPipeItem; > - > -typedef struct RedNotifyPipeItem { > - RedPipeItem base; > - char *msg; > -} RedNotifyPipeItem; > - > -typedef struct RedMultiMediaTimePipeItem { > - RedPipeItem base; > - int time; > -} RedMultiMediaTimePipeItem; > - > -struct MainChannelClient { > - RedChannelClient base; > - uint32_t connection_id; > - uint32_t ping_id; > - uint32_t net_test_id; > - int net_test_stage; > - uint64_t latency; > - uint64_t bitrate_per_sec; > -#ifdef RED_STATISTICS > - SpiceTimer *ping_timer; > - int ping_interval; > -#endif > - int mig_wait_connect; > - int mig_connect_ok; > - int mig_wait_prev_complete; > - int mig_wait_prev_try_seamless; > - int init_sent; > - int seamless_mig_dst; > -}; > - > -enum NetTestStage { > - NET_TEST_STAGE_INVALID, > - NET_TEST_STAGE_WARMUP, > - NET_TEST_STAGE_LATENCY, > - NET_TEST_STAGE_RATE, > - NET_TEST_STAGE_COMPLETE, > -}; > - > static void main_channel_release_pipe_item(RedChannelClient *rcc, > RedPipeItem *base, int > item_pushed); > > @@ -187,35 +75,18 @@ RedClient > *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t c > { > RingItem *link; > MainChannelClient *mcc; > + RedChannelClient *rcc; > > RING_FOREACH(link, &main_chan->base.clients) { > - mcc = SPICE_CONTAINEROF(link, MainChannelClient, base.channel_link); > - if (mcc->connection_id == connection_id) { > - return mcc->base.client; > + rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link); > + mcc = (MainChannelClient*) rcc; > + if (main_channel_client_get_connection_id(mcc) == connection_id) { > + return rcc->client; > } > } > return NULL; > } > > -static int main_channel_client_push_ping(MainChannelClient *mcc, int size); > - > -void main_channel_client_start_net_test(MainChannelClient *mcc, int > test_rate) > -{ > - if (!mcc || mcc->net_test_id) { > - return; > - } > - if (test_rate) { > - if (main_channel_client_push_ping(mcc, NET_TEST_WARMUP_BYTES) > - && main_channel_client_push_ping(mcc, 0) > - && main_channel_client_push_ping(mcc, NET_TEST_BYTES)) { > - mcc->net_test_id = mcc->ping_id - 2; > - mcc->net_test_stage = NET_TEST_STAGE_WARMUP; > - } > - } else { > - red_channel_client_start_connectivity_monitoring(&mcc->base, > CLIENT_CONNECTIVITY_TIMEOUT); > - } > -} > - > typedef struct MainMouseModeItemInfo { > int current_mode; > int is_client_mouse_allowed; > @@ -232,88 +103,8 @@ static RedPipeItem > *main_mouse_mode_item_new(RedChannelClient *rcc, void *data, > return &item->base; > } > > -static RedPipeItem *red_ping_item_new(MainChannelClient *mcc, int size) > -{ > - RedPingPipeItem *item = spice_malloc(sizeof(RedPingPipeItem)); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_PING); > - item->size = size; > - return &item->base; > -} > - > -static RedPipeItem *main_agent_tokens_item_new(RedChannelClient *rcc, > uint32_t num_tokens) > -{ > - RedTokensPipeItem *item = spice_malloc(sizeof(RedTokensPipeItem)); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN); > - item->tokens = num_tokens; > - return &item->base; > -} > - > -static RedPipeItem *main_agent_data_item_new(RedChannelClient *rcc, uint8_t* > data, size_t len, > - spice_marshaller_item_free_func > free_data, > - void *opaque) > -{ > - RedAgentDataPipeItem *item = spice_malloc(sizeof(RedAgentDataPipeItem)); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA); > - item->data = data; > - item->len = len; > - item->free_data = free_data; > - item->opaque = opaque; > - return &item->base; > -} > - > -static RedPipeItem *main_init_item_new(MainChannelClient *mcc, > - int connection_id, int display_channels_hint, int current_mouse_mode, > - int is_client_mouse_allowed, int multi_media_time, > - int ram_hint) > -{ > - RedInitPipeItem *item = spice_malloc(sizeof(RedInitPipeItem)); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_INIT); > - item->connection_id = connection_id; > - item->display_channels_hint = display_channels_hint; > - item->current_mouse_mode = current_mouse_mode; > - item->is_client_mouse_allowed = is_client_mouse_allowed; > - item->multi_media_time = multi_media_time; > - item->ram_hint = ram_hint; > - return &item->base; > -} > - > -static RedPipeItem *main_name_item_new(MainChannelClient *mcc, const char > *name) > -{ > - RedNamePipeItem *item = spice_malloc(sizeof(RedNamePipeItem) + > strlen(name) + 1); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NAME); > - item->msg.name_len = strlen(name) + 1; > - memcpy(&item->msg.name, name, item->msg.name_len); > - > - return &item->base; > -} > - > -static RedPipeItem *main_uuid_item_new(MainChannelClient *mcc, const uint8_t > uuid[16]) > -{ > - RedUuidPipeItem *item = spice_malloc(sizeof(RedUuidPipeItem)); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_UUID); > - memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid)); > - > - return &item->base; > -} > - > -static RedPipeItem *main_notify_item_new(RedChannelClient *rcc, void *data, > int num) > -{ > - RedNotifyPipeItem *item = spice_malloc(sizeof(RedNotifyPipeItem)); > - const char *msg = data; > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NOTIFY); > - item->msg = spice_strdup(msg); > - return &item->base; > -} > - > -static RedPipeItem *main_multi_media_time_item_new( > - RedChannelClient *rcc, void *data, int num) > +static RedPipeItem *main_multi_media_time_item_new(RedChannelClient *rcc, > + void *data, int num) > { > RedMultiMediaTimePipeItem *item, *info = data; > > @@ -325,12 +116,12 @@ static RedPipeItem *main_multi_media_time_item_new( > > static void main_channel_push_channels(MainChannelClient *mcc) > { > - if (red_client_during_migrate_at_target(mcc->base.client)) { > + if > (red_client_during_migrate_at_target((main_channel_client_get_base(mcc))->client)) > { > spice_printerr("warning: ignoring unexpected > SPICE_MSGC_MAIN_ATTACH_CHANNELS" > "during migration"); > return; > } > - red_channel_client_pipe_add_type(&mcc->base, > RED_PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST); > + red_channel_client_pipe_add_type(main_channel_client_get_base(mcc), > RED_PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST); > } > > static void main_channel_marshall_channels(RedChannelClient *rcc, > @@ -345,28 +136,16 @@ static void > main_channel_marshall_channels(RedChannelClient *rcc, > free(channels_info); > } > > -int main_channel_client_push_ping(MainChannelClient *mcc, int size) > -{ > - RedPipeItem *item; > - > - if (mcc == NULL) { > - return FALSE; > - } > - item = red_ping_item_new(mcc, size); > - red_channel_client_pipe_add_push(&mcc->base, item); > - return TRUE; > -} > - > static void main_channel_marshall_ping(RedChannelClient *rcc, > SpiceMarshaller *m, > RedPingPipeItem *item) > { > - MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, > base); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > SpiceMsgPing ping; > int size_left = item->size; > > red_channel_client_init_send_data(rcc, SPICE_MSG_PING, &item->base); > - ping.id = ++(mcc->ping_id); > + ping.id = main_channel_client_next_ping_id(mcc); > ping.timestamp = g_get_monotonic_time(); > spice_marshall_msg_ping(m, &ping); > > @@ -440,13 +219,6 @@ static void > main_channel_marshall_agent_disconnected(RedChannelClient *rcc, > spice_marshall_msg_main_agent_disconnected(m, &disconnect); > } > > -void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t > num_tokens) > -{ > - RedPipeItem *item = main_agent_tokens_item_new(&mcc->base, num_tokens); > - > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > static void main_channel_marshall_tokens(RedChannelClient *rcc, > SpiceMarshaller *m, > RedTokensPipeItem *item) > { > @@ -457,15 +229,6 @@ static void > main_channel_marshall_tokens(RedChannelClient *rcc, > spice_marshall_msg_main_agent_token(m, &tokens); > } > > -void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* > data, size_t len, > - spice_marshaller_item_free_func free_data, void *opaque) > -{ > - RedPipeItem *item; > - > - item = main_agent_data_item_new(&mcc->base, data, len, free_data, > opaque); > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > static void main_channel_marshall_agent_data(RedChannelClient *rcc, > SpiceMarshaller *m, > RedAgentDataPipeItem *item) > @@ -490,7 +253,7 @@ static void > main_channel_marshall_migrate_data_item(RedChannelClient *rcc, > static int main_channel_handle_migrate_data(RedChannelClient *rcc, > uint32_t size, void *message) > { > - MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, > base); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message; > > /* not supported with multi-clients */ > @@ -509,21 +272,6 @@ static int > main_channel_handle_migrate_data(RedChannelClient *rcc, > return reds_handle_migrate_data(rcc->channel->reds, mcc, > (SpiceMigrateDataMain *)(header + 1), size); > } > > -void main_channel_client_push_init(MainChannelClient *mcc, > - int display_channels_hint, > - int current_mouse_mode, > - int is_client_mouse_allowed, > - int multi_media_time, > - int ram_hint) > -{ > - RedPipeItem *item; > - > - item = main_init_item_new(mcc, > - mcc->connection_id, display_channels_hint, current_mouse_mode, > - is_client_mouse_allowed, multi_media_time, ram_hint); > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > static void main_channel_marshall_init(RedChannelClient *rcc, > SpiceMarshaller *m, > RedInitPipeItem *item) > @@ -546,36 +294,6 @@ static void main_channel_marshall_init(RedChannelClient > *rcc, > spice_marshall_msg_main_init(m, &init); > } > > -void main_channel_client_push_name(MainChannelClient *mcc, const char *name) > -{ > - RedPipeItem *item; > - > - if (!red_channel_client_test_remote_cap(&mcc->base, > - SPICE_MAIN_CAP_NAME_AND_UUID)) > - return; > - > - item = main_name_item_new(mcc, name); > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > -void main_channel_client_push_uuid(MainChannelClient *mcc, const uint8_t > uuid[16]) > -{ > - RedPipeItem *item; > - > - if (!red_channel_client_test_remote_cap(&mcc->base, > - SPICE_MAIN_CAP_NAME_AND_UUID)) > - return; > - > - item = main_uuid_item_new(mcc, uuid); > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > -void main_channel_client_push_notify(MainChannelClient *mcc, const char > *msg) > -{ > - RedPipeItem *item = main_notify_item_new(&mcc->base, (void *)msg, 1); > - red_channel_client_pipe_add_push(&mcc->base, item); > -} > - > static void main_channel_marshall_notify(RedChannelClient *rcc, > SpiceMarshaller *m, > RedNotifyPipeItem *item) > { > @@ -701,14 +419,16 @@ static void > main_channel_marshall_multi_media_time(RedChannelClient *rcc, > > static void main_channel_send_item(RedChannelClient *rcc, RedPipeItem *base) > { > - MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, > base); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); > > /* 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 != > RED_PIPE_ITEM_TYPE_MAIN_INIT) { > + if (!main_channel_client_get_init_sent(mcc) && > + !main_channel_client_get_seamless_migration(mcc) && > + base->type != RED_PIPE_ITEM_TYPE_MAIN_INIT) { > spice_printerr("Init msg for client %p was not sent yet " > "(client is probably during semi-seamless migration). > Ignoring msg type %d", > rcc->client, base->type); > @@ -745,7 +465,7 @@ static void main_channel_send_item(RedChannelClient *rcc, > RedPipeItem *base) > main_channel_marshall_migrate_data_item(rcc, m, base); > break; > case RED_PIPE_ITEM_TYPE_MAIN_INIT: > - mcc->init_sent = TRUE; > + main_channel_client_on_send_init(mcc); > main_channel_marshall_init(rcc, m, > SPICE_CONTAINEROF(base, RedInitPipeItem, base)); > break; > @@ -804,77 +524,11 @@ static void > main_channel_release_pipe_item(RedChannelClient *rcc, > free(base); > } > > -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) { > - 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(mcc->base.channel->reds, seamless > && success); > - } > - } else { > - if (success) { > - spice_printerr("client %p MIGRATE_CANCEL", mcc->base.client); > - red_channel_client_pipe_add_empty_msg(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_CANCEL); > - } > - } > -} > - > -void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient > *mcc, > - uint32_t > src_version) > -{ > - if (reds_on_migrate_dst_set_seamless(mcc->base.channel->reds, 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 { > - red_channel_client_pipe_add_empty_msg(&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)) { > - spice_printerr("unexpected SPICE_MSGC_MIGRATE_END"); > - return; > - } > - if (!red_channel_client_test_remote_cap(&mcc->base, > - > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) > { > - spice_printerr("unexpected SPICE_MSGC_MIGRATE_END, " > - "client does not support semi-seamless migration"); > - return; > - } > - red_client_semi_seamless_migrate_complete(mcc->base.client); > -} > - > -void main_channel_client_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, > - > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS); > - } else { > - red_channel_client_pipe_add_type(&mcc->base, > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN); > - } > - mcc->mig_wait_connect = TRUE; > - mcc->mig_wait_prev_complete = FALSE; > - } > -} > - > static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, > uint16_t type, > void *message) > { > MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, > base); > - MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, > base); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > > switch (type) { > case SPICE_MSGC_MAIN_AGENT_START: { > @@ -923,64 +577,7 @@ static int main_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, uint > reds_on_main_mouse_mode_request(rcc->channel->reds, message, size); > break; > case SPICE_MSGC_PONG: { > - SpiceMsgPing *ping = (SpiceMsgPing *)message; > - uint64_t roundtrip; > - > - roundtrip = g_get_monotonic_time() - ping->timestamp; > - > - if (ping->id == mcc->net_test_id) { > - switch (mcc->net_test_stage) { > - case NET_TEST_STAGE_WARMUP: > - mcc->net_test_id++; > - mcc->net_test_stage = NET_TEST_STAGE_LATENCY; > - mcc->latency = roundtrip; > - break; > - case NET_TEST_STAGE_LATENCY: > - mcc->net_test_id++; > - mcc->net_test_stage = NET_TEST_STAGE_RATE; > - mcc->latency = MIN(mcc->latency, roundtrip); > - break; > - case NET_TEST_STAGE_RATE: > - mcc->net_test_id = 0; > - if (roundtrip <= mcc->latency) { > - // probably high load on client or server result with > incorrect values > - spice_printerr("net test: invalid values, latency %" > PRIu64 > - " roundtrip %" PRIu64 ". assuming high" > - " bandwidth", mcc->latency, roundtrip); > - mcc->latency = 0; > - mcc->net_test_stage = NET_TEST_STAGE_INVALID; > - > red_channel_client_start_connectivity_monitoring(&mcc->base, > - > CLIENT_CONNECTIVITY_TIMEOUT); > - break; > - } > - mcc->bitrate_per_sec = (uint64_t)(NET_TEST_BYTES * 8) * > 1000000 > - / (roundtrip - mcc->latency); > - mcc->net_test_stage = NET_TEST_STAGE_COMPLETE; > - spice_printerr("net test: latency %f ms, bitrate %"PRIu64" > bps (%f Mbps)%s", > - (double)mcc->latency / 1000, > - mcc->bitrate_per_sec, > - (double)mcc->bitrate_per_sec / 1024 / 1024, > - main_channel_client_is_low_bandwidth(mcc) ? " LOW > BANDWIDTH" : ""); > - red_channel_client_start_connectivity_monitoring(&mcc->base, > - > CLIENT_CONNECTIVITY_TIMEOUT); > - break; > - default: > - spice_printerr("invalid net test stage, ping id %d test id > %d stage %d", > - ping->id, > - mcc->net_test_id, > - mcc->net_test_stage); > - mcc->net_test_stage = NET_TEST_STAGE_INVALID; > - } > - break; > - } else { > - /* > - * channel client monitors the connectivity using ping-pong > messages > - */ > - red_channel_client_handle_message(rcc, size, type, message); > - } > -#ifdef RED_STATISTICS > - stat_update_value(rcc->channel->reds, roundtrip); > -#endif > + main_channel_client_handle_pong(mcc, (SpiceMsgPing *)message, size); > break; > } > case SPICE_MSGC_DISCONNECTING: > @@ -999,7 +596,7 @@ static uint8_t > *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, > uint32_t size) > { > MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, > base); > - MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, > base); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > > if (type == SPICE_MSGC_MAIN_AGENT_DATA) { > return reds_get_agent_data_buffer(rcc->channel->reds, mcc, size); > @@ -1035,60 +632,6 @@ static int > main_channel_handle_migrate_flush_mark(RedChannelClient *rcc) > return TRUE; > } > > -#ifdef RED_STATISTICS > -static void do_ping_client(MainChannelClient *mcc, > - const char *opt, int has_interval, int interval) > -{ > - spice_printerr(""); > - if (!opt) { > - main_channel_client_push_ping(mcc, 0); > - } else if (!strcmp(opt, "on")) { > - if (has_interval && interval > 0) { > - mcc->ping_interval = interval * MSEC_PER_SEC; > - } > - reds_core_timer_start(mcc->base.channel->reds, mcc->ping_timer, > mcc->ping_interval); > - } else if (!strcmp(opt, "off")) { > - reds_core_timer_cancel(mcc->base.channel->reds, mcc->ping_timer); > - } else { > - return; > - } > -} > - > -static void ping_timer_cb(void *opaque) > -{ > - MainChannelClient *mcc = opaque; > - > - if (!red_channel_client_is_connected(&mcc->base)) { > - spice_printerr("not connected to peer, ping off"); > - reds_core_timer_cancel(mcc->base.channel->reds, mcc->ping_timer); > - return; > - } > - do_ping_client(mcc, NULL, 0, 0); > - reds_core_timer_start(mcc->base.channel->reds, mcc->ping_timer, > mcc->ping_interval); > -} > -#endif /* RED_STATISTICS */ > - > -static MainChannelClient *main_channel_client_create(MainChannel *main_chan, > RedClient *client, > - RedsStream *stream, > uint32_t connection_id, > - int num_common_caps, > uint32_t *common_caps, > - int num_caps, uint32_t > *caps) > -{ > - MainChannelClient *mcc = (MainChannelClient*) > - > red_channel_client_create(sizeof(MainChannelClient), > &main_chan->base, > - client, stream, > FALSE, num_common_caps, > - common_caps, > num_caps, caps); > - spice_assert(mcc != NULL); > - mcc->connection_id = connection_id; > - mcc->bitrate_per_sec = ~0; > -#ifdef RED_STATISTICS > - if (!(mcc->ping_timer = > reds_core_timer_add(red_channel_get_server(&main_chan->base), ping_timer_cb, > mcc))) { > - spice_error("ping timer create failed"); > - } > - mcc->ping_interval = PING_INTERVAL; > -#endif > - return mcc; > -} > - > MainChannelClient *main_channel_link(MainChannel *channel, RedClient > *client, > RedsStream *stream, uint32_t > connection_id, int migration, > int num_common_caps, uint32_t > *common_caps, int num_caps, > @@ -1128,33 +671,6 @@ void main_channel_close(MainChannel *main_chan) > } > } > > -int main_channel_client_is_network_info_initialized(MainChannelClient *mcc) > -{ > - return mcc->net_test_stage == NET_TEST_STAGE_COMPLETE; > -} > - > -int main_channel_client_is_low_bandwidth(MainChannelClient *mcc) > -{ > - // TODO: configurable? > - return mcc->bitrate_per_sec < 10 * 1024 * 1024; > -} > - > -uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc) > -{ > - return mcc->bitrate_per_sec; > -} > - > -uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc) > -{ > - return mcc->latency / 1000; > -} > - > -static void main_channel_client_migrate(RedChannelClient *rcc) > -{ > - reds_on_main_channel_migrate(rcc->channel->reds, SPICE_CONTAINEROF(rcc, > MainChannelClient, base)); > - red_channel_client_default_migrate(rcc); > -} > - > MainChannel* main_channel_new(RedsState *reds) > { > RedChannel *channel; > @@ -1190,33 +706,16 @@ MainChannel* main_channel_new(RedsState *reds) > return (MainChannel *)channel; > } > > -RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc) > -{ > - spice_assert(mcc); > - return &mcc->base; > -} > - > static int main_channel_connect_semi_seamless(MainChannel *main_channel) > { > RingItem *client_link; > > RING_FOREACH(client_link, &main_channel->base.clients) { > - MainChannelClient * mcc = SPICE_CONTAINEROF(client_link, > MainChannelClient, > - base.channel_link); > - if (red_channel_client_test_remote_cap(&mcc->base, > - > SPICE_MAIN_CAP_SEMI_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 = FALSE; > - } else { > - red_channel_client_pipe_add_type(&mcc->base, > - > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN); > - mcc->mig_wait_connect = TRUE; > - } > - mcc->mig_connect_ok = FALSE; > + RedChannelClient *rcc = SPICE_CONTAINEROF(client_link, > RedChannelClient, > + channel_link); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > + if (main_channel_client_connect_semi_seamless(mcc)) > main_channel->num_clients_mig_wait++; > - } > } > return main_channel->num_clients_mig_wait; > } > @@ -1228,20 +727,10 @@ static int main_channel_connect_seamless(MainChannel > *main_channel) > 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, > - > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS); > - mcc->mig_wait_connect = TRUE; > - } > - mcc->mig_connect_ok = FALSE; > + RedChannelClient *rcc = SPICE_CONTAINEROF(client_link, > RedChannelClient, > + channel_link); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > + main_channel_client_connect_seamless(mcc); > main_channel->num_clients_mig_wait++; > } > return main_channel->num_clients_mig_wait; > @@ -1261,12 +750,12 @@ int main_channel_migrate_connect(MainChannel > *main_channel, RedsMigSpice *mig_ta > return main_channel_connect_semi_seamless(main_channel); > } else { > RingItem *client_item; > - MainChannelClient *mcc; > + RedChannelClient *rcc; > > client_item = ring_get_head(&main_channel->base.clients); > - mcc = SPICE_CONTAINEROF(client_item, MainChannelClient, > base.channel_link); > + rcc = SPICE_CONTAINEROF(client_item, RedChannelClient, > channel_link); > > - if (!red_channel_client_test_remote_cap(&mcc->base, > + if (!red_channel_client_test_remote_cap(rcc, > SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) > { > return main_channel_connect_semi_seamless(main_channel); > } else { > @@ -1281,15 +770,10 @@ void main_channel_migrate_cancel_wait(MainChannel > *main_chan) > RingItem *client_link; > > RING_FOREACH(client_link, &main_chan->base.clients) { > - MainChannelClient *mcc; > - > - mcc = SPICE_CONTAINEROF(client_link, MainChannelClient, > base.channel_link); > - if (mcc->mig_wait_connect) { > - spice_printerr("client %p cancel wait connect", > mcc->base.client); > - mcc->mig_wait_connect = FALSE; > - mcc->mig_connect_ok = FALSE; > - } > - mcc->mig_wait_prev_complete = FALSE; > + RedChannelClient *rcc = SPICE_CONTAINEROF(client_link, > RedChannelClient, > + channel_link); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > + main_channel_client_migrate_cancel_wait(mcc); > } > main_chan->num_clients_mig_wait = 0; > } > @@ -1307,29 +791,11 @@ int main_channel_migrate_src_complete(MainChannel > *main_chan, int success) > } > > RING_FOREACH(client_link, &main_chan->base.clients) { > - MainChannelClient *mcc; > - int semi_seamless_support; > - > - mcc = SPICE_CONTAINEROF(client_link, MainChannelClient, > base.channel_link); > - semi_seamless_support = > red_channel_client_test_remote_cap(&mcc->base, > - > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); > - if (semi_seamless_support && mcc->mig_connect_ok) { > - if (success) { > - spice_printerr("client %p MIGRATE_END", mcc->base.client); > - 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_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, > RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST); > - } > - } > - mcc->mig_connect_ok = FALSE; > - mcc->mig_wait_connect = FALSE; > + RedChannelClient *rcc = SPICE_CONTAINEROF(client_link, > RedChannelClient, > + channel_link); > + MainChannelClient *mcc = (MainChannelClient*)rcc; > + if (main_channel_client_migrate_src_complete(mcc, success)) > + semi_seamless_count++; > } > return semi_seamless_count; > } > diff --git a/server/main-channel.h b/server/main-channel.h > index 4eb9a9c..868a14a 100644 > --- a/server/main-channel.h > +++ b/server/main-channel.h > @@ -23,6 +23,7 @@ > #include <common/marshaller.h> > > #include "red-channel.h" > +#include "main-channel-client.h" > > // 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. > @@ -59,34 +60,11 @@ void main_channel_close(MainChannel *main_chan); // not > destroy, just socket clo > void main_channel_push_mouse_mode(MainChannel *main_chan, int current_mode, > int is_client_mouse_allowed); > void main_channel_push_agent_connected(MainChannel *main_chan); > void main_channel_push_agent_disconnected(MainChannel *main_chan); > -void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t > num_tokens); > -void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* > data, size_t len, > - spice_marshaller_item_free_func > free_data, void *opaque); > -void main_channel_client_start_net_test(MainChannelClient *mcc, int > test_rate); > -// TODO: huge. Consider making a reds_* interface for these functions > -// and calling from main. > -void main_channel_client_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_client_push_notify(MainChannelClient *mcc, const char > *msg); > 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); > > -/* > - * return TRUE if network test had been completed successfully. > - * If FALSE, bitrate_per_sec is set to MAX_UINT64 and the roundtrip is set > to 0 > - */ > -int main_channel_client_is_network_info_initialized(MainChannelClient *mcc); > -int main_channel_client_is_low_bandwidth(MainChannelClient *mcc); > -uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc); > -uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc); > - > int main_channel_is_connected(MainChannel *main_chan); > -RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc); > > /* switch host migration */ > void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice > *mig_target); > @@ -100,8 +78,5 @@ int main_channel_migrate_connect(MainChannel > *main_channel, RedsMigSpice *mig_ta > 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_src_complete(MainChannel *main_chan, int success); > -void main_channel_client_migrate_dst_complete(MainChannelClient *mcc); > -void main_channel_client_push_name(MainChannelClient *mcc, const char > *name); > -void main_channel_client_push_uuid(MainChannelClient *mcc, const uint8_t > uuid[16]); > > #endif Beside these small changes patch looks good Acked. Frediano _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel