[Spice-devel] [PATCH 02/11] Move MainChannelClient to separate file
Frediano Ziglio
fziglio at redhat.com
Fri May 13 08:25:17 UTC 2016
>
> 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
More information about the Spice-devel
mailing list