[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