[Spice-devel] [PATCH 02/10] Move RedChannelClient to separate file
Christophe Fergeau
cfergeau at redhat.com
Thu Sep 1 15:45:56 UTC 2016
On Wed, Aug 31, 2016 at 11:54:38AM -0500, Jonathon Jongsma wrote:
> Reduce direct access to RedChannelClient, and get ready to convert to
> GObject.
> ---
> server/Makefile.am | 2 +
> server/cursor-channel.c | 2 +
> server/dcc-private.h | 1 +
> server/inputs-channel-client.c | 1 +
> server/inputs-channel.c | 1 +
> server/main-channel-client.c | 2 +
> server/main-channel.c | 1 +
> server/red-channel-client.c | 1626 ++++++++++++++++++++++++++++++++++++
> server/red-channel-client.h | 253 ++++++
> server/red-channel.c | 1809 +++-------------------------------------
> server/red-channel.h | 207 +----
> server/red-worker.h | 1 +
> server/reds.c | 1 +
> server/smartcard.c | 2 +-
> server/sound.c | 1 +
> server/spicevmc.c | 1 +
> 16 files changed, 2018 insertions(+), 1893 deletions(-)
> create mode 100644 server/red-channel-client.c
> create mode 100644 server/red-channel-client.h
>
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 24e6e21..e275765 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -95,6 +95,8 @@ libserver_la_SOURCES = \
> mjpeg-encoder.c \
> red-channel.c \
> red-channel.h \
> + red-channel-client.c \
> + red-channel-client.h \
> red-common.h \
> dispatcher.c \
> dispatcher.h \
> diff --git a/server/cursor-channel.c b/server/cursor-channel.c
> index cb3aa49..290f763 100644
> --- a/server/cursor-channel.c
> +++ b/server/cursor-channel.c
> @@ -21,7 +21,9 @@
>
> #include <glib.h>
> #include <common/generated_server_marshallers.h>
> +
> #include "cursor-channel.h"
> +#include "red-channel-client.h"
> #include "cache-item.h"
>
> #define CLIENT_CURSOR_CACHE_SIZE 256
> diff --git a/server/dcc-private.h b/server/dcc-private.h
> index 02b51dd..d5aad3f 100644
> --- a/server/dcc-private.h
> +++ b/server/dcc-private.h
> @@ -22,6 +22,7 @@
> #include "dcc.h"
> #include "image-encoders.h"
> #include "stream.h"
> +#include "red-channel-client.h"
>
> struct DisplayChannelClient {
> RedChannelClient base;
> diff --git a/server/inputs-channel-client.c b/server/inputs-channel-client.c
> index bdbcf5c..ce21b9c 100644
> --- a/server/inputs-channel-client.c
> +++ b/server/inputs-channel-client.c
> @@ -21,6 +21,7 @@
> #include "inputs-channel-client.h"
> #include "inputs-channel.h"
> #include "migration-protocol.h"
> +#include "red-channel-client.h"
>
> struct InputsChannelClient {
> RedChannelClient base;
> diff --git a/server/inputs-channel.c b/server/inputs-channel.c
> index c28273a..da0f027 100644
> --- a/server/inputs-channel.c
> +++ b/server/inputs-channel.c
> @@ -39,6 +39,7 @@
> #include "reds.h"
> #include "reds-stream.h"
> #include "red-channel.h"
> +#include "red-channel-client.h"
> #include "inputs-channel-client.h"
> #include "main-channel-client.h"
> #include "inputs-channel.h"
> diff --git a/server/main-channel-client.c b/server/main-channel-client.c
> index 12151a7..bd339d0 100644
> --- a/server/main-channel-client.c
> +++ b/server/main-channel-client.c
> @@ -23,7 +23,9 @@
> #include "main-channel-client.h"
> #include <common/generated_server_marshallers.h>
>
> +#include "main-channel-client.h"
> #include "main-channel.h"
> +#include "red-channel-client.h"
> #include "reds.h"
>
> #define NET_TEST_WARMUP_BYTES 0
> diff --git a/server/main-channel.c b/server/main-channel.c
> index 8bb874b..24c69a4 100644
> --- a/server/main-channel.c
> +++ b/server/main-channel.c
> @@ -24,6 +24,7 @@
> #include "red-common.h"
> #include "main-channel.h"
> #include "reds.h"
> +#include "red-channel-client.h"
>
> int main_channel_is_connected(MainChannel *main_chan)
> {
> diff --git a/server/red-channel-client.c b/server/red-channel-client.c
> new file mode 100644
> index 0000000..253e30e
> --- /dev/null
> +++ b/server/red-channel-client.c
> @@ -0,0 +1,1626 @@
> +
> +static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
> +{
> + RedChannel *channel = red_channel_client_get_channel(rcc);
> + if (channel->channel_cbs.handle_migrate_flush_mark) {
> + channel->channel_cbs.handle_migrate_flush_mark(rcc);
> + }
> +}
> +
> +// TODO: the whole migration is broken with multiple clients. What do we want to do?
> +// basically just
> +// 1) source send mark to all
> +// 2) source gets at various times the data (waits for all)
> +// 3) source migrates to target
> +// 4) target sends data to all
> +// So need to make all the handlers work with per channel/client data (what data exactly?)
> +static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
Just to be sure, these 2 functions were intended to be moved? They are
not in the red_channel_client_ namespace but in the red_channel_ one.
> +{
> + RedChannel *channel = red_channel_client_get_channel(rcc);
> + spice_debug("channel type %d id %d rcc %p size %u",
> + channel->type, channel->id, rcc, size);
> + if (!channel->channel_cbs.handle_migrate_data) {
> + return;
> + }
> + if (!red_channel_client_is_waiting_for_migrate_data(rcc)) {
> + spice_channel_client_error(rcc, "unexpected");
> + return;
> + }
> + if (channel->channel_cbs.handle_migrate_data_get_serial) {
> + red_channel_client_set_message_serial(rcc,
> + channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
> + }
> + if (!channel->channel_cbs.handle_migrate_data(rcc, size, message)) {
> + spice_channel_client_error(rcc, "handle_migrate_data failed");
> + return;
> + }
> + red_channel_client_seamless_migration_done(rcc);
> +}
> +
> +
> +int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
> + uint16_t type, void *message)
> +{
> + switch (type) {
> + case SPICE_MSGC_ACK_SYNC:
> + if (size != sizeof(uint32_t)) {
> + spice_printerr("bad message size");
> + return FALSE;
> + }
> + rcc->ack_data.client_generation = *(uint32_t *)(message);
> + break;
> + case SPICE_MSGC_ACK:
> + if (rcc->ack_data.client_generation == rcc->ack_data.generation) {
> + rcc->ack_data.messages_window -= rcc->ack_data.client_window;
> + red_channel_client_push(rcc);
> + }
> + break;
> + case SPICE_MSGC_DISCONNECTING:
> + break;
> + case SPICE_MSGC_MIGRATE_FLUSH_MARK:
> + if (!rcc->wait_migrate_flush_mark) {
> + spice_error("unexpected flush mark");
> + return FALSE;
> + }
> + red_channel_handle_migrate_flush_mark(rcc);
> + rcc->wait_migrate_flush_mark = FALSE;
> + break;
> + case SPICE_MSGC_MIGRATE_DATA:
> + red_channel_handle_migrate_data(rcc, size, message);
> + break;
> + case SPICE_MSGC_PONG:
> + red_channel_client_handle_pong(rcc, message);
> + break;
> + default:
> + spice_printerr("invalid message type %u", type);
> + return FALSE;
> + }
> + return TRUE;
> +}
> +
> +void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, RedPipeItem *item)
> +{
> + spice_assert(red_channel_client_no_item_being_sent(rcc));
> + spice_assert(msg_type != 0);
> + rcc->send_data.header.set_msg_type(&rcc->send_data.header, msg_type);
> + rcc->send_data.item = item;
> + if (item) {
> + red_pipe_item_ref(item);
> + }
> +}
> +
> +void red_channel_client_begin_send_message(RedChannelClient *rcc)
> +{
> + SpiceMarshaller *m = rcc->send_data.marshaller;
> +
> + // TODO - better check: type in channel_allowed_types. Better: type in channel_allowed_types(channel_state)
> + if (rcc->send_data.header.get_msg_type(&rcc->send_data.header) == 0) {
> + spice_printerr("BUG: header->type == 0");
> + return;
> + }
> +
> + /* canceling the latency test timer till the nework is idle */
> + red_channel_client_cancel_ping_timer(rcc);
> +
> + spice_marshaller_flush(m);
> + rcc->send_data.size = spice_marshaller_get_total_size(m);
> + rcc->send_data.header.set_msg_size(&rcc->send_data.header,
> + rcc->send_data.size - rcc->send_data.header.header_size);
> + rcc->ack_data.messages_window++;
> + rcc->send_data.last_sent_serial = rcc->send_data.serial;
> + rcc->send_data.header.data = NULL; /* avoid writing to this until we have a new message */
> + red_channel_client_send(rcc);
> +}
> +
> +SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rcc)
> +{
> + spice_assert(red_channel_client_no_item_being_sent(rcc));
> + spice_assert(rcc->send_data.header.data != NULL);
> + rcc->send_data.main.header_data = rcc->send_data.header.data;
> + rcc->send_data.main.item = rcc->send_data.item;
> +
> + rcc->send_data.marshaller = rcc->send_data.urgent.marshaller;
> + rcc->send_data.item = NULL;
> + red_channel_client_reset_send_data(rcc);
> + return rcc->send_data.marshaller;
> +}
> +
> +uint64_t red_channel_client_get_message_serial(RedChannelClient *rcc)
> +{
> + return rcc->send_data.serial;
> +}
> +
> +void red_channel_client_set_message_serial(RedChannelClient *rcc, uint64_t serial)
> +{
> + rcc->send_data.last_sent_serial = serial;
> + rcc->send_data.serial = serial;
> +}
> +
> +static inline gboolean client_pipe_add(RedChannelClient *rcc, RedPipeItem *item, RingItem *pos)
> +{
> + spice_assert(rcc && item);
> + if (SPICE_UNLIKELY(!red_channel_client_is_connected(rcc))) {
> + spice_debug("rcc is disconnected %p", rcc);
> + red_pipe_item_unref(item);
> + return FALSE;
> + }
> + if (ring_is_empty(&rcc->pipe) && rcc->stream->watch) {
> + rcc->channel->core->watch_update_mask(rcc->stream->watch,
> + SPICE_WATCH_EVENT_READ |
> + SPICE_WATCH_EVENT_WRITE);
> + }
> + rcc->pipe_size++;
> + ring_add(pos, &item->link);
> + return TRUE;
> +}
> +
> +void red_channel_client_pipe_add(RedChannelClient *rcc, RedPipeItem *item)
> +{
> +
> + client_pipe_add(rcc, item, &rcc->pipe);
> +}
> +
> +void red_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item)
> +{
> + red_channel_client_pipe_add(rcc, item);
> + red_channel_client_push(rcc);
> +}
> +
> +void red_channel_client_pipe_add_after(RedChannelClient *rcc,
> + RedPipeItem *item,
> + RedPipeItem *pos)
> +{
> + spice_assert(pos);
> + client_pipe_add(rcc, item, &pos->link);
> +}
> +
> +int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
> + RedPipeItem *item)
> +{
> + return ring_item_is_linked(&item->link);
> +}
> +
> +void red_channel_client_pipe_add_tail(RedChannelClient *rcc,
> + RedPipeItem *item)
> +{
> + client_pipe_add(rcc, item, rcc->pipe.prev);
> +}
> +
> +void red_channel_client_pipe_add_tail_and_push(RedChannelClient *rcc, RedPipeItem *item)
> +{
> + if (client_pipe_add(rcc, item, rcc->pipe.prev)) {
> + red_channel_client_push(rcc);
> + }
> +}
> +
> +void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type)
> +{
> + RedPipeItem *item = spice_new(RedPipeItem, 1);
> +
> + red_pipe_item_init(item, pipe_item_type);
> + red_channel_client_pipe_add(rcc, item);
> + red_channel_client_push(rcc);
> +}
> +
> +void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type)
> +{
> + RedEmptyMsgPipeItem *item = spice_new(RedEmptyMsgPipeItem, 1);
> +
> + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_EMPTY_MSG);
> + item->msg = msg_type;
> + red_channel_client_pipe_add(rcc, &item->base);
> + red_channel_client_push(rcc);
> +}
> +
> +gboolean red_channel_client_pipe_is_empty(RedChannelClient *rcc)
> +{
> + g_return_val_if_fail(rcc != NULL, TRUE);
> + return (rcc->pipe_size == 0) && (ring_is_empty(&rcc->pipe));
> +}
> +
> +uint32_t red_channel_client_get_pipe_size(RedChannelClient *rcc)
> +{
> + return rcc->pipe_size;
> +}
> +
> +int red_channel_client_is_connected(RedChannelClient *rcc)
> +{
> + if (!rcc->dummy) {
> + return rcc->channel
> + && (g_list_find(rcc->channel->clients, rcc) != NULL);
> + } else {
> + return rcc->dummy_connected;
> + }
> +}
> +
> +static void red_channel_client_clear_sent_item(RedChannelClient *rcc)
> +{
> + red_channel_client_release_sent_item(rcc);
> + rcc->send_data.blocked = FALSE;
> + rcc->send_data.size = 0;
> +}
> +
> +static void red_channel_client_pipe_clear(RedChannelClient *rcc)
> +{
> + RedPipeItem *item;
> +
> + if (rcc) {
> + red_channel_client_clear_sent_item(rcc);
> + }
> + while ((item = (RedPipeItem *)ring_get_head(&rcc->pipe))) {
> + ring_remove(&item->link);
> + red_pipe_item_unref(item);
> + }
> + rcc->pipe_size = 0;
> +}
> +
> +void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
> +{
> + rcc->ack_data.messages_window = 0;
> +}
> +
> +void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window)
> +{
> + rcc->ack_data.client_window = client_window;
> +}
> +
> +void red_channel_client_push_set_ack(RedChannelClient *rcc)
> +{
> + red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_SET_ACK);
> +}
> +
> +static void red_channel_client_disconnect_dummy(RedChannelClient *rcc)
> +{
> + RedChannel *channel = red_channel_client_get_channel(rcc);
> + GList *link;
> + spice_assert(rcc->dummy);
> + if (channel && (link = g_list_find(channel->clients, rcc))) {
> + spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
> + channel->type, channel->id);
> + red_channel_remove_client(channel, link->data);
> + }
> + rcc->dummy_connected = FALSE;
> +}
> +
> +void red_channel_client_disconnect(RedChannelClient *rcc)
> +{
> + RedChannel *channel = rcc->channel;
> +
> + if (rcc->dummy) {
> + red_channel_client_disconnect_dummy(rcc);
> + return;
> + }
> + if (!red_channel_client_is_connected(rcc)) {
> + return;
> + }
> + spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
> + channel->type, channel->id);
> + red_channel_client_pipe_clear(rcc);
> + if (rcc->stream->watch) {
> + channel->core->watch_remove(rcc->stream->watch);
> + rcc->stream->watch = NULL;
> + }
> + if (rcc->latency_monitor.timer) {
> + channel->core->timer_remove(rcc->latency_monitor.timer);
> + rcc->latency_monitor.timer = NULL;
> + }
> + if (rcc->connectivity_monitor.timer) {
> + channel->core->timer_remove(rcc->connectivity_monitor.timer);
> + rcc->connectivity_monitor.timer = NULL;
> + }
> + red_channel_remove_client(channel, rcc);
> + channel->channel_cbs.on_disconnect(rcc);
> +}
> +
> +int red_channel_client_is_blocked(RedChannelClient *rcc)
> +{
> + return rcc && rcc->send_data.blocked;
> +}
> +
> +int red_channel_client_send_message_pending(RedChannelClient *rcc)
> +{
> + return rcc->send_data.header.get_msg_type(&rcc->send_data.header) != 0;
> +}
> +
> +SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc)
> +{
> + return rcc->send_data.marshaller;
> +}
> +
> +RedsStream *red_channel_client_get_stream(RedChannelClient *rcc)
> +{
> + return rcc->stream;
> +}
> +
> +RedClient *red_channel_client_get_client(RedChannelClient *rcc)
> +{
> + return rcc->client;
> +}
> +
> +void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_list)
> +{
> + rcc->send_data.header.set_msg_sub_list(&rcc->send_data.header, sub_list);
> +}
> +
> +static void marker_pipe_item_free(RedPipeItem *base)
> +{
> + MarkerPipeItem *item = SPICE_UPCAST(MarkerPipeItem, base);
> +
> + if (item->item_in_pipe) {
> + *item->item_in_pipe = FALSE;
> + }
> + free(item);
> +}
> +
> +/* TODO: more evil sync stuff. anything with the word wait in it's name. */
> +int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
> + RedPipeItem *item,
> + int64_t timeout)
> +{
> + uint64_t end_time;
> + gboolean item_in_pipe;
> +
> + spice_info(NULL);
> +
> + if (timeout != -1) {
> + end_time = spice_get_monotonic_time_ns() + timeout;
> + } else {
> + end_time = UINT64_MAX;
> + }
> +
> + MarkerPipeItem *mark_item = spice_new0(MarkerPipeItem, 1);
> +
> + red_pipe_item_init_full(&mark_item->base, RED_PIPE_ITEM_TYPE_MARKER,
> + marker_pipe_item_free);
> + item_in_pipe = TRUE;
> + mark_item->item_in_pipe = &item_in_pipe;
> + red_channel_client_pipe_add_after(rcc, &mark_item->base, item);
> +
> + if (red_channel_client_is_blocked(rcc)) {
> + red_channel_client_receive(rcc);
> + red_channel_client_send(rcc);
> + }
> + red_channel_client_push(rcc);
> +
> + while(item_in_pipe &&
> + (timeout == -1 || spice_get_monotonic_time_ns() < end_time)) {
> + usleep(CHANNEL_BLOCKED_SLEEP_DURATION);
> + red_channel_client_receive(rcc);
> + red_channel_client_send(rcc);
> + red_channel_client_push(rcc);
> + }
> +
> + if (item_in_pipe) {
> + // still on the queue, make sure won't overwrite the stack variable
> + mark_item->item_in_pipe = NULL;
> + spice_warning("timeout");
> + return FALSE;
> + } else {
> + return red_channel_client_wait_outgoing_item(rcc,
> + timeout == -1 ? -1 : end_time - spice_get_monotonic_time_ns());
> + }
> +}
> +
> +int red_channel_client_wait_outgoing_item(RedChannelClient *rcc,
> + int64_t timeout)
> +{
> + uint64_t end_time;
> + int blocked;
> +
> + if (!red_channel_client_is_blocked(rcc)) {
> + return TRUE;
> + }
> + if (timeout != -1) {
> + end_time = spice_get_monotonic_time_ns() + timeout;
> + } else {
> + end_time = UINT64_MAX;
> + }
> + spice_info("blocked");
> +
> + do {
> + usleep(CHANNEL_BLOCKED_SLEEP_DURATION);
> + red_channel_client_receive(rcc);
> + red_channel_client_send(rcc);
> + } while ((blocked = red_channel_client_is_blocked(rcc)) &&
> + (timeout == -1 || spice_get_monotonic_time_ns() < end_time));
> +
> + if (blocked) {
> + spice_warning("timeout");
> + return FALSE;
> + } else {
> + spice_assert(red_channel_client_no_item_being_sent(rcc));
> + return TRUE;
> + }
> +}
> +
> +void red_channel_client_disconnect_if_pending_send(RedChannelClient *rcc)
> +{
> + if (red_channel_client_is_blocked(rcc) || rcc->pipe_size > 0) {
> + red_channel_client_disconnect(rcc);
> + } else {
> + spice_assert(red_channel_client_no_item_being_sent(rcc));
> + }
> +}
> +
> +gboolean red_channel_client_no_item_being_sent(RedChannelClient *rcc)
> +{
> + return !rcc || (rcc->send_data.size == 0);
> +}
> +
> +void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc,
> + RedPipeItem *item)
> +{
> + red_channel_client_pipe_remove(rcc, item);
> + red_pipe_item_unref(item);
> +}
> +
> +/* client mutex should be locked before this call */
> +gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc)
> +{
> + gboolean ret = FALSE;
> +
> + if (rcc->channel->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
> + rcc->wait_migrate_data = TRUE;
> + ret = TRUE;
> + }
> + spice_debug("channel type %d id %d rcc %p wait data %d", rcc->channel->type, rcc->channel->id, rcc,
> + rcc->wait_migrate_data);
> +
> + return ret;
> +}
> +
> +void red_channel_client_set_destroying(RedChannelClient *rcc)
> +{
> + rcc->destroying = TRUE;
> +}
> +
> +gboolean red_channel_client_is_destroying(RedChannelClient *rcc)
> +{
> + return rcc->destroying;
> +}
> diff --git a/server/red-channel-client.h b/server/red-channel-client.h
> new file mode 100644
> index 0000000..bacfeb5
> --- /dev/null
> +++ b/server/red-channel-client.h
> @@ -0,0 +1,253 @@
> +/*
> + 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 _H_RED_CHANNEL_CLIENT
> +#define _H_RED_CHANNEL_CLIENT
> +
> +#include <common/marshaller.h>
> +
> +#include "red-pipe-item.h"
> +#include "reds-stream.h"
> +#include "red-channel.h"
> +
> +typedef struct RedChannel RedChannel;
> +typedef struct RedClient RedClient;
> +typedef struct IncomingHandler IncomingHandler;
> +
> +typedef struct RedChannelClient RedChannelClient;
> +
> +/*
> + * When an error occurs over a channel, we treat it as a warning
> + * for spice-server and shutdown the channel.
> + */
> +#define spice_channel_client_error(rcc, format, ...) \
> + do { \
> + RedChannel *_ch = red_channel_client_get_channel(rcc); \
> + spice_warning("rcc %p type %u id %u: " format, rcc, \
> + _ch->type, _ch->id, ## __VA_ARGS__); \
> + red_channel_client_shutdown(rcc); \
> + } while (0)
> +
> +RedChannelClient *red_channel_client_create(int size, RedChannel *channel,
> + RedClient *client, RedsStream *stream,
> + int monitor_latency,
> + int num_common_caps, uint32_t *common_caps,
> + int num_caps, uint32_t *caps);
> +
> +RedChannelClient *red_channel_client_create_dummy(int size,
> + RedChannel *channel,
> + RedClient *client,
> + int num_common_caps, uint32_t *common_caps,
> + int num_caps, uint32_t *caps);
> +
> +void red_channel_client_ref(RedChannelClient *rcc);
> +void red_channel_client_unref(RedChannelClient *rcc);
> +
> +int red_channel_client_is_connected(RedChannelClient *rcc);
> +void red_channel_client_default_migrate(RedChannelClient *rcc);
> +int red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc);
> +void red_channel_client_destroy(RedChannelClient *rcc);
> +int red_channel_client_test_remote_common_cap(RedChannelClient *rcc, uint32_t cap);
> +int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap);
> +/* shutdown is the only safe thing to do out of the client/channel
> + * thread. It will not touch the rings, just shutdown the socket.
> + * It should be followed by some way to gurantee a disconnection. */
> +void red_channel_client_shutdown(RedChannelClient *rcc);
> +/* handles general channel msgs from the client */
> +int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
> + uint16_t type, void *message);
> +/* when preparing send_data: should call init and then use marshaller */
> +void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, RedPipeItem *item);
> +
> +uint64_t red_channel_client_get_message_serial(RedChannelClient *channel);
> +void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t);
> +
> +/* When sending a msg. Should first call red_channel_client_begin_send_message.
> + * It will first send the pending urgent data, if there is any, and then
> + * the rest of the data.
> + */
> +void red_channel_client_begin_send_message(RedChannelClient *rcc);
> +
> +/*
> + * Stores the current send data, and switches to urgent send data.
> + * When it begins the actual send, it will send first the urgent data
> + * and afterward the rest of the data.
> + * Should be called only if during the marshalling of on message,
> + * the need to send another message, before, rises.
> + * Important: the serial of the non-urgent sent data, will be succeeded.
> + * return: the urgent send data marshaller
> + */
> +SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rcc);
> +
> +/* returns -1 if we don't have an estimation */
> +int red_channel_client_get_roundtrip_ms(RedChannelClient *rcc);
> +
> +/* Checks periodically if the connection is still alive */
> +void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms);
> +
> +void red_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item);
> +void red_channel_client_pipe_add(RedChannelClient *rcc, RedPipeItem *item);
> +void red_channel_client_pipe_add_after(RedChannelClient *rcc, RedPipeItem *item, RedPipeItem *pos);
> +int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc, RedPipeItem *item);
> +void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc, RedPipeItem *item);
> +void red_channel_client_pipe_add_tail(RedChannelClient *rcc, RedPipeItem *item);
> +void red_channel_client_pipe_add_tail_and_push(RedChannelClient *rcc, RedPipeItem *item);
> +/* for types that use this routine -> the pipe item should be freed */
> +void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type);
> +void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type);
> +gboolean red_channel_client_pipe_is_empty(RedChannelClient *rcc);
> +uint32_t red_channel_client_get_pipe_size(RedChannelClient *rcc);
> +
> +void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
> +void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
> +void red_channel_client_push_set_ack(RedChannelClient *rcc);
> +
> +gboolean red_channel_client_is_blocked(RedChannelClient *rcc);
> +
> +/* helper for channels that have complex logic that can possibly ready a send */
> +int red_channel_client_send_message_pending(RedChannelClient *rcc);
> +
> +gboolean red_channel_client_no_item_being_sent(RedChannelClient *rcc);
> +void red_channel_client_push(RedChannelClient *rcc);
> +// TODO: again - what is the context exactly? this happens in channel disconnect. but our
> +// current red_channel_shutdown also closes the socket - is there a socket to close?
> +// are we reading from an fd here? arghh
> +void red_channel_client_receive(RedChannelClient *rcc);
> +void red_channel_client_send(RedChannelClient *rcc);
> +void red_channel_client_disconnect(RedChannelClient *rcc);
> +
> +/* Note: the valid times to call red_channel_get_marshaller are just during send_item callback. */
> +SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc);
> +RedsStream *red_channel_client_get_stream(RedChannelClient *rcc);
> +RedClient *red_channel_client_get_client(RedChannelClient *rcc);
> +
> +/* Note that the header is valid only between red_channel_reset_send_data and
> + * red_channel_begin_send_message.*/
> +void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_list);
> +
> +/*
> + * blocking functions.
> + *
> + * timeout is in nano sec. -1 for no timeout.
> + *
> + * Return: TRUE if waiting succeeded. FALSE if timeout expired.
> + */
> +
> +int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
> + RedPipeItem *item,
> + int64_t timeout);
> +int red_channel_client_wait_outgoing_item(RedChannelClient *rcc,
> + int64_t timeout);
> +void red_channel_client_disconnect_if_pending_send(RedChannelClient *rcc);
> +
> +RedChannel* red_channel_client_get_channel(RedChannelClient* rcc);
> +IncomingHandler* red_channel_client_get_incoming_handler(RedChannelClient *rcc);
> +
> +void red_channel_client_on_output(void *opaque, int n);
> +void red_channel_client_on_input(void *opaque, int n);
> +int red_channel_client_get_out_msg_size(void *opaque);
> +void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
> + int *vec_size, int pos);
> +void red_channel_client_on_out_block(void *opaque);
> +void red_channel_client_on_out_msg_done(void *opaque);
> +
> +void red_channel_client_seamless_migration_done(RedChannelClient *rcc);
> +void red_channel_client_semi_seamless_migration_complete(RedChannelClient *rcc);
> +void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc);
> +
> +gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc);
> +void red_channel_client_set_destroying(RedChannelClient *rcc);
> +gboolean red_channel_client_is_destroying(RedChannelClient *rcc);
> +
> +#define RED_CHANNEL_CLIENT(Client) ((RedChannelClient *)(Client))
> +
> +typedef struct OutgoingHandler {
> + OutgoingHandlerInterface *cb;
> + void *opaque;
> + struct iovec vec_buf[IOV_MAX];
> + int vec_size;
> + struct iovec *vec;
> + int pos;
> + int size;
> +} OutgoingHandler;
> +
> +typedef struct IncomingHandler {
> + IncomingHandlerInterface *cb;
> + void *opaque;
> + uint8_t header_buf[MAX_HEADER_SIZE];
> + SpiceDataHeaderOpaque header;
> + uint32_t header_pos;
> + uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
> + uint32_t msg_pos;
> + uint64_t serial;
> +} IncomingHandler;
> +
> +struct RedChannelClient {
> + RedChannel *channel;
> + RedClient *client;
> + RedsStream *stream;
> + int dummy;
> + int dummy_connected;
> +
> + uint32_t refs;
> +
> + struct {
> + uint32_t generation;
> + uint32_t client_generation;
> + uint32_t messages_window;
> + uint32_t client_window;
> + } ack_data;
> +
> + struct {
> + SpiceMarshaller *marshaller;
> + SpiceDataHeaderOpaque header;
> + uint32_t size;
> + RedPipeItem *item;
> + int blocked;
> + uint64_t serial;
> + uint64_t last_sent_serial;
> +
> + struct {
> + SpiceMarshaller *marshaller;
> + uint8_t *header_data;
> + RedPipeItem *item;
> + } main;
> +
> + struct {
> + SpiceMarshaller *marshaller;
> + } urgent;
> + } send_data;
> +
> + OutgoingHandler outgoing;
> + IncomingHandler incoming;
> + int during_send;
> + int id; // debugging purposes
> + Ring pipe;
> + uint32_t pipe_size;
> +
> + RedChannelCapabilities remote_caps;
> + int is_mini_header;
> + gboolean destroying;
> +
> + int wait_migrate_data;
> + int wait_migrate_flush_mark;
> +
> + RedChannelClientLatencyMonitor latency_monitor;
> + RedChannelClientConnectivityMonitor connectivity_monitor;
> +};
> +
> +#endif /* _H_RED_CHANNEL_CLIENT */
> diff --git a/server/red-channel.c b/server/red-channel.c
> index bf290b1..03338aa 100644
> --- a/server/red-channel.c
> +++ b/server/red-channel.c
> @@ -2179,11 +707,7 @@ void red_client_semi_seamless_migrate_complete(RedClient *client)
> link = client->channels;
> while (link) {
> next = link->next;
> - RedChannelClient *rcc = link->data;
> -
> - if (rcc->latency_monitor.timer) {
> - red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
> - }
> + red_channel_client_semi_seamless_migration_complete(link->data);
Non-obvious name given the code it replaces, but I guess you
double-checked that's a good name?
> diff --git a/server/red-channel.h b/server/red-channel.h
> index 370f6a7..68bfc7a 100644
> --- a/server/red-channel.h
> +++ b/server/red-channel.h
> @@ -500,24 +345,13 @@ int red_channel_all_blocked(RedChannel *channel);
> /* return TRUE if any of the connected clients to this channel are blocked */
> int red_channel_any_blocked(RedChannel *channel);
>
> -int red_channel_client_is_blocked(RedChannelClient *rcc);
> -
> -/* helper for channels that have complex logic that can possibly ready a send */
> -int red_channel_client_send_message_pending(RedChannelClient *rcc);
> -
> int red_channel_no_item_being_sent(RedChannel *channel);
> -int red_channel_client_no_item_being_sent(RedChannelClient *rcc);
>
> // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
> // adding elements or on events. but not sure if this is actually required (only result
> // should be that they ""try"" a little harder, but if the event system is correct it
> // should not make any difference.
> void red_channel_push(RedChannel *channel);
> -void red_channel_client_push(RedChannelClient *rcc);
> -// TODO: again - what is the context exactly? this happens in channel disconnect. but our
> -// current red_channel_shutdown also closes the socket - is there a socket to close?
> -// are we reading from an fd here? arghh
> -void red_channel_client_pipe_clear(RedChannelClient *rcc);
Note that this comment is attached to red_channel_client_pipe_clear().
In the new header, _pipe_clear() is static and the header now has
> +// TODO: again - what is the context exactly? this happens in channel disconnect. but our
> +// current red_channel_shutdown also closes the socket - is there a socket to close?
> +// are we reading from an fd here? arghh
> +void red_channel_client_receive(RedChannelClient *rcc);
Christophe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20160901/6153ff4c/attachment-0001.sig>
More information about the Spice-devel
mailing list