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
Attachment:
signature.asc
Description: PGP signature
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel