[Spice-devel] [PATCH 14/14] Convert RedChannel heirarchy to GObject
Jonathon Jongsma
jjongsma at redhat.com
Tue May 3 20:00:30 UTC 2016
When using private structs with GObject, there's a maximum size of (I
think) 64k, which was exceeded by the DisplayChannel object. To make
this work, I had to make several of the arrays here dynamically
allocated rather than statically allocated.
---
server/Makefile.am | 5 +
server/common-graphics-channel-client.c | 3 +-
server/common-graphics-channel-client.h | 3 +-
server/common-graphics-channel.c | 181 ++++++++
server/common-graphics-channel.h | 98 +++++
server/cursor-channel.c | 126 +++---
server/cursor-channel.h | 37 +-
server/dcc-send.c | 44 +-
server/dcc.c | 61 +--
server/dcc.h | 4 +-
server/display-channel-private.h | 81 ++++
server/display-channel.c | 726 ++++++++++++++++++++------------
server/display-channel.h | 158 +++----
server/dummy-channel-client.c | 17 +-
server/dummy-channel.c | 58 +++
server/dummy-channel.h | 61 +++
server/inputs-channel.c | 262 +++++++-----
server/inputs-channel.h | 30 ++
server/main-channel-client.c | 47 +--
server/main-channel-client.h | 4 +-
server/main-channel.c | 241 ++++++-----
server/main-channel.h | 44 +-
server/red-channel-client-private.h | 19 +
server/red-channel-client.c | 197 +++++----
server/red-channel-client.h | 6 +-
server/red-channel.c | 684 ++++++++++++++++++++----------
server/red-channel.h | 190 ++++-----
server/red-parse-qxl.h | 2 +
server/red-qxl.c | 21 +-
server/red-replay-qxl.c | 2 +-
server/red-worker.c | 197 ++-------
server/red-worker.h | 64 ---
server/reds-private.h | 3 +-
server/reds.c | 67 +--
server/smartcard.c | 131 ++++--
server/sound.c | 43 +-
server/spicevmc.c | 339 ++++++++++-----
server/stream.c | 67 +--
server/stream.h | 3 -
39 files changed, 2753 insertions(+), 1573 deletions(-)
create mode 100644 server/common-graphics-channel.c
create mode 100644 server/common-graphics-channel.h
create mode 100644 server/display-channel-private.h
create mode 100644 server/dummy-channel.c
create mode 100644 server/dummy-channel.h
diff --git a/server/Makefile.am b/server/Makefile.am
index b1de055..2679082 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -73,6 +73,8 @@ libserver_la_SOURCES = \
cache-item.h \
char-device.c \
char-device.h \
+ common-graphics-channel.c \
+ common-graphics-channel.h \
common-graphics-channel-client.c \
common-graphics-channel-client.h \
common-graphics-channel-client-private.h \
@@ -102,6 +104,8 @@ libserver_la_SOURCES = \
red-channel-client.c \
red-channel-client.h \
red-channel-client-private.h \
+ dummy-channel.c \
+ dummy-channel.h \
dummy-channel-client.c \
dummy-channel-client.h \
red-common.h \
@@ -124,6 +128,7 @@ libserver_la_SOURCES = \
red-worker.h \
display-channel.c \
display-channel.h \
+ display-channel-private.h \
cursor-channel-client.c \
cursor-channel-client.h \
cursor-channel.c \
diff --git a/server/common-graphics-channel-client.c b/server/common-graphics-channel-client.c
index e83855b..6277d0b 100644
--- a/server/common-graphics-channel-client.c
+++ b/server/common-graphics-channel-client.c
@@ -19,6 +19,7 @@
#endif
#include "common-graphics-channel-client-private.h"
+#include "common-graphics-channel.h"
#include "dcc.h"
#include "red-channel-client.h"
@@ -89,7 +90,7 @@ static void common_graphics_channel_client_constructed(GObject *object)
self->priv->is_low_bandwidth ?
WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
- channel->during_target_migrate = self->priv->migration_target;
+ common_graphics_channel_set_during_target_migrate(channel, self->priv->migration_target);
}
static void common_graphics_channel_client_class_init(CommonGraphicsChannelClientClass *klass)
diff --git a/server/common-graphics-channel-client.h b/server/common-graphics-channel-client.h
index dc1173a..7acb3a2 100644
--- a/server/common-graphics-channel-client.h
+++ b/server/common-graphics-channel-client.h
@@ -21,6 +21,8 @@
#include "red-common.h"
#include "red-channel-client.h"
+#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30)
+
G_BEGIN_DECLS
#define TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT common_graphics_channel_client_get_type()
@@ -49,7 +51,6 @@ struct CommonGraphicsChannelClientClass
GType common_graphics_channel_client_get_type(void) G_GNUC_CONST;
-typedef struct CommonGraphicsChannel CommonGraphicsChannel;
typedef struct RedClient RedClient;
typedef struct RedsStream RedsStream;
diff --git a/server/common-graphics-channel.c b/server/common-graphics-channel.c
new file mode 100644
index 0000000..fe211aa
--- /dev/null
+++ b/server/common-graphics-channel.c
@@ -0,0 +1,181 @@
+/* common-graphics-channel.c */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include "common-graphics-channel.h"
+#include "common-graphics-channel-client.h"
+
+#define CHANNEL_RECEIVE_BUF_SIZE 1024
+
+G_DEFINE_ABSTRACT_TYPE(CommonGraphicsChannel, common_graphics_channel, RED_TYPE_CHANNEL)
+
+#define GRAPHICS_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelPrivate))
+
+struct CommonGraphicsChannelPrivate
+{
+ QXLInstance *qxl;
+ uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE];
+ uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
+ int during_target_migrate; /* TRUE when the client that is associated with the channel
+ is during migration. Turned off when the vm is started.
+ The flag is used to avoid sending messages that are artifacts
+ of the transition from stopped vm to loaded vm (e.g., recreation
+ of the primary surface) */
+};
+
+enum {
+ PROP0,
+ PROP_QXL
+};
+
+static void
+common_graphics_channel_get_property(GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_QXL:
+ g_value_set_pointer(value, self->priv->qxl);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+common_graphics_channel_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_QXL:
+ self->priv->qxl = g_value_get_pointer(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static int common_channel_config_socket(RedChannelClient *rcc)
+{
+ RedClient *client = red_channel_client_get_client(rcc);
+ MainChannelClient *mcc = red_client_get_main(client);
+ RedsStream *stream = red_channel_client_get_stream(rcc);
+ CommonGraphicsChannelClient *ccc = COMMON_GRAPHICS_CHANNEL_CLIENT(rcc);
+ int flags;
+ int delay_val;
+ gboolean low_bw;
+
+ if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
+ spice_warning("accept failed, %s", strerror(errno));
+ return FALSE;
+ }
+
+ if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+ spice_warning("accept failed, %s", strerror(errno));
+ return FALSE;
+ }
+
+ // TODO - this should be dynamic, not one time at channel creation
+ low_bw = main_channel_client_is_low_bandwidth(mcc);
+ common_graphics_channel_client_set_low_bandwidth(ccc, low_bw);
+ delay_val = low_bw ? 0 : 1;
+ /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending
+ * on the delayed ack timeout on the other side.
+ * Instead of using Nagle's, we need to implement message buffering on
+ * the application level.
+ * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/
+ */
+ if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
+ sizeof(delay_val)) == -1) {
+ if (errno != ENOTSUP) {
+ spice_warning("setsockopt failed, %s", strerror(errno));
+ }
+ }
+ return TRUE;
+}
+
+static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
+{
+ RedChannel *channel = red_channel_client_get_channel(rcc);
+ CommonGraphicsChannel *common = COMMON_GRAPHICS_CHANNEL(channel);
+
+ /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */
+ if (type == SPICE_MSGC_MIGRATE_DATA) {
+ return spice_malloc(size);
+ }
+
+ if (size > CHANNEL_RECEIVE_BUF_SIZE) {
+ spice_critical("unexpected message size %u (max is %d)", size, CHANNEL_RECEIVE_BUF_SIZE);
+ return NULL;
+ }
+ return common->priv->recv_buf;
+}
+
+static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size,
+ uint8_t* msg)
+{
+ if (type == SPICE_MSGC_MIGRATE_DATA) {
+ free(msg);
+ }
+}
+
+static void
+common_graphics_channel_class_init(CommonGraphicsChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(CommonGraphicsChannelPrivate));
+
+ object_class->get_property = common_graphics_channel_get_property;
+ object_class->set_property = common_graphics_channel_set_property;
+
+ channel_class->config_socket = common_channel_config_socket;
+ channel_class->alloc_recv_buf = common_alloc_recv_buf;
+ channel_class->release_recv_buf = common_release_recv_buf;
+
+ g_object_class_install_property(object_class,
+ PROP_QXL,
+ g_param_spec_pointer("qxl",
+ "qxl",
+ "QXLInstance for this channel",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+common_graphics_channel_init(CommonGraphicsChannel *self)
+{
+ self->priv = GRAPHICS_CHANNEL_PRIVATE(self);
+}
+
+void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value)
+{
+ self->priv->during_target_migrate = value;
+}
+
+gboolean common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel *self)
+{
+ return self->priv->during_target_migrate;
+}
+
+QXLInstance* common_graphics_channel_get_qxl(CommonGraphicsChannel *self)
+{
+ return self->priv->qxl;
+}
diff --git a/server/common-graphics-channel.h b/server/common-graphics-channel.h
new file mode 100644
index 0000000..949470e
--- /dev/null
+++ b/server/common-graphics-channel.h
@@ -0,0 +1,98 @@
+/* common-graphics-channel.h */
+/*
+ Copyright (C) 2009 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 __COMMON_GRAPHICS_CHANNEL_H__
+#define __COMMON_GRAPHICS_CHANNEL_H__
+
+#include <glib-object.h>
+
+#include "red-channel.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_COMMON_GRAPHICS_CHANNEL common_graphics_channel_get_type()
+
+#define COMMON_GRAPHICS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannel))
+#define COMMON_GRAPHICS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelClass))
+#define COMMON_IS_GRAPHICS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COMMON_GRAPHICS_CHANNEL))
+#define COMMON_IS_GRAPHICS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COMMON_GRAPHICS_CHANNEL))
+#define COMMON_GRAPHICS_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelClass))
+
+typedef struct CommonGraphicsChannel CommonGraphicsChannel;
+typedef struct CommonGraphicsChannelClass CommonGraphicsChannelClass;
+typedef struct CommonGraphicsChannelPrivate CommonGraphicsChannelPrivate;
+
+struct CommonGraphicsChannel
+{
+ RedChannel parent;
+
+ CommonGraphicsChannelPrivate *priv;
+};
+
+struct CommonGraphicsChannelClass
+{
+ RedChannelClass parent_class;
+};
+
+GType common_graphics_channel_get_type(void) G_GNUC_CONST;
+
+void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value);
+gboolean common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel *self);
+QXLInstance* common_graphics_channel_get_qxl(CommonGraphicsChannel *self);
+
+enum {
+ RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
+ RED_PIPE_ITEM_TYPE_INVAL_ONE,
+
+ RED_PIPE_ITEM_TYPE_COMMON_LAST
+};
+
+typedef struct RedVerbItem {
+ RedPipeItem base;
+ uint16_t verb;
+} RedVerbItem;
+
+static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem *item)
+{
+ red_channel_client_init_send_data(rcc, item->verb, NULL);
+}
+
+static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
+{
+ RedVerbItem *item = spice_new(RedVerbItem, 1);
+
+ red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB);
+ item->verb = verb;
+ red_channel_client_pipe_add(rcc, &item->base);
+}
+
+static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer data)
+{
+ uint16_t verb = GPOINTER_TO_UINT(data);
+ red_pipe_add_verb(rcc, verb);
+}
+
+static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
+{
+ red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb));
+}
+
+
+G_END_DECLS
+
+#endif /* __COMMON_GRAPHICS_CHANNEL_H__ */
diff --git a/server/cursor-channel.c b/server/cursor-channel.c
index 032a1e1..26c72d8 100644
--- a/server/cursor-channel.c
+++ b/server/cursor-channel.c
@@ -24,6 +24,7 @@
#include "common-graphics-channel-client-private.h"
#include "cursor-channel.h"
#include "reds.h"
+#include "red-qxl.h"
enum {
RED_PIPE_ITEM_TYPE_CURSOR = RED_PIPE_ITEM_TYPE_COMMON_LAST,
@@ -45,9 +46,12 @@ typedef struct RedCursorPipeItem {
int refs;
} RedCursorPipeItem;
-struct CursorChannel {
- CommonGraphicsChannel common; // Must be the first thing
+G_DEFINE_TYPE(CursorChannel, cursor_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
+#define CURSOR_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_CURSOR_CHANNEL, CursorChannelPrivate))
+
+struct CursorChannelPrivate
+{
CursorItem *item;
int cursor_visible;
SpicePoint16 cursor_position;
@@ -104,10 +108,10 @@ static void cursor_item_unref(CursorItem *item)
static void cursor_set_item(CursorChannel *cursor, CursorItem *item)
{
- if (cursor->item)
- cursor_item_unref(cursor->item);
+ if (cursor->priv->item)
+ cursor_item_unref(cursor->priv->item);
- cursor->item = item ? cursor_item_ref(item) : NULL;
+ cursor->priv->item = item ? cursor_item_ref(item) : NULL;
}
static RedPipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, int num)
@@ -237,12 +241,12 @@ static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *bas
cursor_channel = (CursorChannel*)red_channel_client_get_channel(rcc);
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL);
- msg.visible = cursor_channel->cursor_visible;
- msg.position = cursor_channel->cursor_position;
- msg.trail_length = cursor_channel->cursor_trail_length;
- msg.trail_frequency = cursor_channel->cursor_trail_frequency;
+ msg.visible = cursor_channel->priv->cursor_visible;
+ msg.position = cursor_channel->priv->cursor_position;
+ msg.trail_length = cursor_channel->priv->cursor_trail_length;
+ msg.trail_frequency = cursor_channel->priv->cursor_trail_frequency;
- cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info);
+ cursor_fill(ccc, &msg.cursor, cursor_channel->priv->item, &info);
spice_marshall_msg_cursor_init(base_marshaller, &msg);
add_buf_from_info(base_marshaller, &info);
}
@@ -251,8 +255,7 @@ static void cursor_marshall(RedChannelClient *rcc,
SpiceMarshaller *m,
RedCursorPipeItem *cursor_pipe_item)
{
- CursorChannel *cursor_channel = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
- CursorChannel, common.base);
+ CursorChannel *cursor_channel = CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
CursorChannelClient *ccc = CURSOR_CHANNEL_CLIENT(rcc);
CursorItem *item = cursor_pipe_item->cursor_item;
RedPipeItem *pipe_item = &cursor_pipe_item->base;
@@ -277,7 +280,7 @@ static void cursor_marshall(RedChannelClient *rcc,
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item);
cursor_set.position = cmd->u.set.position;
- cursor_set.visible = cursor_channel->cursor_visible;
+ cursor_set.visible = cursor_channel->priv->cursor_visible;
cursor_fill(ccc, &cursor_set.cursor, item, &info);
spice_marshall_msg_cursor_set(m, &cursor_set);
@@ -378,27 +381,17 @@ static void cursor_channel_release_item(RedChannelClient *rcc, RedPipeItem *item
}
}
-CursorChannel* cursor_channel_new(RedWorker *worker)
+CursorChannel* cursor_channel_new(SpiceServer *reds, QXLInstance *qxl,
+ const SpiceCoreInterfaceInternal *core)
{
- CursorChannel *cursor_channel;
- CommonGraphicsChannel *channel = NULL;
- ChannelCbs cbs = {
- .on_disconnect = cursor_channel_client_on_disconnect,
- .send_item = cursor_channel_send_item,
- .hold_item = cursor_channel_hold_pipe_item,
- .release_item = cursor_channel_release_item
- };
-
spice_info("create cursor channel");
- channel = red_worker_new_channel(worker, sizeof(CursorChannel), "cursor_channel",
- SPICE_CHANNEL_CURSOR, 0,
- &cbs, red_channel_client_handle_message);
-
- cursor_channel = (CursorChannel *)channel;
- cursor_channel->cursor_visible = TRUE;
- cursor_channel->mouse_mode = SPICE_MOUSE_MODE_SERVER;
-
- return cursor_channel;
+ return g_object_new(TYPE_CURSOR_CHANNEL,
+ "spice-server", reds,
+ "core-interface", core,
+ "channel-type", SPICE_CHANNEL_CURSOR,
+ "migration-flags", 0,
+ "qxl", qxl,
+ NULL);
}
void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
@@ -409,35 +402,36 @@ void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
spice_return_if_fail(cursor);
spice_return_if_fail(cursor_cmd);
- cursor_item = cursor_item_new(cursor->common.qxl, cursor_cmd);
+ cursor_item = cursor_item_new(common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(cursor)),
+ cursor_cmd);
switch (cursor_cmd->type) {
case QXL_CURSOR_SET:
- cursor->cursor_visible = cursor_cmd->u.set.visible;
+ cursor->priv->cursor_visible = cursor_cmd->u.set.visible;
cursor_set_item(cursor, cursor_item);
break;
case QXL_CURSOR_MOVE:
- cursor_show = !cursor->cursor_visible;
- cursor->cursor_visible = TRUE;
- cursor->cursor_position = cursor_cmd->u.position;
+ cursor_show = !cursor->priv->cursor_visible;
+ cursor->priv->cursor_visible = TRUE;
+ cursor->priv->cursor_position = cursor_cmd->u.position;
break;
case QXL_CURSOR_HIDE:
- cursor->cursor_visible = FALSE;
+ cursor->priv->cursor_visible = FALSE;
break;
case QXL_CURSOR_TRAIL:
- cursor->cursor_trail_length = cursor_cmd->u.trail.length;
- cursor->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
+ cursor->priv->cursor_trail_length = cursor_cmd->u.trail.length;
+ cursor->priv->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
break;
default:
spice_warning("invalid cursor command %u", cursor_cmd->type);
return;
}
- if (red_channel_is_connected(&cursor->common.base) &&
- (cursor->mouse_mode == SPICE_MOUSE_MODE_SERVER
+ if (red_channel_is_connected(RED_CHANNEL(cursor)) &&
+ (cursor->priv->mouse_mode == SPICE_MOUSE_MODE_SERVER
|| cursor_cmd->type != QXL_CURSOR_MOVE
|| cursor_show)) {
- red_channel_pipes_new_add(&cursor->common.base,
+ red_channel_pipes_new_add(RED_CHANNEL(cursor),
new_cursor_pipe_item, cursor_item);
}
@@ -446,34 +440,34 @@ void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
void cursor_channel_reset(CursorChannel *cursor)
{
- RedChannel *channel = &cursor->common.base;
+ RedChannel *channel = RED_CHANNEL(cursor);
spice_return_if_fail(cursor);
cursor_set_item(cursor, NULL);
- cursor->cursor_visible = TRUE;
- cursor->cursor_position.x = cursor->cursor_position.y = 0;
- cursor->cursor_trail_length = cursor->cursor_trail_frequency = 0;
+ cursor->priv->cursor_visible = TRUE;
+ cursor->priv->cursor_position.x = cursor->priv->cursor_position.y = 0;
+ cursor->priv->cursor_trail_length = cursor->priv->cursor_trail_frequency = 0;
if (red_channel_is_connected(channel)) {
red_channel_pipes_add_type(channel, RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
- if (!cursor->common.during_target_migrate) {
+ if (!common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
red_pipes_add_verb(channel, SPICE_MSG_CURSOR_RESET);
}
- if (!red_channel_wait_all_sent(&cursor->common.base,
+ if (!red_channel_wait_all_sent(RED_CHANNEL(cursor),
COMMON_CLIENT_TIMEOUT)) {
- red_channel_apply_clients(channel,
+ red_channel_apply_clients(RED_CHANNEL(cursor),
red_channel_client_disconnect_if_pending_send);
}
}
}
-void cursor_channel_init(CursorChannel *cursor, CursorChannelClient *client)
+void cursor_channel_do_init(CursorChannel *cursor, CursorChannelClient *client)
{
spice_return_if_fail(cursor);
- if (!red_channel_is_connected(&cursor->common.base)
- || COMMON_GRAPHICS_CHANNEL(cursor)->during_target_migrate) {
+ if (!red_channel_is_connected(RED_CHANNEL(cursor))
+ || common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
spice_debug("during_target_migrate: skip init");
return;
}
@@ -489,5 +483,29 @@ void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode)
{
spice_return_if_fail(cursor);
- cursor->mouse_mode = mode;
+ cursor->priv->mouse_mode = mode;
+}
+
+static void
+cursor_channel_class_init(CursorChannelClass *klass)
+{
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(CursorChannelPrivate));
+
+ channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_CURSOR, NULL);
+ channel_class->handle_parsed = red_channel_client_handle_message;
+
+ channel_class->on_disconnect = cursor_channel_client_on_disconnect;
+ channel_class->send_item = cursor_channel_send_item;
+ channel_class->hold_item = cursor_channel_hold_pipe_item;
+ channel_class->release_item = cursor_channel_release_item;
+}
+
+static void
+cursor_channel_init(CursorChannel *self)
+{
+ self->priv = CURSOR_CHANNEL_PRIVATE(self);
+ self->priv->cursor_visible = TRUE;
+ self->priv->mouse_mode = SPICE_MOUSE_MODE_SERVER;
}
diff --git a/server/cursor-channel.h b/server/cursor-channel.h
index 2b09b21..81ad96f 100644
--- a/server/cursor-channel.h
+++ b/server/cursor-channel.h
@@ -19,16 +19,47 @@
# define CURSOR_CHANNEL_H_
#include "cursor-channel-client.h"
-#include "red-worker.h"
+#include "common-graphics-channel.h"
+#include "red-parse-qxl.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_CURSOR_CHANNEL cursor_channel_get_type()
+
+#define CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_CURSOR_CHANNEL, CursorChannel))
+#define CURSOR_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_CURSOR_CHANNEL, CursorChannelClass))
+#define IS_CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_CURSOR_CHANNEL))
+#define IS_CURSOR_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_CURSOR_CHANNEL))
+#define CURSOR_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_CURSOR_CHANNEL, CursorChannelClass))
typedef struct CursorChannel CursorChannel;
+typedef struct CursorChannelClass CursorChannelClass;
+typedef struct CursorChannelPrivate CursorChannelPrivate;
+
+struct CursorChannel
+{
+ CommonGraphicsChannel parent;
+
+ CursorChannelPrivate *priv;
+};
+
+struct CursorChannelClass
+{
+ CommonGraphicsChannelClass parent_class;
+};
+
+GType cursor_channel_get_type(void) G_GNUC_CONST;
+
typedef struct CursorItem CursorItem;
-CursorChannel* cursor_channel_new (RedWorker *worker);
+CursorChannel* cursor_channel_new (SpiceServer *reds, QXLInstance *qxl,
+ const SpiceCoreInterfaceInternal *core);
void cursor_channel_disconnect (CursorChannel *cursor_channel);
void cursor_channel_reset (CursorChannel *cursor);
-void cursor_channel_init (CursorChannel *cursor, CursorChannelClient* client);
+void cursor_channel_do_init (CursorChannel *cursor, CursorChannelClient* client);
void cursor_channel_process_cmd (CursorChannel *cursor, RedCursorCmd *cursor_cmd);
void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode);
+G_END_DECLS
+
#endif /* CURSOR_CHANNEL_H_ */
diff --git a/server/dcc-send.c b/server/dcc-send.c
index 2525753..9b9af93 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -21,6 +21,7 @@
#include "dcc-private.h"
#include "display-channel.h"
+#include "display-channel-private.h"
#include "common/marshaller.h"
#include "common/generated_server_marshallers.h"
@@ -94,9 +95,9 @@ static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
QRegion lossy_region;
DisplayChannel *display = DCC_TO_DC(dcc);
- spice_return_val_if_fail(validate_surface(display, surface_id), FALSE);
+ spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), FALSE);
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
surface_lossy_region = &dcc->priv->surface_client_lossy_region[surface_id];
if (!area) {
@@ -197,8 +198,7 @@ static void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
int is_lossy)
{
DisplayChannel *display_channel =
- SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), DisplayChannel,
- common.base);
+ DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
@@ -210,13 +210,13 @@ static void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] =
image->descriptor.id;
- stat_inc_counter(reds, display_channel->add_to_cache_counter, 1);
+ stat_inc_counter(reds, display_channel->priv->add_to_cache_counter, 1);
}
}
}
if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
- stat_inc_counter(reds, display_channel->non_cache_counter, 1);
+ stat_inc_counter(reds, display_channel->priv->non_cache_counter, 1);
}
}
@@ -367,7 +367,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] =
image.descriptor.id;
if (can_lossy || !lossy_cache_item) {
- if (!display->enable_jpeg || lossy_cache_item) {
+ if (!display->priv->enable_jpeg || lossy_cache_item) {
image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
} else {
// making sure, in multiple monitor scenario, that lossy items that
@@ -379,7 +379,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
&bitmap_palette_out, &lzplt_palette_out);
spice_assert(bitmap_palette_out == NULL);
spice_assert(lzplt_palette_out == NULL);
- stat_inc_counter(reds, display->cache_hits_counter, 1);
+ stat_inc_counter(reds, display->priv->cache_hits_counter, 1);
pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock);
return FILL_BITS_TYPE_CACHE;
} else {
@@ -396,13 +396,13 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
RedSurface *surface;
surface_id = simage->u.surface.surface_id;
- if (!validate_surface(display, surface_id)) {
+ if (!display_channel_validate_surface(display, surface_id)) {
spice_warning("Invalid surface in SPICE_IMAGE_TYPE_SURFACE");
pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock);
return FILL_BITS_TYPE_SURFACE;
}
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
image.descriptor.flags = 0;
image.descriptor.width = surface->context.width;
@@ -1692,7 +1692,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
height = stream->height;
}
- StreamAgent *agent = &dcc->priv->stream_agents[get_stream_id(display, stream)];
+ StreamAgent *agent = &dcc->priv->stream_agents[display_channel_get_stream_id(display, stream)];
uint64_t time_now = spice_get_monotonic_time_ns();
size_t outbuf_size;
@@ -1739,7 +1739,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
- stream_data.base.id = get_stream_id(display, stream);
+ stream_data.base.id = display_channel_get_stream_id(display, stream);
stream_data.base.multi_media_time = frame_mm_time;
stream_data.data_size = n;
@@ -1749,7 +1749,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL);
- stream_data.base.id = get_stream_id(display, stream);
+ stream_data.base.id = display_channel_get_stream_id(display, stream);
stream_data.base.multi_media_time = frame_mm_time;
stream_data.data_size = n;
stream_data.width = width;
@@ -1822,8 +1822,7 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
SpiceMigrateDataDisplay display_data = {0,};
- display_channel = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
- DisplayChannel, common.base);
+ display_channel = DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC);
@@ -1853,7 +1852,7 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
spice_marshaller_add(base_marshaller,
(uint8_t *)&display_data, sizeof(display_data) - sizeof(uint32_t));
display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller,
- display_channel->enable_jpeg);
+ display_channel->priv->enable_jpeg);
}
static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc,
@@ -2132,8 +2131,7 @@ static void marshall_qxl_drawable(RedChannelClient *rcc,
Drawable *item = dpi->drawable;
DisplayChannel *display =
- SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), DisplayChannel,
- common.base);
+ DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
spice_return_if_fail(display);
/* allow sized frames to be streamed, even if they where replaced by another frame, since
@@ -2141,7 +2139,7 @@ static void marshall_qxl_drawable(RedChannelClient *rcc,
if ((item->stream || item->sized_stream) && red_marshall_stream_data(rcc, m, item)) {
return;
}
- if (display->enable_jpeg)
+ if (display->priv->enable_jpeg)
marshall_lossy_qxl_drawable(rcc, m, dpi);
else
marshall_lossless_qxl_drawable(rcc, m, dpi);
@@ -2160,7 +2158,7 @@ static void marshall_stream_start(RedChannelClient *rcc,
SpiceClipRects clip_rects;
stream_create.surface_id = 0;
- stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream);
+ stream_create.id = display_channel_get_stream_id(DCC_TO_DC(dcc), stream);
stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
@@ -2196,7 +2194,7 @@ static void marshall_stream_clip(RedChannelClient *rcc,
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
SpiceMsgDisplayStreamClip stream_clip;
- stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
+ stream_clip.id = display_channel_get_stream_id(DCC_TO_DC(dcc), agent->stream);
stream_clip.clip.type = item->clip_type;
stream_clip.clip.rects = item->rects;
@@ -2210,7 +2208,7 @@ static void marshall_stream_end(RedChannelClient *rcc,
SpiceMsgDisplayStreamDestroy destroy;
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
- destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
+ destroy.id = display_channel_get_stream_id(DCC_TO_DC(dcc), agent->stream);
stream_agent_stop(agent);
spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
}
@@ -2319,7 +2317,7 @@ static void marshall_gl_scanout(RedChannelClient *rcc,
{
DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
DisplayChannel *display_channel = DCC_TO_DC(dcc);
- QXLInstance* qxl = display_channel->common.qxl;
+ QXLInstance* qxl = common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(display_channel));
SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl);
if (scanout != NULL) {
diff --git a/server/dcc.c b/server/dcc.c
index 6b5517e..d3c77f4 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -22,6 +22,7 @@
#include "dcc-private.h"
#include "dcc.h"
#include "display-channel.h"
+#include "display-channel-private.h"
#include "red-channel-client-private.h"
#include "spice-server-enums.h"
@@ -305,12 +306,12 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
/* don't send redundant create surface commands to client */
- if (!dcc || display->common.during_target_migrate ||
+ if (!dcc || common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(display)) ||
dcc->priv->surface_client_created[surface_id]) {
return;
}
channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(dcc));
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
create = red_surface_create_item_new(channel,
surface_id, surface->context.width,
surface->context.height,
@@ -327,7 +328,7 @@ RedImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc,
int can_lossy)
{
DisplayChannel *display = DCC_TO_DC(dcc);
- RedSurface *surface = &display->surfaces[surface_id];
+ RedSurface *surface = &display->priv->surfaces[surface_id];
SpiceCanvas *canvas = surface->context.canvas;
RedImageItem *item;
int stride;
@@ -393,7 +394,7 @@ void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
}
display = DCC_TO_DC(dcc);
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
if (!surface->context.canvas) {
return;
}
@@ -495,7 +496,7 @@ static void dcc_init_stream_agents(DisplayChannelClient *dcc)
dcc->priv->stream_agents = g_new0(StreamAgent, NUM_STREAMS);
for (i = 0; i < NUM_STREAMS; i++) {
StreamAgent *agent = &dcc->priv->stream_agents[i];
- agent->stream = &display->streams_buf[i];
+ agent->stream = &display->priv->streams_buf[i];
region_init(&agent->vis_region);
region_init(&agent->clip);
red_pipe_item_init(&agent->create_item, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
@@ -552,7 +553,7 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
static void dcc_create_all_streams(DisplayChannelClient *dcc)
{
- Ring *ring = &DCC_TO_DC(dcc)->streams;
+ Ring *ring = &DCC_TO_DC(dcc)->priv->streams;
RingItem *item = ring;
while ((item = ring_next(ring, item))) {
@@ -606,7 +607,7 @@ void dcc_start(DisplayChannelClient *dcc)
return;
red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
- if (display->surfaces[0].context.canvas) {
+ if (display->priv->surfaces[0].context.canvas) {
display_channel_current_flush(display, 0);
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
dcc_create_surface(dcc, 0);
@@ -693,7 +694,7 @@ static RedMonitorsConfigItem *red_monitors_config_item_new(RedChannel* channel,
void dcc_push_monitors_config(DisplayChannelClient *dcc)
{
DisplayChannel *dc = DCC_TO_DC(dcc);
- MonitorsConfig *monitors_config = dc->monitors_config;
+ MonitorsConfig *monitors_config = dc->priv->monitors_config;
RedMonitorsConfigItem *mci;
RedChannel *channel;
@@ -709,7 +710,7 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(dcc));
mci = red_monitors_config_item_new(channel,
- monitors_config_ref(dc->monitors_config));
+ monitors_config_ref(dc->priv->monitors_config));
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &mci->pipe_item);
red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
}
@@ -777,7 +778,7 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
display = DCC_TO_DC(dcc);
channel = RED_CHANNEL(display);
- if (COMMON_GRAPHICS_CHANNEL(display)->during_target_migrate ||
+ if (common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(display)) ||
!dcc->priv->surface_client_created[surface_id]) {
return;
}
@@ -859,7 +860,7 @@ static int dcc_compress_image_glz(DisplayChannelClient *dcc,
{
DisplayChannel *display_channel = DCC_TO_DC(dcc);
stat_start_time_t start_time;
- stat_start_time_init(&start_time, &display_channel->zlib_glz_stat);
+ stat_start_time_init(&start_time, &display_channel->priv->zlib_glz_stat);
spice_assert(bitmap_fmt_is_rgb(src->format));
GlzData *glz_data = &dcc->priv->glz_data;
ZlibData *zlib_data;
@@ -890,12 +891,12 @@ static int dcc_compress_image_glz(DisplayChannelClient *dcc,
glz_drawable_instance,
&glz_drawable_instance->context);
- stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
+ stat_compress_add(&display_channel->priv->glz_stat, start_time, src->stride * src->y, glz_size);
- if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
+ if (!display_channel->priv->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
goto glz;
}
- stat_start_time_init(&start_time, &display_channel->zlib_glz_stat);
+ stat_start_time_init(&start_time, &display_channel->priv->zlib_glz_stat);
zlib_data = &dcc->priv->zlib_data;
encoder_data_init(&zlib_data->data, dcc);
@@ -922,7 +923,7 @@ static int dcc_compress_image_glz(DisplayChannelClient *dcc,
o_comp_data->comp_buf = zlib_data->data.bufs_head;
o_comp_data->comp_buf_size = zlib_size;
- stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
+ stat_compress_add(&display_channel->priv->zlib_glz_stat, start_time, glz_size, zlib_size);
return TRUE;
glz:
dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
@@ -944,7 +945,7 @@ static int dcc_compress_image_lz(DisplayChannelClient *dcc,
int size; // size of the compressed data
stat_start_time_t start_time;
- stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->lz_stat);
+ stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->lz_stat);
#ifdef COMPRESS_DEBUG
spice_info("LZ LOCAL compress");
@@ -995,7 +996,7 @@ static int dcc_compress_image_lz(DisplayChannelClient *dcc,
o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
}
- stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->priv->lz_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -1016,7 +1017,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest,
int stride;
uint8_t *lz_out_start_byte;
stat_start_time_t start_time;
- stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->jpeg_alpha_stat);
+ stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->jpeg_alpha_stat);
#ifdef COMPRESS_DEBUG
spice_info("JPEG compress");
@@ -1080,7 +1081,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest,
o_comp_data->comp_buf_size = jpeg_size;
o_comp_data->is_lossy = TRUE;
- stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->priv->jpeg_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -1122,7 +1123,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest,
o_comp_data->comp_buf = jpeg_data->data.bufs_head;
o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size;
o_comp_data->is_lossy = TRUE;
- stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->priv->jpeg_alpha_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -1135,7 +1136,7 @@ static int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage *dest,
Lz4EncoderContext *lz4 = dcc->priv->lz4;
int lz4_size = 0;
stat_start_time_t start_time;
- stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->lz4_stat);
+ stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->lz4_stat);
#ifdef COMPRESS_DEBUG
spice_info("LZ4 compress");
@@ -1172,7 +1173,7 @@ static int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage *dest,
o_comp_data->comp_buf = lz4_data->data.bufs_head;
o_comp_data->comp_buf_size = lz4_size;
- stat_compress_add(&DCC_TO_DC(dcc)->lz4_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->priv->lz4_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -1186,7 +1187,7 @@ static int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest,
volatile QuicImageType type;
int size, stride;
stat_start_time_t start_time;
- stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->quic_stat);
+ stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->quic_stat);
#ifdef COMPRESS_DEBUG
spice_info("QUIC compress");
@@ -1246,7 +1247,7 @@ static int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest,
o_comp_data->comp_buf = quic_data->data.bufs_head;
o_comp_data->comp_buf_size = size << 2;
- stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->priv->quic_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -1345,14 +1346,14 @@ int dcc_compress_image(DisplayChannelClient *dcc,
stat_start_time_t start_time;
int success = FALSE;
- stat_start_time_init(&start_time, &display_channel->off_stat);
+ stat_start_time_init(&start_time, &display_channel->priv->off_stat);
image_compression = get_compression_for_bitmap(src, dcc->priv->image_compression, drawable);
switch (image_compression) {
case SPICE_IMAGE_COMPRESSION_OFF:
break;
case SPICE_IMAGE_COMPRESSION_QUIC:
- if (can_lossy && display_channel->enable_jpeg &&
+ if (can_lossy && display_channel->priv->enable_jpeg &&
(src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src))) {
success = dcc_compress_image_jpeg(dcc, dest, src, o_comp_data);
break;
@@ -1392,7 +1393,7 @@ lz_compress:
if (!success) {
uint64_t image_size = src->stride * src->y;
- stat_compress_add(&display_channel->off_stat, start_time, image_size, image_size);
+ stat_compress_add(&display_channel->priv->off_stat, start_time, image_size, image_size);
}
return success;
@@ -1739,15 +1740,15 @@ int dcc_handle_migrate_data(DisplayChannelClient *dcc, uint32_t size, void *mess
if (migrate_data->low_bandwidth_setting) {
red_channel_client_ack_set_client_window(RED_CHANNEL_CLIENT(dcc), WIDE_CLIENT_ACK_WINDOW);
if (dcc->priv->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
- display->enable_jpeg = TRUE;
+ display->priv->enable_jpeg = TRUE;
}
if (dcc->priv->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
- display->enable_zlib_glz_wrap = TRUE;
+ display->priv->enable_zlib_glz_wrap = TRUE;
}
}
surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr;
- surfaces_restored = display->enable_jpeg ?
+ surfaces_restored = display->priv->enable_jpeg ?
restore_surfaces_lossy(dcc, (MigrateDisplaySurfacesAtClientLossy *)surfaces) :
restore_surfaces_lossless(dcc, (MigrateDisplaySurfacesAtClientLossless*)surfaces);
diff --git a/server/dcc.h b/server/dcc.h
index 9567afd..ab51047 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -21,7 +21,7 @@
#include <glib-object.h>
#include "image-cache.h"
#include "pixmap-cache.h"
-#include "red-worker.h"
+#include "common-graphics-channel-client.h"
#include "display-limits.h"
G_BEGIN_DECLS
@@ -69,7 +69,6 @@ GType display_channel_client_get_type(void) G_GNUC_CONST;
#define MAX_PIPE_SIZE 50
-/* FIXME: remove */
typedef struct DisplayChannel DisplayChannel;
typedef struct Stream Stream;
typedef struct StreamAgent StreamAgent;
@@ -87,7 +86,6 @@ typedef struct FreeList {
WaitForChannels wait;
} FreeList;
-#define DCC_TO_WORKER(dcc) ((RedWorker*)((CommonGraphicsChannel*)(red_channel_client_get_channel((RedChannelClient*)dcc)))->worker)
#define DCC_TO_DC(dcc) ((DisplayChannel*)red_channel_client_get_channel((RedChannelClient*)dcc))
typedef struct RedSurfaceCreateItem {
diff --git a/server/display-channel-private.h b/server/display-channel-private.h
new file mode 100644
index 0000000..039a93d
--- /dev/null
+++ b/server/display-channel-private.h
@@ -0,0 +1,81 @@
+/*
+ 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 DISPLAY_CHANNEL_PRIVATE_H_
+#define DISPLAY_CHANNEL_PRIVATE_H_
+
+struct DisplayChannelPrivate
+{
+ DisplayChannel *pub;
+
+ uint32_t bits_unique;
+
+ MonitorsConfig *monitors_config;
+
+ uint32_t renderer;
+ int enable_jpeg;
+ int enable_zlib_glz_wrap;
+
+ Ring current_list; // of TreeItem
+ uint32_t current_size;
+
+ uint32_t drawable_count;
+ _Drawable *drawables;
+ _Drawable *free_drawables;
+
+ int stream_video;
+ uint32_t stream_count;
+ Stream *streams_buf;
+ Stream *free_streams;
+ Ring streams;
+ ItemTrace *items_trace;
+ uint32_t next_item_trace;
+ uint64_t streams_size_total;
+
+ RedSurface *surfaces;
+ uint32_t n_surfaces;
+ SpiceImageSurfaces image_surfaces;
+
+ ImageCache *image_cache;
+ RedCompressBuf *free_compress_bufs;
+
+ int gl_draw_async_count;
+
+/* TODO: some day unify this, make it more runtime.. */
+ stat_info_t add_stat;
+ stat_info_t exclude_stat;
+ stat_info_t __exclude_stat;
+#ifdef RED_WORKER_STAT
+ uint32_t add_count;
+ uint32_t add_with_shadow_count;
+#endif
+#ifdef RED_STATISTICS
+ uint64_t *cache_hits_counter;
+ uint64_t *add_to_cache_counter;
+ uint64_t *non_cache_counter;
+#endif
+ stat_info_t off_stat;
+ stat_info_t lz_stat;
+ stat_info_t glz_stat;
+ stat_info_t quic_stat;
+ stat_info_t jpeg_stat;
+ stat_info_t zlib_glz_stat;
+ stat_info_t jpeg_alpha_stat;
+ stat_info_t lz4_stat;
+};
+
+#endif /* DISPLAY_CHANNEL_PRIVATE_H_ */
diff --git a/server/display-channel.c b/server/display-channel.c
index 352058a..91b4255 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -19,6 +19,138 @@
#endif
#include "display-channel.h"
+#include "display-channel-private.h"
+
+G_DEFINE_TYPE(DisplayChannel, display_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
+
+#define DISPLAY_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DISPLAY_CHANNEL, DisplayChannelPrivate))
+
+enum {
+ PROP0,
+ PROP_N_SURFACES
+};
+
+static void
+display_channel_get_property(GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ DisplayChannel *self = DISPLAY_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_N_SURFACES:
+ g_value_set_uint(value, self->priv->n_surfaces);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+display_channel_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ DisplayChannel *self = DISPLAY_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_N_SURFACES:
+ self->priv->n_surfaces = g_value_get_uint(value);
+ if (self->priv->surfaces == NULL)
+ self->priv->surfaces = g_new0(RedSurface, self->priv->n_surfaces);
+ else
+ self->priv->surfaces = g_renew(RedSurface, self->priv->surfaces, self->priv->n_surfaces);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+display_channel_finalize(GObject *object)
+{
+ DisplayChannel *self = DISPLAY_CHANNEL(object);
+
+ G_OBJECT_CLASS(display_channel_parent_class)->finalize(object);
+
+ g_free(self->priv->drawables);
+ g_free(self->priv->surfaces);
+ g_free(self->priv->streams_buf);
+ g_free(self->priv->items_trace);
+ g_free(self->priv->image_cache);
+}
+
+static void
+display_channel_constructed(GObject *object)
+{
+ DisplayChannel *self = DISPLAY_CHANNEL(object);
+
+ G_OBJECT_CLASS(display_channel_parent_class)->constructed(object);
+
+ self->priv->renderer = RED_RENDERER_INVALID;
+
+ stat_init(&self->priv->add_stat, "add", CLOCK_THREAD_CPUTIME_ID);
+ stat_init(&self->priv->exclude_stat, "exclude", CLOCK_THREAD_CPUTIME_ID);
+ stat_init(&self->priv->__exclude_stat, "__exclude", CLOCK_THREAD_CPUTIME_ID);
+#ifdef RED_STATISTICS
+ QXLInstance *qxl = common_graphics_channel_get_qxl(&self->parent);
+ RedsState *reds = red_qxl_get_server(qxl->st);
+ RedChannel *channel = RED_CHANNEL(self);
+ self->priv->cache_hits_counter =
+ stat_add_counter(reds, red_channel_get_stat_node(channel),
+ "cache_hits", TRUE);
+ self->priv->add_to_cache_counter =
+ stat_add_counter(reds, red_channel_get_stat_node(channel),
+ "add_to_cache", TRUE);
+ self->priv->non_cache_counter =
+ stat_add_counter(reds, red_channel_get_stat_node(channel),
+ "non_cache", TRUE);
+#endif
+ image_cache_init(self->priv->image_cache);
+ self->priv->stream_video = SPICE_STREAM_VIDEO_OFF;
+ display_channel_init_streams(self);
+}
+
+static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
+{
+ DisplayChannelPrivate *p = SPICE_CONTAINEROF(surfaces, DisplayChannelPrivate, image_surfaces);
+ DisplayChannel *display = p->pub;
+
+ spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), NULL);
+
+ return p->surfaces[surface_id].context.canvas;
+}
+
+static void drawables_init(DisplayChannel *display);
+static void
+display_channel_init(DisplayChannel *self)
+{
+ static SpiceImageSurfacesOps image_surfaces_ops = {
+ image_surfaces_get,
+ };
+
+ self->priv = DISPLAY_CHANNEL_PRIVATE(self);
+ self->priv->pub = self;
+
+ stat_compress_init(&self->priv->lz_stat, "lz", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->glz_stat, "glz", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->quic_stat, "quic", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->jpeg_stat, "jpeg", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->zlib_glz_stat, "zlib", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->jpeg_alpha_stat, "jpeg_alpha", CLOCK_THREAD_CPUTIME_ID);
+ stat_compress_init(&self->priv->lz4_stat, "lz4", CLOCK_THREAD_CPUTIME_ID);
+
+ ring_init(&self->priv->current_list);
+ drawables_init(self);
+ self->priv->image_surfaces.ops = &image_surfaces_ops;
+ self->priv->streams_buf = g_new0(Stream, NUM_STREAMS);
+ self->priv->items_trace = g_new0(ItemTrace, NUM_TRACE_ITEMS);
+ self->priv->image_cache = g_new0(ImageCache, 1);
+}
static void drawable_draw(DisplayChannel *display, Drawable *drawable);
@@ -26,7 +158,7 @@ uint32_t display_channel_generate_uid(DisplayChannel *display)
{
spice_return_val_if_fail(display != NULL, 0);
- return ++display->bits_unique;
+ return ++display->priv->bits_unique;
}
#define stat_start(stat, var) \
@@ -36,107 +168,111 @@ void display_channel_compress_stats_reset(DisplayChannel *display)
{
spice_return_if_fail(display);
- stat_reset(&display->off_stat);
- stat_reset(&display->quic_stat);
- stat_reset(&display->lz_stat);
- stat_reset(&display->glz_stat);
- stat_reset(&display->jpeg_stat);
- stat_reset(&display->zlib_glz_stat);
- stat_reset(&display->jpeg_alpha_stat);
- stat_reset(&display->lz4_stat);
+ stat_reset(&display->priv->off_stat);
+ stat_reset(&display->priv->quic_stat);
+ stat_reset(&display->priv->lz_stat);
+ stat_reset(&display->priv->glz_stat);
+ stat_reset(&display->priv->jpeg_stat);
+ stat_reset(&display->priv->zlib_glz_stat);
+ stat_reset(&display->priv->jpeg_alpha_stat);
+ stat_reset(&display->priv->lz4_stat);
}
-void display_channel_compress_stats_print(const DisplayChannel *display_channel)
+void display_channel_compress_stats_print(DisplayChannel *display_channel)
{
spice_return_if_fail(display_channel);
#ifdef COMPRESS_STAT
+ DisplayChannelPrivate *priv = display_channel->priv;
uint64_t glz_enc_size;
+ uint32_t id;
+
+ glz_enc_size = priv->enable_zlib_glz_wrap ?
+ priv->zlib_glz_stat.comp_size :
+ priv->glz_stat.comp_size;
- glz_enc_size = display_channel->enable_zlib_glz_wrap ?
- display_channel->zlib_glz_stat.comp_size :
- display_channel->glz_stat.comp_size;
+ g_object_get(display_channel, "id", &id, NULL);
- spice_info("==> Compression stats for display %u", display_channel->common.base.id);
+ spice_info("==> Compression stats for display %u", id);
spice_info("Method \t count \torig_size(MB)\tenc_size(MB)\tenc_time(s)");
spice_info("OFF \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->off_stat.count,
- stat_byte_to_mega(display_channel->off_stat.orig_size),
- stat_byte_to_mega(display_channel->off_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->off_stat.total)
+ priv->off_stat.count,
+ stat_byte_to_mega(priv->off_stat.orig_size),
+ stat_byte_to_mega(priv->off_stat.comp_size),
+ stat_cpu_time_to_sec(priv->off_stat.total)
);
spice_info("QUIC \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->quic_stat.count,
- stat_byte_to_mega(display_channel->quic_stat.orig_size),
- stat_byte_to_mega(display_channel->quic_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->quic_stat.total)
+ priv->quic_stat.count,
+ stat_byte_to_mega(priv->quic_stat.orig_size),
+ stat_byte_to_mega(priv->quic_stat.comp_size),
+ stat_cpu_time_to_sec(priv->quic_stat.total)
);
spice_info("GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->glz_stat.count,
- stat_byte_to_mega(display_channel->glz_stat.orig_size),
- stat_byte_to_mega(display_channel->glz_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->glz_stat.total)
+ priv->glz_stat.count,
+ stat_byte_to_mega(priv->glz_stat.orig_size),
+ stat_byte_to_mega(priv->glz_stat.comp_size),
+ stat_cpu_time_to_sec(priv->glz_stat.total)
);
spice_info("ZLIB GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->zlib_glz_stat.count,
- stat_byte_to_mega(display_channel->zlib_glz_stat.orig_size),
- stat_byte_to_mega(display_channel->zlib_glz_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->zlib_glz_stat.total)
+ priv->zlib_glz_stat.count,
+ stat_byte_to_mega(priv->zlib_glz_stat.orig_size),
+ stat_byte_to_mega(priv->zlib_glz_stat.comp_size),
+ stat_cpu_time_to_sec(priv->zlib_glz_stat.total)
);
spice_info("LZ \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->lz_stat.count,
- stat_byte_to_mega(display_channel->lz_stat.orig_size),
- stat_byte_to_mega(display_channel->lz_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->lz_stat.total)
+ priv->lz_stat.count,
+ stat_byte_to_mega(priv->lz_stat.orig_size),
+ stat_byte_to_mega(priv->lz_stat.comp_size),
+ stat_cpu_time_to_sec(priv->lz_stat.total)
);
spice_info("JPEG \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->jpeg_stat.count,
- stat_byte_to_mega(display_channel->jpeg_stat.orig_size),
- stat_byte_to_mega(display_channel->jpeg_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->jpeg_stat.total)
+ priv->jpeg_stat.count,
+ stat_byte_to_mega(priv->jpeg_stat.orig_size),
+ stat_byte_to_mega(priv->jpeg_stat.comp_size),
+ stat_cpu_time_to_sec(priv->jpeg_stat.total)
);
spice_info("JPEG-RGBA\t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->jpeg_alpha_stat.count,
- stat_byte_to_mega(display_channel->jpeg_alpha_stat.orig_size),
- stat_byte_to_mega(display_channel->jpeg_alpha_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->jpeg_alpha_stat.total)
+ priv->jpeg_alpha_stat.count,
+ stat_byte_to_mega(priv->jpeg_alpha_stat.orig_size),
+ stat_byte_to_mega(priv->jpeg_alpha_stat.comp_size),
+ stat_cpu_time_to_sec(priv->jpeg_alpha_stat.total)
);
spice_info("LZ4 \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->lz4_stat.count,
- stat_byte_to_mega(display_channel->lz4_stat.orig_size),
- stat_byte_to_mega(display_channel->lz4_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->lz4_stat.total)
+ priv->lz4_stat.count,
+ stat_byte_to_mega(priv->lz4_stat.orig_size),
+ stat_byte_to_mega(priv->lz4_stat.comp_size),
+ stat_cpu_time_to_sec(priv->lz4_stat.total)
);
spice_info("-------------------------------------------------------------------");
spice_info("Total \t%8d\t%13.2f\t%12.2f\t%12.2f",
- display_channel->lz_stat.count + display_channel->glz_stat.count +
- display_channel->off_stat.count +
- display_channel->quic_stat.count +
- display_channel->jpeg_stat.count +
- display_channel->lz4_stat.count +
- display_channel->jpeg_alpha_stat.count,
- stat_byte_to_mega(display_channel->lz_stat.orig_size +
- display_channel->glz_stat.orig_size +
- display_channel->off_stat.orig_size +
- display_channel->quic_stat.orig_size +
- display_channel->jpeg_stat.orig_size +
- display_channel->lz4_stat.orig_size +
- display_channel->jpeg_alpha_stat.orig_size),
- stat_byte_to_mega(display_channel->lz_stat.comp_size +
+ display_channel->priv->lz_stat.count + display_channel->priv->glz_stat.count +
+ priv->off_stat.count +
+ priv->quic_stat.count +
+ priv->jpeg_stat.count +
+ priv->lz4_stat.count +
+ priv->jpeg_alpha_stat.count,
+ stat_byte_to_mega(priv->lz_stat.orig_size +
+ priv->glz_stat.orig_size +
+ priv->off_stat.orig_size +
+ priv->quic_stat.orig_size +
+ priv->jpeg_stat.orig_size +
+ priv->lz4_stat.orig_size +
+ priv->jpeg_alpha_stat.orig_size),
+ stat_byte_to_mega(priv->lz_stat.comp_size +
glz_enc_size +
- display_channel->off_stat.comp_size +
- display_channel->quic_stat.comp_size +
- display_channel->jpeg_stat.comp_size +
- display_channel->lz4_stat.comp_size +
- display_channel->jpeg_alpha_stat.comp_size),
- stat_cpu_time_to_sec(display_channel->lz_stat.total +
- display_channel->glz_stat.total +
- display_channel->zlib_glz_stat.total +
- display_channel->off_stat.total +
- display_channel->quic_stat.total +
- display_channel->jpeg_stat.total +
- display_channel->lz4_stat.total +
- display_channel->jpeg_alpha_stat.total)
+ priv->off_stat.comp_size +
+ priv->quic_stat.comp_size +
+ priv->jpeg_stat.comp_size +
+ priv->lz4_stat.comp_size +
+ priv->jpeg_alpha_stat.comp_size),
+ stat_cpu_time_to_sec(priv->lz_stat.total +
+ priv->glz_stat.total +
+ priv->zlib_glz_stat.total +
+ priv->off_stat.total +
+ priv->quic_stat.total +
+ priv->jpeg_stat.total +
+ priv->lz4_stat.total +
+ priv->jpeg_alpha_stat.total)
);
#endif
}
@@ -189,7 +325,7 @@ MonitorsConfig* monitors_config_new(QXLHead *heads, ssize_t nheads, ssize_t max)
int display_channel_get_streams_timeout(DisplayChannel *display)
{
int timeout = INT_MAX;
- Ring *ring = &display->streams;
+ Ring *ring = &display->priv->streams;
RingItem *item = ring;
red_time_t now = spice_get_monotonic_time_ns();
@@ -227,12 +363,18 @@ void display_channel_set_stream_video(DisplayChannel *display, int stream_video)
return;
}
- display->stream_video = stream_video;
+ display->priv->stream_video = stream_video;
+}
+
+int display_channel_get_stream_video(DisplayChannel *display)
+{
+ return display->priv->stream_video;
}
+
static void stop_streams(DisplayChannel *display)
{
- Ring *ring = &display->streams;
+ Ring *ring = &display->priv->streams;
RingItem *item = ring_get_head(ring);
while (item) {
@@ -245,14 +387,14 @@ static void stop_streams(DisplayChannel *display)
}
}
- display->next_item_trace = 0;
- memset(display->items_trace, 0, sizeof(display->items_trace));
+ display->priv->next_item_trace = 0;
+ memset(display->priv->items_trace, 0, NUM_TRACE_ITEMS * sizeof(*display->priv->items_trace));
}
void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
{
- RedSurface *surface = &display->surfaces[surface_id];
- QXLInstance *qxl = display->common.qxl;
+ RedSurface *surface = &display->priv->surfaces[surface_id];
+ QXLInstance *qxl = common_graphics_channel_get_qxl(&display->parent);
DisplayChannelClient *dcc;
GList *link, *next;
@@ -283,6 +425,13 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
spice_warn_if_fail(ring_is_empty(&surface->depend_on_me));
}
+/* TODO: perhaps rename to "ready" or "realized" ? */
+bool display_channel_surface_has_canvas(DisplayChannel *display,
+ uint32_t surface_id)
+{
+ return display->priv->surfaces[surface_id].context.canvas != NULL;
+}
+
static void streams_update_visible_region(DisplayChannel *display, Drawable *drawable)
{
Ring *ring;
@@ -298,7 +447,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
return;
}
- ring = &display->streams;
+ ring = &display->priv->streams;
item = ring_get_head(ring);
while (item) {
@@ -312,7 +461,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
}
FOREACH_DCC(display, link, next, dcc) {
- agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+ agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
@@ -350,7 +499,7 @@ static void pipes_add_drawable_after(DisplayChannel *display,
pipes_add_drawable(display, drawable);
return;
}
- if (num_other_linked != display->common.base.clients_num) {
+ if (num_other_linked != red_channel_get_n_clients(RED_CHANNEL(display))) {
GList *link, *next;
spice_debug("TODO: not O(n^2)");
FOREACH_DCC(display, link, next, dcc) {
@@ -374,11 +523,11 @@ static void current_add_drawable(DisplayChannel *display,
RedSurface *surface;
uint32_t surface_id = drawable->surface_id;
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
ring_add_after(&drawable->tree_item.base.siblings_link, pos);
- ring_add(&display->current_list, &drawable->list_link);
+ ring_add(&display->priv->current_list, &drawable->list_link);
ring_add(&surface->current_list, &drawable->surface_list_link);
- display->current_size++;
+ display->priv->current_size++;
drawable->refs++;
}
@@ -391,7 +540,7 @@ static void current_remove_drawable(DisplayChannel *display, Drawable *item)
ring_remove(&item->list_link);
ring_remove(&item->surface_list_link);
drawable_unref(item);
- display->current_size--;
+ display->priv->current_size--;
}
static void drawable_remove_from_pipes(Drawable *drawable)
@@ -448,7 +597,7 @@ static void current_remove(DisplayChannel *display, TreeItem *item)
static void current_remove_all(DisplayChannel *display, int surface_id)
{
- Ring *ring = &display->surfaces[surface_id].current;
+ Ring *ring = &display->priv->surfaces[surface_id].current;
RingItem *ring_item;
while ((ring_item = ring_get_head(ring))) {
@@ -506,7 +655,7 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
/* sending the drawable to clients that already received
* (or will receive) other_drawable */
- link = RED_CHANNEL(display)->clients;
+ link = red_channel_get_clients(RED_CHANNEL(display));
dpi_ring_item = ring_get_head(&other_drawable->pipes);
/* dpi contains a sublist of dcc's, ordered the same */
while (link) {
@@ -555,7 +704,7 @@ static void __exclude_region(DisplayChannel *display, Ring *ring, TreeItem *item
Ring **top_ring, Drawable *frame_candidate)
{
QRegion and_rgn;
- stat_start(&display->__exclude_stat, start_time);
+ stat_start(&display->priv->__exclude_stat, start_time);
region_clone(&and_rgn, rgn);
region_and(&and_rgn, &item->rgn);
@@ -617,14 +766,14 @@ static void __exclude_region(DisplayChannel *display, Ring *ring, TreeItem *item
}
}
region_destroy(&and_rgn);
- stat_add(&display->__exclude_stat, start_time);
+ stat_add(&display->priv->__exclude_stat, start_time);
}
static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_item,
QRegion *rgn, TreeItem **last, Drawable *frame_candidate)
{
Ring *top_ring;
- stat_start(&display->exclude_stat, start_time);
+ stat_start(&display->priv->exclude_stat, start_time);
if (!ring_item) {
return;
@@ -659,7 +808,7 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
}
if (region_is_empty(rgn)) {
- stat_add(&display->exclude_stat, start_time);
+ stat_add(&display->priv->exclude_stat, start_time);
return;
}
}
@@ -667,7 +816,7 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
while ((last && *last == (TreeItem *)ring_item) ||
!(ring_item = ring_next(ring, ring_item))) {
if (ring == top_ring) {
- stat_add(&display->exclude_stat, start_time);
+ stat_add(&display->priv->exclude_stat, start_time);
return;
}
ring_item = &container->base.siblings_link;
@@ -679,9 +828,9 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable *item)
{
- stat_start(&display->add_stat, start_time);
+ stat_start(&display->priv->add_stat, start_time);
#ifdef RED_WORKER_STAT
- ++display->add_with_shadow_count;
+ ++display->priv->add_with_shadow_count;
#endif
RedDrawable *red_drawable = item->red_drawable;
@@ -692,7 +841,7 @@ static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable
Shadow *shadow = shadow_new(&item->tree_item, &delta);
if (!shadow) {
- stat_add(&display->add_stat, start_time);
+ stat_add(&display->priv->add_stat, start_time);
return FALSE;
}
// item and his shadow must initially be placed in the same container.
@@ -716,7 +865,7 @@ static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable
stream_detach_behind(display, &item->tree_item.base.rgn, item);
}
}
- stat_add(&display->add_stat, start_time);
+ stat_add(&display->priv->add_stat, start_time);
return TRUE;
}
@@ -726,7 +875,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
RingItem *now;
QRegion exclude_rgn;
RingItem *exclude_base = NULL;
- stat_start(&display->add_stat, start_time);
+ stat_start(&display->priv->add_stat, start_time);
spice_assert(!region_is_empty(&item->base.rgn));
region_init(&exclude_rgn);
@@ -748,7 +897,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) &&
!(test_res & REGION_TEST_LEFT_EXCLUSIVE) &&
current_add_equal(display, item, sibling)) {
- stat_add(&display->add_stat, start_time);
+ stat_add(&display->priv->add_stat, start_time);
return FALSE;
}
@@ -834,7 +983,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
}
}
region_destroy(&exclude_rgn);
- stat_add(&display->add_stat, start_time);
+ stat_add(&display->priv->add_stat, start_time);
return TRUE;
}
@@ -843,7 +992,7 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
RedDrawable *red_drawable = drawable->red_drawable;
SpiceImage *image;
- if (display->stream_video == SPICE_STREAM_VIDEO_OFF) {
+ if (display->priv->stream_video == SPICE_STREAM_VIDEO_OFF) {
return FALSE;
}
@@ -863,7 +1012,7 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
return FALSE;
}
- if (display->stream_video == SPICE_STREAM_VIDEO_FILTER) {
+ if (display->priv->stream_video == SPICE_STREAM_VIDEO_FILTER) {
SpiceRect* rect;
int size;
@@ -880,26 +1029,26 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
void display_channel_print_stats(DisplayChannel *display)
{
#ifdef RED_WORKER_STAT
- stat_time_t total = display->add_stat.total;
+ stat_time_t total = display->priv->add_stat.total;
spice_info("add with shadow count %u",
- display->add_with_shadow_count);
- display->add_with_shadow_count = 0;
+ display->priv->add_with_shadow_count);
+ display->priv->add_with_shadow_count = 0;
spice_info("add[%u] %f exclude[%u] %f __exclude[%u] %f",
- display->add_stat.count,
+ display->priv->add_stat.count,
stat_cpu_time_to_sec(total),
- display->exclude_stat.count,
- stat_cpu_time_to_sec(display->exclude_stat.total),
- display->__exclude_stat.count,
- stat_cpu_time_to_sec(display->__exclude_stat.total));
+ display->priv->exclude_stat.count,
+ stat_cpu_time_to_sec(display->priv->exclude_stat.total),
+ display->priv->__exclude_stat.count,
+ stat_cpu_time_to_sec(display->priv->__exclude_stat.total));
spice_info("add %f%% exclude %f%% exclude2 %f%% __exclude %f%%",
- (double)(total - display->exclude_stat.total) / total * 100,
- (double)(display->exclude_stat.total) / total * 100,
- (double)(display->exclude_stat.total -
- display->__exclude_stat.total) / display->exclude_stat.total * 100,
- (double)(display->__exclude_stat.total) / display->exclude_stat.total * 100);
- stat_reset(&display->add_stat);
- stat_reset(&display->exclude_stat);
- stat_reset(&display->__exclude_stat);
+ (double)(total - display->priv->exclude_stat.total) / total * 100,
+ (double)(display->priv->exclude_stat.total) / total * 100,
+ (double)(display->priv->exclude_stat.total -
+ display->priv->__exclude_stat.total) / display->priv->exclude_stat.total * 100,
+ (double)(display->priv->__exclude_stat.total) / display->priv->exclude_stat.total * 100);
+ stat_reset(&display->priv->add_stat);
+ stat_reset(&display->priv->exclude_stat);
+ stat_reset(&display->priv->__exclude_stat);
#endif
}
@@ -914,7 +1063,7 @@ static void drawable_ref_surface_deps(DisplayChannel *display, Drawable *drawabl
if (surface_id == -1) {
continue;
}
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
surface->refs++;
}
}
@@ -923,7 +1072,7 @@ static void surface_read_bits(DisplayChannel *display, int surface_id,
const SpiceRect *area, uint8_t *dest, int dest_stride)
{
SpiceCanvas *canvas;
- RedSurface *surface = &display->surfaces[surface_id];
+ RedSurface *surface = &display->priv->surfaces[surface_id];
canvas = surface->context.canvas;
canvas->ops->read_bits(canvas, dest, dest_stride, area);
@@ -941,7 +1090,7 @@ static void handle_self_bitmap(DisplayChannel *display, Drawable *drawable)
int bpp;
int all_set;
- surface = &display->surfaces[drawable->surface_id];
+ surface = &display->priv->surfaces[drawable->surface_id];
bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
width = red_drawable->self_bitmap_area.right - red_drawable->self_bitmap_area.left;
@@ -993,7 +1142,7 @@ static void surface_add_reverse_dependency(DisplayChannel *display, int surface_
return;
}
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
depend_item->drawable = drawable;
ring_add(&surface->depend_on_me, &depend_item->ring_item);
@@ -1027,7 +1176,7 @@ static void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
RedSurface *surface;
RingItem *ring_item;
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
Drawable *drawable;
@@ -1045,10 +1194,10 @@ static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable
/* surface_id must be validated before calling into
* validate_drawable_bbox
*/
- if (!validate_surface(display, drawable->surface_id)) {
+ if (!display_channel_validate_surface(display, drawable->surface_id)) {
return FALSE;
}
- context = &display->surfaces[surface_id].context;
+ context = &display->priv->surfaces[surface_id].context;
if (drawable->bbox.top < 0)
return FALSE;
@@ -1088,7 +1237,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
}
for (x = 0; x < 3; ++x) {
if (red_drawable->surface_deps[x] != -1
- && !validate_surface(display, red_drawable->surface_deps[x])) {
+ && !display_channel_validate_surface(display, red_drawable->surface_deps[x])) {
return NULL;
}
}
@@ -1102,7 +1251,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
drawable->red_drawable = red_drawable_ref(red_drawable);
drawable->surface_id = red_drawable->surface_id;
- display->surfaces[drawable->surface_id].refs++;
+ display->priv->surfaces[drawable->surface_id].refs++;
memcpy(drawable->surface_deps, red_drawable->surface_deps, sizeof(drawable->surface_deps));
/*
@@ -1152,7 +1301,7 @@ static void display_channel_add_drawable(DisplayChannel *display, Drawable *draw
return;
}
- Ring *ring = &display->surfaces[surface_id].current;
+ Ring *ring = &display->priv->surfaces[surface_id].current;
int add_to_pipe;
if (has_shadow(red_drawable)) {
add_to_pipe = current_add_with_shadow(display, ring, drawable);
@@ -1165,7 +1314,7 @@ static void display_channel_add_drawable(DisplayChannel *display, Drawable *draw
pipes_add_drawable(display, drawable);
#ifdef RED_WORKER_STAT
- if ((++display->add_count % 100) == 0)
+ if ((++display->priv->add_count % 100) == 0)
display_channel_print_stats(display);
#endif
}
@@ -1189,18 +1338,18 @@ void display_channel_process_draw(DisplayChannel *display, RedDrawable *red_draw
int display_channel_wait_for_migrate_data(DisplayChannel *display)
{
uint64_t end_time = spice_get_monotonic_time_ns() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
- RedChannel *channel = &display->common.base;
RedChannelClient *rcc;
int ret = FALSE;
+ GList *clients = red_channel_get_clients(RED_CHANNEL(display));;
- if (!red_channel_is_waiting_for_migrate_data(&display->common.base)) {
+ if (!red_channel_is_waiting_for_migrate_data(RED_CHANNEL(display))) {
return FALSE;
}
spice_debug(NULL);
- spice_warn_if_fail(g_list_length(channel->clients) == 1);
+ spice_warn_if_fail(g_list_length(clients) == 1);
- rcc = channel->clients->data;
+ rcc = clients->data;
g_object_ref(rcc);
for (;;) {
@@ -1228,8 +1377,8 @@ void display_channel_flush_all_surfaces(DisplayChannel *display)
{
int x;
- for (x = 0; x < NUM_SURFACES; ++x) {
- if (display->surfaces[x].context.canvas) {
+ for (x = 0; x < display->priv->n_surfaces; ++x) {
+ if (display->priv->surfaces[x].context.canvas) {
display_channel_current_flush(display, x);
}
}
@@ -1261,7 +1410,7 @@ void display_channel_free_glz_drawables(DisplayChannel *display)
static bool free_one_drawable(DisplayChannel *display, int force_glz_free)
{
- RingItem *ring_item = ring_get_tail(&display->current_list);
+ RingItem *ring_item = ring_get_tail(&display->priv->current_list);
Drawable *drawable;
Container *container;
@@ -1287,7 +1436,7 @@ static bool free_one_drawable(DisplayChannel *display, int force_glz_free)
void display_channel_current_flush(DisplayChannel *display, int surface_id)
{
- while (!ring_is_empty(&display->surfaces[surface_id].current_list)) {
+ while (!ring_is_empty(&display->priv->surfaces[surface_id].current_list)) {
free_one_drawable(display, FALSE);
}
current_remove_all(display, surface_id);
@@ -1299,7 +1448,7 @@ void display_channel_free_some(DisplayChannel *display)
DisplayChannelClient *dcc;
GList *link, *next;
- spice_debug("#draw=%d, #glz_draw=%d", display->drawable_count,
+ spice_debug("#draw=%d, #glz_draw=%d", display->priv->drawable_count,
display->glz_drawable_count);
FOREACH_DCC(display, link, next, dcc) {
GlzSharedDictionary *glz_dict = dcc_get_glz_dictionary(dcc);
@@ -1312,7 +1461,7 @@ void display_channel_free_some(DisplayChannel *display)
}
}
- while (!ring_is_empty(&display->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
+ while (!ring_is_empty(&display->priv->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
free_one_drawable(display, TRUE);
}
@@ -1329,29 +1478,30 @@ static Drawable* drawable_try_new(DisplayChannel *display)
{
Drawable *drawable;
- if (!display->free_drawables)
+ if (!display->priv->free_drawables)
return NULL;
- drawable = &display->free_drawables->u.drawable;
- display->free_drawables = display->free_drawables->u.next;
- display->drawable_count++;
+ drawable = &display->priv->free_drawables->u.drawable;
+ display->priv->free_drawables = display->priv->free_drawables->u.next;
+ display->priv->drawable_count++;
return drawable;
}
static void drawable_free(DisplayChannel *display, Drawable *drawable)
{
- ((_Drawable *)drawable)->u.next = display->free_drawables;
- display->free_drawables = (_Drawable *)drawable;
+ ((_Drawable *)drawable)->u.next = display->priv->free_drawables;
+ display->priv->free_drawables = (_Drawable *)drawable;
}
static void drawables_init(DisplayChannel *display)
{
int i;
- display->free_drawables = NULL;
+ display->priv->drawables = g_new0(_Drawable, NUM_DRAWABLES);
+ display->priv->free_drawables = NULL;
for (i = 0; i < NUM_DRAWABLES; i++) {
- drawable_free(display, &display->drawables[i].u.drawable);
+ drawable_free(display, &display->priv->drawables[i].u.drawable);
}
}
@@ -1449,11 +1599,12 @@ void drawable_unref(Drawable *drawable)
SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = NULL;
ring_remove(item);
}
+
if (drawable->red_drawable) {
red_drawable_unref(drawable->red_drawable);
}
drawable_free(display, drawable);
- display->drawable_count--;
+ display->priv->drawable_count--;
}
static void drawable_deps_draw(DisplayChannel *display, Drawable *drawable)
@@ -1478,11 +1629,11 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
drawable_deps_draw(display, drawable);
- surface = &display->surfaces[drawable->surface_id];
+ surface = &display->priv->surfaces[drawable->surface_id];
canvas = surface->context.canvas;
spice_return_if_fail(canvas);
- image_cache_aging(&display->image_cache);
+ image_cache_aging(display->priv->image_cache);
region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox);
@@ -1490,8 +1641,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_FILL: {
SpiceFill fill = drawable->red_drawable->u.fill;
SpiceImage img1, img2;
- image_cache_localize_brush(&display->image_cache, &fill.brush, &img1);
- image_cache_localize_mask(&display->image_cache, &fill.mask, &img2);
+ image_cache_localize_brush(display->priv->image_cache, &fill.brush, &img1);
+ image_cache_localize_mask(display->priv->image_cache, &fill.mask, &img2);
canvas->ops->draw_fill(canvas, &drawable->red_drawable->bbox,
&clip, &fill);
break;
@@ -1499,17 +1650,17 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_OPAQUE: {
SpiceOpaque opaque = drawable->red_drawable->u.opaque;
SpiceImage img1, img2, img3;
- image_cache_localize_brush(&display->image_cache, &opaque.brush, &img1);
- image_cache_localize(&display->image_cache, &opaque.src_bitmap, &img2, drawable);
- image_cache_localize_mask(&display->image_cache, &opaque.mask, &img3);
+ image_cache_localize_brush(display->priv->image_cache, &opaque.brush, &img1);
+ image_cache_localize(display->priv->image_cache, &opaque.src_bitmap, &img2, drawable);
+ image_cache_localize_mask(display->priv->image_cache, &opaque.mask, &img3);
canvas->ops->draw_opaque(canvas, &drawable->red_drawable->bbox, &clip, &opaque);
break;
}
case QXL_DRAW_COPY: {
SpiceCopy copy = drawable->red_drawable->u.copy;
SpiceImage img1, img2;
- image_cache_localize(&display->image_cache, ©.src_bitmap, &img1, drawable);
- image_cache_localize_mask(&display->image_cache, ©.mask, &img2);
+ image_cache_localize(display->priv->image_cache, ©.src_bitmap, &img1, drawable);
+ image_cache_localize_mask(display->priv->image_cache, ©.mask, &img2);
canvas->ops->draw_copy(canvas, &drawable->red_drawable->bbox,
&clip, ©);
break;
@@ -1517,7 +1668,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_TRANSPARENT: {
SpiceTransparent transparent = drawable->red_drawable->u.transparent;
SpiceImage img1;
- image_cache_localize(&display->image_cache, &transparent.src_bitmap, &img1, drawable);
+ image_cache_localize(display->priv->image_cache, &transparent.src_bitmap, &img1, drawable);
canvas->ops->draw_transparent(canvas,
&drawable->red_drawable->bbox, &clip, &transparent);
break;
@@ -1525,7 +1676,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_ALPHA_BLEND: {
SpiceAlphaBlend alpha_blend = drawable->red_drawable->u.alpha_blend;
SpiceImage img1;
- image_cache_localize(&display->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
+ image_cache_localize(display->priv->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
canvas->ops->draw_alpha_blend(canvas,
&drawable->red_drawable->bbox, &clip, &alpha_blend);
break;
@@ -1538,8 +1689,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_BLEND: {
SpiceBlend blend = drawable->red_drawable->u.blend;
SpiceImage img1, img2;
- image_cache_localize(&display->image_cache, &blend.src_bitmap, &img1, drawable);
- image_cache_localize_mask(&display->image_cache, &blend.mask, &img2);
+ image_cache_localize(display->priv->image_cache, &blend.src_bitmap, &img1, drawable);
+ image_cache_localize_mask(display->priv->image_cache, &blend.mask, &img2);
canvas->ops->draw_blend(canvas, &drawable->red_drawable->bbox,
&clip, &blend);
break;
@@ -1547,7 +1698,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_BLACKNESS: {
SpiceBlackness blackness = drawable->red_drawable->u.blackness;
SpiceImage img1;
- image_cache_localize_mask(&display->image_cache, &blackness.mask, &img1);
+ image_cache_localize_mask(display->priv->image_cache, &blackness.mask, &img1);
canvas->ops->draw_blackness(canvas,
&drawable->red_drawable->bbox, &clip, &blackness);
break;
@@ -1555,7 +1706,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_WHITENESS: {
SpiceWhiteness whiteness = drawable->red_drawable->u.whiteness;
SpiceImage img1;
- image_cache_localize_mask(&display->image_cache, &whiteness.mask, &img1);
+ image_cache_localize_mask(display->priv->image_cache, &whiteness.mask, &img1);
canvas->ops->draw_whiteness(canvas,
&drawable->red_drawable->bbox, &clip, &whiteness);
break;
@@ -1563,7 +1714,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_INVERS: {
SpiceInvers invers = drawable->red_drawable->u.invers;
SpiceImage img1;
- image_cache_localize_mask(&display->image_cache, &invers.mask, &img1);
+ image_cache_localize_mask(display->priv->image_cache, &invers.mask, &img1);
canvas->ops->draw_invers(canvas,
&drawable->red_drawable->bbox, &clip, &invers);
break;
@@ -1571,9 +1722,9 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_ROP3: {
SpiceRop3 rop3 = drawable->red_drawable->u.rop3;
SpiceImage img1, img2, img3;
- image_cache_localize_brush(&display->image_cache, &rop3.brush, &img1);
- image_cache_localize(&display->image_cache, &rop3.src_bitmap, &img2, drawable);
- image_cache_localize_mask(&display->image_cache, &rop3.mask, &img3);
+ image_cache_localize_brush(display->priv->image_cache, &rop3.brush, &img1);
+ image_cache_localize(display->priv->image_cache, &rop3.src_bitmap, &img2, drawable);
+ image_cache_localize_mask(display->priv->image_cache, &rop3.mask, &img3);
canvas->ops->draw_rop3(canvas, &drawable->red_drawable->bbox,
&clip, &rop3);
break;
@@ -1581,9 +1732,9 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_COMPOSITE: {
SpiceComposite composite = drawable->red_drawable->u.composite;
SpiceImage src, mask;
- image_cache_localize(&display->image_cache, &composite.src_bitmap, &src, drawable);
+ image_cache_localize(display->priv->image_cache, &composite.src_bitmap, &src, drawable);
if (composite.mask_bitmap)
- image_cache_localize(&display->image_cache, &composite.mask_bitmap, &mask, drawable);
+ image_cache_localize(display->priv->image_cache, &composite.mask_bitmap, &mask, drawable);
canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox,
&clip, &composite);
break;
@@ -1591,7 +1742,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_STROKE: {
SpiceStroke stroke = drawable->red_drawable->u.stroke;
SpiceImage img1;
- image_cache_localize_brush(&display->image_cache, &stroke.brush, &img1);
+ image_cache_localize_brush(display->priv->image_cache, &stroke.brush, &img1);
canvas->ops->draw_stroke(canvas,
&drawable->red_drawable->bbox, &clip, &stroke);
break;
@@ -1599,8 +1750,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
case QXL_DRAW_TEXT: {
SpiceText text = drawable->red_drawable->u.text;
SpiceImage img1, img2;
- image_cache_localize_brush(&display->image_cache, &text.fore_brush, &img1);
- image_cache_localize_brush(&display->image_cache, &text.back_brush, &img2);
+ image_cache_localize_brush(display->priv->image_cache, &text.fore_brush, &img1);
+ image_cache_localize_brush(display->priv->image_cache, &text.back_brush, &img2);
canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox,
&clip, &text);
break;
@@ -1692,11 +1843,11 @@ void display_channel_draw_until(DisplayChannel *display, const SpiceRect *area,
spice_return_if_fail(last);
spice_return_if_fail(ring_item_is_linked(&last->list_link));
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
if (surface_id != last->surface_id) {
// find the nearest older drawable from the appropriate surface
- ring = &display->current_list;
+ ring = &display->priv->current_list;
ring_item = &last->list_link;
while ((ring_item = ring_next(ring, ring_item))) {
now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
@@ -1732,12 +1883,12 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
spice_debug("surface %d: area ==>", surface_id);
rect_debug(area);
- spice_return_if_fail(surface_id >= 0 && surface_id < NUM_SURFACES);
+ spice_return_if_fail(surface_id >= 0 && surface_id < display->priv->n_surfaces);
spice_return_if_fail(area);
spice_return_if_fail(area->left >= 0 && area->top >= 0 &&
area->left < area->right && area->top < area->bottom);
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
last = current_find_intersects_rect(&surface->current_list, NULL, area);
if (last)
@@ -1769,12 +1920,12 @@ void display_channel_update(DisplayChannel *display,
SpiceRect rect;
RedSurface *surface;
- spice_return_if_fail(validate_surface(display, surface_id));
+ spice_return_if_fail(display_channel_validate_surface(display, surface_id));
red_get_rect_ptr(&rect, area);
display_channel_draw(display, &rect, surface_id);
- surface = &display->surfaces[surface_id];
+ surface = &display->priv->surfaces[surface_id];
if (*qxl_dirty_rects == NULL) {
*num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
*qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
@@ -1812,9 +1963,9 @@ void display_channel_destroy_surface(DisplayChannel *display, uint32_t surface_i
void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t surface_id)
{
- if (!validate_surface(display, surface_id))
+ if (!display_channel_validate_surface(display, surface_id))
return;
- if (!display->surfaces[surface_id].context.canvas)
+ if (!display->priv->surfaces[surface_id].context.canvas)
return;
draw_depend_on_me(display, surface_id);
@@ -1833,16 +1984,16 @@ void display_channel_destroy_surfaces(DisplayChannel *display)
spice_debug(NULL);
//to handle better
- for (i = 0; i < NUM_SURFACES; ++i) {
- if (display->surfaces[i].context.canvas) {
+ for (i = 0; i < display->priv->n_surfaces; ++i) {
+ if (display->priv->surfaces[i].context.canvas) {
display_channel_destroy_surface_wait(display, i);
- if (display->surfaces[i].context.canvas) {
+ if (display->priv->surfaces[i].context.canvas) {
display_channel_surface_unref(display, i);
}
- spice_assert(!display->surfaces[i].context.canvas);
+ spice_assert(!display->priv->surfaces[i].context.canvas);
}
}
- spice_warn_if_fail(ring_is_empty(&display->streams));
+ spice_warn_if_fail(ring_is_empty(&display->priv->streams));
if (red_channel_is_connected(RED_CHANNEL(display))) {
red_channel_pipes_add_type(RED_CHANNEL(display), RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
@@ -1873,8 +2024,8 @@ create_canvas_for_surface(DisplayChannel *display, RedSurface *surface, uint32_t
case RED_RENDERER_SW:
canvas = canvas_create_for_data(surface->context.width, surface->context.height, surface->context.format,
surface->context.line_0, surface->context.stride,
- &display->image_cache.base,
- &display->image_surfaces, NULL, NULL, NULL);
+ &display->priv->image_cache->base,
+ &display->priv->image_surfaces, NULL, NULL, NULL);
surface->context.top_down = TRUE;
surface->context.canvas_draws_on_surface = TRUE;
return canvas;
@@ -1889,7 +2040,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
uint32_t height, int32_t stride, uint32_t format,
void *line_0, int data_is_valid, int send_client)
{
- RedSurface *surface = &display->surfaces[surface_id];
+ RedSurface *surface = &display->priv->surfaces[surface_id];
spice_warn_if_fail(!surface->context.canvas);
@@ -1914,21 +2065,21 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
region_init(&surface->draw_dirty_region);
surface->refs = 1;
- if (display->renderer == RED_RENDERER_INVALID) {
+ if (display->priv->renderer == RED_RENDERER_INVALID) {
int i;
- QXLInstance *qxl = display->common.qxl;
+ QXLInstance *qxl = common_graphics_channel_get_qxl(&display->parent);
RedsState *reds = red_qxl_get_server(qxl->st);
GArray *renderers = reds_get_renderers(reds);
for (i = 0; i < renderers->len; i++) {
uint32_t renderer = g_array_index(renderers, uint32_t, i);
surface->context.canvas = create_canvas_for_surface(display, surface, renderer);
if (surface->context.canvas) {
- display->renderer = renderer;
+ display->priv->renderer = renderer;
break;
}
}
} else {
- surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer);
+ surface->context.canvas = create_canvas_for_surface(display, surface, display->priv->renderer);
}
spice_return_if_fail(surface->context.canvas);
@@ -1952,7 +2103,7 @@ static void on_disconnect(RedChannelClient *rcc)
// this was the last channel client
spice_debug("#draw=%d, #glz_draw=%d",
- display->drawable_count,
+ display->priv->drawable_count,
display->glz_drawable_count);
}
@@ -2007,72 +2158,27 @@ static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *messa
return dcc_handle_migrate_data(DISPLAY_CHANNEL_CLIENT(rcc), size, message);
}
-static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
-{
- DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
-
- spice_return_val_if_fail(validate_surface(display, surface_id), NULL);
-
- return display->surfaces[surface_id].context.canvas;
-}
-
-DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker,
+DisplayChannel* display_channel_new(SpiceServer *reds,
+ QXLInstance *qxl,
+ const SpiceCoreInterfaceInternal* core,
int migrate, int stream_video,
uint32_t n_surfaces)
{
DisplayChannel *display;
- ChannelCbs cbs = {
- .on_disconnect = on_disconnect,
- .send_item = send_item,
- .hold_item = hold_item,
- .release_item = release_item,
- .handle_migrate_flush_mark = handle_migrate_flush_mark,
- .handle_migrate_data = handle_migrate_data,
- .handle_migrate_data_get_serial = handle_migrate_data_get_serial
- };
- static SpiceImageSurfacesOps image_surfaces_ops = {
- image_surfaces_get,
- };
+ /* FIXME: migrate is not used...? */
spice_info("create display channel");
- display = (DisplayChannel *)red_worker_new_channel(
- worker, sizeof(*display), "display_channel",
- SPICE_CHANNEL_DISPLAY,
- SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
- &cbs, dcc_handle_message);
- spice_return_val_if_fail(display, NULL);
-
- clockid_t stat_clock = CLOCK_THREAD_CPUTIME_ID;
- stat_init(&display->add_stat, "add", stat_clock);
- stat_init(&display->exclude_stat, "exclude", stat_clock);
- stat_init(&display->__exclude_stat, "__exclude", stat_clock);
-#ifdef RED_STATISTICS
- RedChannel *channel = RED_CHANNEL(display);
- display->cache_hits_counter = stat_add_counter(reds, channel->stat,
- "cache_hits", TRUE);
- display->add_to_cache_counter = stat_add_counter(reds, channel->stat,
- "add_to_cache", TRUE);
- display->non_cache_counter = stat_add_counter(reds, channel->stat,
- "non_cache", TRUE);
-#endif
- stat_compress_init(&display->lz_stat, "lz", stat_clock);
- stat_compress_init(&display->glz_stat, "glz", stat_clock);
- stat_compress_init(&display->quic_stat, "quic", stat_clock);
- stat_compress_init(&display->jpeg_stat, "jpeg", stat_clock);
- stat_compress_init(&display->zlib_glz_stat, "zlib", stat_clock);
- stat_compress_init(&display->jpeg_alpha_stat, "jpeg_alpha", stat_clock);
- stat_compress_init(&display->lz4_stat, "lz4", stat_clock);
-
- display->n_surfaces = n_surfaces;
- display->renderer = RED_RENDERER_INVALID;
-
- ring_init(&display->current_list);
- display->image_surfaces.ops = &image_surfaces_ops;
- drawables_init(display);
- image_cache_init(&display->image_cache);
- display->stream_video = stream_video;
- display_channel_init_streams(display);
-
+ display = g_object_new(TYPE_DISPLAY_CHANNEL,
+ "spice-server", reds,
+ "core-interface", core,
+ "channel-type", SPICE_CHANNEL_DISPLAY,
+ "migration-flags", (SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
+ "qxl", qxl,
+ "n-surfaces", n_surfaces,
+ NULL);
+ if (display) {
+ display_channel_set_stream_video(display, stream_video);
+ }
return display;
}
@@ -2084,11 +2190,11 @@ void display_channel_process_surface_cmd(DisplayChannel *display, RedSurfaceCmd
uint8_t *data;
surface_id = surface->surface_id;
- if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
+ if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) {
return;
}
- red_surface = &display->surfaces[surface_id];
+ red_surface = &display->priv->surfaces[surface_id];
switch (surface->type) {
case QXL_SURFACE_CMD_CREATE: {
@@ -2129,18 +2235,18 @@ void display_channel_update_compression(DisplayChannel *display, DisplayChannelC
{
gboolean is_low_bw = common_graphics_channel_client_is_low_bandwidth(COMMON_GRAPHICS_CHANNEL_CLIENT(dcc));
if (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) {
- display->enable_jpeg = is_low_bw;
+ display->priv->enable_jpeg = is_low_bw;
} else {
- display->enable_jpeg = (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
+ display->priv->enable_jpeg = (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
}
if (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) {
- display->enable_zlib_glz_wrap = is_low_bw;
+ display->priv->enable_zlib_glz_wrap = is_low_bw;
} else {
- display->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
+ display->priv->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
}
- spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled");
- spice_info("zlib-over-glz %s", display->enable_zlib_glz_wrap ? "enabled" : "disabled");
+ spice_info("jpeg %s", display->priv->enable_jpeg ? "enabled" : "disabled");
+ spice_info("zlib-over-glz %s", display->priv->enable_zlib_glz_wrap ? "enabled" : "disabled");
}
void display_channel_gl_scanout(DisplayChannel *display)
@@ -2150,9 +2256,9 @@ void display_channel_gl_scanout(DisplayChannel *display)
static void set_gl_draw_async_count(DisplayChannel *display, int num)
{
- QXLInstance *qxl = display->common.qxl;
+ QXLInstance *qxl = common_graphics_channel_get_qxl(&display->parent);
- display->gl_draw_async_count = num;
+ display->priv->gl_draw_async_count = num;
if (num == 0) {
red_qxl_gl_draw_async_complete(qxl);
@@ -2163,7 +2269,7 @@ void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *dra
{
int num;
- spice_return_if_fail(display->gl_draw_async_count == 0);
+ spice_return_if_fail(display->priv->gl_draw_async_count == 0);
num = red_channel_pipes_new_add_push(RED_CHANNEL(display), dcc_gl_draw_item_new, draw);
set_gl_draw_async_count(display, num);
@@ -2171,5 +2277,93 @@ void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *dra
void display_channel_gl_draw_done(DisplayChannel *display)
{
- set_gl_draw_async_count(display, display->gl_draw_async_count - 1);
+ set_gl_draw_async_count(display, display->priv->gl_draw_async_count - 1);
+}
+
+int display_channel_get_stream_id(DisplayChannel *display, Stream *stream)
+{
+ return (int)(stream - display->priv->streams_buf);
+}
+
+gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id)
+{
+ if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) {
+ spice_warning("invalid surface_id %u", surface_id);
+ return 0;
+ }
+ if (!display->priv->surfaces[surface_id].context.canvas) {
+ spice_warning("canvas address is %p for %d (and is NULL)\n",
+ &(display->priv->surfaces[surface_id].context.canvas), surface_id);
+ spice_warning("failed on %d", surface_id);
+ return 0;
+ }
+ return 1;
+}
+
+void display_channel_update_monitors_config(DisplayChannel *display,
+ QXLMonitorsConfig *config,
+ uint16_t count, uint16_t max_allowed)
+{
+ if (display->priv->monitors_config)
+ monitors_config_unref(display->priv->monitors_config);
+
+ display->priv->monitors_config =
+ monitors_config_new(config->heads, count, max_allowed);
+
+}
+
+void display_channel_set_monitors_config_to_primary(DisplayChannel *display)
+{
+ DrawContext *context = &display->priv->surfaces[0].context;
+ QXLHead head = { 0, };
+
+ spice_return_if_fail(display->priv->surfaces[0].context.canvas);
+
+ if (display->priv->monitors_config)
+ monitors_config_unref(display->priv->monitors_config);
+
+ head.width = context->width;
+ head.height = context->height;
+ display->priv->monitors_config = monitors_config_new(&head, 1, 1);
+}
+
+void display_channel_reset_image_cache(DisplayChannel *self)
+{
+ image_cache_reset(self->priv->image_cache);
+}
+
+static void
+display_channel_class_init(DisplayChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(DisplayChannelPrivate));
+
+ object_class->get_property = display_channel_get_property;
+ object_class->set_property = display_channel_set_property;
+ object_class->constructed = display_channel_constructed;
+ object_class->finalize = display_channel_finalize;
+
+ channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
+ channel_class->handle_parsed = dcc_handle_message;
+
+ channel_class->on_disconnect = on_disconnect;
+ channel_class->send_item = send_item;
+ channel_class->hold_item = hold_item;
+ channel_class->release_item = release_item;
+ channel_class->handle_migrate_flush_mark = handle_migrate_flush_mark;
+ channel_class->handle_migrate_data = handle_migrate_data;
+ channel_class->handle_migrate_data_get_serial = handle_migrate_data_get_serial;
+
+ g_object_class_install_property(object_class,
+ PROP_N_SURFACES,
+ g_param_spec_uint("n-surfaces",
+ "number of surfaces",
+ "Number of surfaces for this channel",
+ 0, G_MAXUINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
}
diff --git a/server/display-channel.h b/server/display-channel.h
index cb0a1e3..597d615 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -20,31 +20,63 @@
#include <setjmp.h>
-#include "common/rect.h"
-#include "reds-stream.h"
#include "cache-item.h"
-#include "pixmap-cache.h"
#include "sw-canvas.h"
-#include "stat.h"
-#include "reds.h"
-#include "memslot.h"
-#include "red-parse-qxl.h"
-#include "red-record-qxl.h"
+#include "common-graphics-channel.h"
+#include "common/rect.h"
+#include "dcc-encoders.h"
+#include "dcc.h"
#include "demarshallers.h"
-#include "red-channel.h"
-#include "red-qxl.h"
#include "dispatcher.h"
#include "main-channel.h"
-#include "migration-protocol.h"
#include "main-dispatcher.h"
+#include "memslot.h"
+#include "migration-protocol.h"
+#include "mjpeg-encoder.h"
+#include "pixmap-cache.h"
+#include "red-channel.h"
+#include "red-qxl.h"
+#include "red-parse-qxl.h"
+#include "red-record-qxl.h"
+#include "reds-stream.h"
+#include "reds.h"
#include "spice-bitmap-utils.h"
-#include "image-cache.h"
-#include "utils.h"
-#include "tree.h"
+#include "stat.h"
#include "stream.h"
-#include "dcc.h"
-#include "dcc-encoders.h"
+#include "tree.h"
+#include "utils.h"
+
+G_BEGIN_DECLS
+#define TYPE_DISPLAY_CHANNEL display_channel_get_type()
+
+#define DISPLAY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DISPLAY_CHANNEL, DisplayChannel))
+#define DISPLAY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DISPLAY_CHANNEL, DisplayChannelClass))
+#define IS_DISPLAY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DISPLAY_CHANNEL))
+#define IS_DISPLAY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DISPLAY_CHANNEL))
+#define DISPLAY_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DISPLAY_CHANNEL, DisplayChannelClass))
+
+typedef struct DisplayChannel DisplayChannel;
+typedef struct DisplayChannelClass DisplayChannelClass;
+typedef struct DisplayChannelPrivate DisplayChannelPrivate;
+
+struct DisplayChannel
+{
+ CommonGraphicsChannel parent;
+
+ uint32_t glz_drawable_count;
+
+ DisplayChannelPrivate *priv;
+};
+
+struct DisplayChannelClass
+{
+ CommonGraphicsChannelClass parent_class;
+};
+
+GType display_channel_get_type(void) G_GNUC_CONST;
+
+G_END_DECLS
typedef struct DependItem {
Drawable *drawable;
RingItem ring_item;
@@ -164,68 +196,8 @@ struct _Drawable {
} u;
};
-struct DisplayChannel {
- CommonGraphicsChannel common; // Must be the first thing
- uint32_t bits_unique;
-
- MonitorsConfig *monitors_config;
-
- uint32_t renderer;
- int enable_jpeg;
- int enable_zlib_glz_wrap;
-
- Ring current_list; // of TreeItem
- uint32_t current_size;
-
- uint32_t drawable_count;
- _Drawable drawables[NUM_DRAWABLES];
- _Drawable *free_drawables;
-
- uint32_t glz_drawable_count;
-
- int stream_video;
- uint32_t stream_count;
- Stream streams_buf[NUM_STREAMS];
- Stream *free_streams;
- Ring streams;
- ItemTrace items_trace[NUM_TRACE_ITEMS];
- uint32_t next_item_trace;
- uint64_t streams_size_total;
-
- RedSurface surfaces[NUM_SURFACES];
- uint32_t n_surfaces;
- SpiceImageSurfaces image_surfaces;
-
- ImageCache image_cache;
- RedCompressBuf *free_compress_bufs;
-
- int gl_draw_async_count;
-
-/* TODO: some day unify this, make it more runtime.. */
- stat_info_t add_stat;
- stat_info_t exclude_stat;
- stat_info_t __exclude_stat;
-#ifdef RED_WORKER_STAT
- uint32_t add_count;
- uint32_t add_with_shadow_count;
-#endif
-#ifdef RED_STATISTICS
- uint64_t *cache_hits_counter;
- uint64_t *add_to_cache_counter;
- uint64_t *non_cache_counter;
-#endif
- stat_info_t off_stat;
- stat_info_t lz_stat;
- stat_info_t glz_stat;
- stat_info_t quic_stat;
- stat_info_t jpeg_stat;
- stat_info_t zlib_glz_stat;
- stat_info_t jpeg_alpha_stat;
- stat_info_t lz4_stat;
-};
-
#define FOREACH_DCC(channel, _link, _next, _data) \
- for (_link = (channel ? RED_CHANNEL(channel)->clients : NULL), \
+ for (_link = (channel ? red_channel_get_clients(RED_CHANNEL(channel)) : NULL), \
_next = (_link ? _link->next : NULL), \
_data = (_link ? _link->data : NULL); \
_link; \
@@ -233,10 +205,7 @@ struct DisplayChannel {
_next = (_link ? _link->next : NULL), \
_data = (_link ? _link->data : NULL))
-static inline int get_stream_id(DisplayChannel *display, Stream *stream)
-{
- return (int)(stream - display->streams_buf);
-}
+int display_channel_get_stream_id(DisplayChannel *display, Stream *stream);
typedef struct RedSurfaceDestroyItem {
SpiceMsgSurfaceDestroy surface_destroy;
@@ -251,7 +220,8 @@ typedef struct RedUpgradeItem {
DisplayChannel* display_channel_new (SpiceServer *reds,
- RedWorker *worker,
+ QXLInstance *qxl,
+ const SpiceCoreInterfaceInternal* core,
int migrate,
int stream_video,
uint32_t n_surfaces);
@@ -275,13 +245,16 @@ void display_channel_update (DisplayCha
void display_channel_free_some (DisplayChannel *display);
void display_channel_set_stream_video (DisplayChannel *display,
int stream_video);
+int display_channel_get_stream_video (DisplayChannel *display);
int display_channel_get_streams_timeout (DisplayChannel *display);
-void display_channel_compress_stats_print (const DisplayChannel *display);
+void display_channel_compress_stats_print (DisplayChannel *display);
void display_channel_compress_stats_reset (DisplayChannel *display);
Drawable * display_channel_drawable_try_new (DisplayChannel *display,
int process_commands_generation);
void display_channel_surface_unref (DisplayChannel *display,
uint32_t surface_id);
+bool display_channel_surface_has_canvas (DisplayChannel *display,
+ uint32_t surface_id);
void display_channel_current_flush (DisplayChannel *display,
int surface_id);
int display_channel_wait_for_migrate_data (DisplayChannel *display);
@@ -306,21 +279,12 @@ void display_channel_gl_scanout (DisplayCha
void display_channel_gl_draw (DisplayChannel *display,
SpiceMsgDisplayGlDraw *draw);
void display_channel_gl_draw_done (DisplayChannel *display);
+void display_channel_update_monitors_config(DisplayChannel *display, QXLMonitorsConfig *config,
+ uint16_t count, uint16_t max_allowed);
+void display_channel_set_monitors_config_to_primary(DisplayChannel *display);
-static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
-{
- if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
- spice_warning("invalid surface_id %u", surface_id);
- return 0;
- }
- if (!display->surfaces[surface_id].context.canvas) {
- spice_warning("canvas address is %p for %d (and is NULL)\n",
- &(display->surfaces[surface_id].context.canvas), surface_id);
- spice_warning("failed on %d", surface_id);
- return 0;
- }
- return 1;
-}
+gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id);
+void display_channel_reset_image_cache(DisplayChannel *self);
static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
{
diff --git a/server/dummy-channel-client.c b/server/dummy-channel-client.c
index a0354fd..6f0b868 100644
--- a/server/dummy-channel-client.c
+++ b/server/dummy-channel-client.c
@@ -36,9 +36,11 @@ struct DummyChannelClientPrivate
static int dummy_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
{
- if (red_client_get_channel(client, channel->type, channel->id)) {
+ uint32_t type, id;
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ if (red_client_get_channel(client, type, id)) {
spice_printerr("Error client %p: duplicate channel type %d id %d",
- client, channel->type, channel->id);
+ client, type, id);
return FALSE;
}
return TRUE;
@@ -53,6 +55,9 @@ static gboolean dummy_channel_client_initable_init(GInitable *initable,
RedChannelClient *rcc = RED_CHANNEL_CLIENT(self);
RedClient *client = red_channel_client_get_client(rcc);
RedChannel *channel = red_channel_client_get_channel(rcc);
+ uint32_t type, id;
+
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
pthread_mutex_lock(&client->lock);
if (!dummy_channel_client_pre_create_validate(channel,
client)) {
@@ -60,7 +65,7 @@ static gboolean dummy_channel_client_initable_init(GInitable *initable,
SPICE_SERVER_ERROR,
SPICE_SERVER_ERROR_FAILED,
"Client %p: duplicate channel type %d id %d",
- client, channel->type, channel->id);
+ client, type, id);
goto cleanup;
}
@@ -94,10 +99,12 @@ void dummy_channel_client_disconnect(RedChannelClient *rcc)
DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(rcc);
RedChannel *channel = red_channel_client_get_channel(rcc);
GList *link;
+ uint32_t type, id;
- if (channel && (link = g_list_find(channel->clients, rcc))) {
+ if (channel && (link = g_list_find(red_channel_get_clients(channel), rcc))) {
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
- channel->type, channel->id);
+ type, id);
red_channel_remove_client(channel, link->data);
}
self->priv->connected = FALSE;
diff --git a/server/dummy-channel.c b/server/dummy-channel.c
new file mode 100644
index 0000000..6ec7842
--- /dev/null
+++ b/server/dummy-channel.c
@@ -0,0 +1,58 @@
+/* dummy-channel.c */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "dummy-channel.h"
+
+G_DEFINE_TYPE(DummyChannel, dummy_channel, RED_TYPE_CHANNEL)
+
+#define DUMMY_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DUMMY_CHANNEL, DummyChannelPrivate))
+
+struct DummyChannelPrivate
+{
+ gpointer padding;
+};
+
+static void
+dummy_channel_class_init(DummyChannelClass *klass)
+{
+ g_type_class_add_private(klass, sizeof(DummyChannelPrivate));
+}
+
+static void
+dummy_channel_init(DummyChannel *self)
+{
+ self->priv = DUMMY_CHANNEL_PRIVATE(self);
+}
+
+// TODO: red_worker can use this one
+static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+}
+
+static SpiceWatch *dummy_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+ return NULL; // apparently allowed?
+}
+
+static void dummy_watch_remove(SpiceWatch *watch)
+{
+}
+
+// TODO: actually, since I also use channel_client_dummym, no need for core. Can be NULL
+static const SpiceCoreInterface dummy_core = {
+ .watch_update_mask = dummy_watch_update_mask,
+ .watch_add = dummy_watch_add,
+ .watch_remove = dummy_watch_remove,
+};
+
+RedChannel *dummy_channel_new(RedsState *reds, uint32_t type, uint32_t id)
+{
+ return g_object_new(TYPE_DUMMY_CHANNEL,
+ "spice-server", reds,
+ "core-interface", &dummy_core,
+ "channel-type", type,
+ "id", id,
+ NULL);
+}
diff --git a/server/dummy-channel.h b/server/dummy-channel.h
new file mode 100644
index 0000000..dd2f005
--- /dev/null
+++ b/server/dummy-channel.h
@@ -0,0 +1,61 @@
+/*
+ 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 __DUMMY_CHANNEL_H__
+#define __DUMMY_CHANNEL_H__
+
+#include <glib-object.h>
+
+#include "red-channel.h"
+
+G_BEGIN_DECLS
+
+// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd channel), but
+// do use the client callbacks. So the channel clients are not connected (the channel doesn't
+// have list of them, but they do have a link to the channel, and the client has a list of them)
+
+#define TYPE_DUMMY_CHANNEL dummy_channel_get_type()
+
+#define DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DUMMY_CHANNEL, DummyChannel))
+#define DUMMY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DUMMY_CHANNEL, DummyChannelClass))
+#define _IS_DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DUMMY_CHANNEL))
+#define _IS_DUMMY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DUMMY_CHANNEL))
+#define DUMMY_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DUMMY_CHANNEL, DummyChannelClass))
+
+typedef struct DummyChannel DummyChannel;
+typedef struct DummyChannelClass DummyChannelClass;
+typedef struct DummyChannelPrivate DummyChannelPrivate;
+
+struct DummyChannel
+{
+ RedChannel parent;
+
+ DummyChannelPrivate *priv;
+};
+
+struct DummyChannelClass
+{
+ RedChannelClass parent_class;
+};
+
+GType dummy_channel_get_type(void) G_GNUC_CONST;
+
+RedChannel *dummy_channel_new(RedsState *reds, uint32_t type, uint32_t id);
+
+G_END_DECLS
+
+#endif /* __DUMMY_CHANNEL_H__ */
diff --git a/server/inputs-channel.c b/server/inputs-channel.c
index c0fdc98..32e2cfe 100644
--- a/server/inputs-channel.c
+++ b/server/inputs-channel.c
@@ -57,6 +57,83 @@
#define RECEIVE_BUF_SIZE \
(4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
+G_DEFINE_TYPE(InputsChannel, inputs_channel, RED_TYPE_CHANNEL)
+
+#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_INPUTS_CHANNEL, InputsChannelPrivate))
+
+struct InputsChannelPrivate
+{
+ uint8_t recv_buf[RECEIVE_BUF_SIZE];
+ VDAgentMouseState mouse_state;
+ int src_during_migrate;
+
+ SpiceKbdInstance *keyboard;
+ SpiceMouseInstance *mouse;
+ SpiceTabletInstance *tablet;
+};
+
+
+static void
+inputs_channel_get_property(GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+inputs_channel_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void inputs_connect(RedChannel *channel, RedClient *client,
+ RedsStream *stream, int migration,
+ int num_common_caps, uint32_t *common_caps,
+ int num_caps, uint32_t *caps);
+static void inputs_migrate(RedChannelClient *rcc);
+static SpiceTimer *key_modifiers_timer;
+static void key_modifiers_sender(void *opaque);
+
+static void
+inputs_channel_constructed(GObject *object)
+{
+ ClientCbs client_cbs = { NULL, };
+ InputsChannel *self = INPUTS_CHANNEL(object);
+ RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
+
+ G_OBJECT_CLASS(inputs_channel_parent_class)->constructed(object);
+
+ client_cbs.connect = inputs_connect;
+ client_cbs.migrate = inputs_migrate;
+ red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
+
+ red_channel_set_cap(RED_CHANNEL(self), SPICE_INPUTS_CAP_KEY_SCANCODE);
+ reds_register_channel(reds, RED_CHANNEL(self));
+
+ if (!(key_modifiers_timer = reds_core_timer_add(reds, key_modifiers_sender, self))) {
+ spice_error("key modifiers timer create failed");
+ }
+}
+
+static void
+inputs_channel_init(InputsChannel *self)
+{
+ self->priv = CHANNEL_PRIVATE(self);
+}
+
struct SpiceKbdState {
bool push_ext;
@@ -101,17 +178,6 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *st)
return st->reds;
}
-struct InputsChannel {
- RedChannel base;
- uint8_t recv_buf[RECEIVE_BUF_SIZE];
- VDAgentMouseState mouse_state;
- int src_during_migrate;
-
- SpiceKbdInstance *keyboard;
- SpiceMouseInstance *mouse;
- SpiceTabletInstance *tablet;
-};
-
typedef struct RedInputsPipeItem {
RedPipeItem base;
} RedInputsPipeItem;
@@ -126,8 +192,6 @@ typedef struct RedInputsInitPipeItem {
uint8_t modifiers;
} RedInputsInitPipeItem;
-static SpiceTimer *key_modifiers_timer;
-
#define KEY_MODIFIERS_TTL (MSEC_PER_SEC * 2)
@@ -139,26 +203,26 @@ void inputs_channel_set_tablet_logical_size(InputsChannel *inputs, int x_res, in
{
SpiceTabletInterface *sif;
- sif = SPICE_CONTAINEROF(inputs->tablet->base.sif, SpiceTabletInterface, base);
- sif->set_logical_size(inputs->tablet, x_res, y_res);
+ sif = SPICE_CONTAINEROF(inputs->priv->tablet->base.sif, SpiceTabletInterface, base);
+ sif->set_logical_size(inputs->priv->tablet, x_res, y_res);
}
VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs)
{
- return &inputs->mouse_state;
+ return &inputs->priv->mouse_state;
}
static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
uint16_t type,
uint32_t size)
{
- InputsChannel *inputs_channel = (InputsChannel*)red_channel_client_get_channel(rcc);
+ InputsChannel *inputs = (InputsChannel*)red_channel_client_get_channel(rcc);
if (size > RECEIVE_BUF_SIZE) {
spice_printerr("error: too large incoming message");
return NULL;
}
- return inputs_channel->recv_buf;
+ return inputs->priv->recv_buf;
}
static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc,
@@ -276,10 +340,10 @@ static void inputs_channel_send_item(RedChannelClient *rcc, RedPipeItem *base)
static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
void *message)
{
- InputsChannel *inputs_channel = (InputsChannel *)red_channel_client_get_channel(rcc);
+ InputsChannel *inputs = INPUTS_CHANNEL(red_channel_client_get_channel(rcc));
InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc);
uint32_t i;
- RedsState *reds = red_channel_get_server(&inputs_channel->base);
+ RedsState *reds = red_channel_get_server(RED_CHANNEL(inputs));
switch (type) {
case SPICE_MSGC_INPUTS_KEY_DOWN: {
@@ -297,19 +361,19 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
if (code == 0) {
break;
}
- kbd_push_scan(inputs_channel_get_keyboard(inputs_channel), code);
+ kbd_push_scan(inputs_channel_get_keyboard(inputs), code);
}
break;
}
case SPICE_MSGC_INPUTS_KEY_SCANCODE: {
uint8_t *code = message;
for (i = 0; i < size; i++) {
- kbd_push_scan(inputs_channel_get_keyboard(inputs_channel), code[i]);
+ kbd_push_scan(inputs_channel_get_keyboard(inputs), code[i]);
}
break;
}
case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
- SpiceMouseInstance *mouse = inputs_channel_get_mouse(inputs_channel);
+ SpiceMouseInstance *mouse = inputs_channel_get_mouse(inputs);
SpiceMsgcMouseMotion *mouse_motion = message;
inputs_channel_client_on_mouse_motion(icc);
@@ -324,7 +388,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
}
case SPICE_MSGC_INPUTS_MOUSE_POSITION: {
SpiceMsgcMousePosition *pos = message;
- SpiceTabletInstance *tablet = inputs_channel_get_tablet(inputs_channel);
+ SpiceTabletInstance *tablet = inputs_channel_get_tablet(inputs);
inputs_channel_client_on_mouse_motion(icc);
if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) {
@@ -337,7 +401,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
sif->position(tablet, pos->x, pos->y, RED_MOUSE_STATE_TO_LOCAL(pos->buttons_state));
break;
}
- VDAgentMouseState *mouse_state = &inputs_channel->mouse_state;
+ VDAgentMouseState *mouse_state = &inputs->priv->mouse_state;
mouse_state->x = pos->x;
mouse_state->y = pos->y;
mouse_state->buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state);
@@ -355,20 +419,20 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
}
if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) {
if (reds_config_get_agent_mouse(reds) && reds_has_vdagent(reds)) {
- inputs_channel->mouse_state.buttons =
+ inputs->priv->mouse_state.buttons =
RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) |
(dz == -1 ? VD_AGENT_UBUTTON_MASK : 0) |
(dz == 1 ? VD_AGENT_DBUTTON_MASK : 0);
- reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
- } else if (inputs_channel_get_tablet(inputs_channel)) {
+ reds_handle_agent_mouse_event(reds, &inputs->priv->mouse_state);
+ } else if (inputs_channel_get_tablet(inputs)) {
SpiceTabletInterface *sif;
- sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif, SpiceTabletInterface, base);
- sif->wheel(inputs_channel_get_tablet(inputs_channel), dz, RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
+ sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs)->base.sif, SpiceTabletInterface, base);
+ sif->wheel(inputs_channel_get_tablet(inputs), dz, RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
}
- } else if (inputs_channel_get_mouse(inputs_channel)) {
+ } else if (inputs_channel_get_mouse(inputs)) {
SpiceMouseInterface *sif;
- sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, SpiceMouseInterface, base);
- sif->motion(inputs_channel_get_mouse(inputs_channel), 0, 0, dz,
+ sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs)->base.sif, SpiceMouseInterface, base);
+ sif->motion(inputs_channel_get_mouse(inputs), 0, 0, dz,
RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
}
break;
@@ -377,18 +441,18 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
SpiceMsgcMouseRelease *mouse_release = message;
if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) {
if (reds_config_get_agent_mouse(reds) && reds_has_vdagent(reds)) {
- inputs_channel->mouse_state.buttons =
+ inputs->priv->mouse_state.buttons =
RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state);
- reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
- } else if (inputs_channel_get_tablet(inputs_channel)) {
+ reds_handle_agent_mouse_event(reds, &inputs->priv->mouse_state);
+ } else if (inputs_channel_get_tablet(inputs)) {
SpiceTabletInterface *sif;
- sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif, SpiceTabletInterface, base);
- sif->buttons(inputs_channel_get_tablet(inputs_channel), RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
+ sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs)->base.sif, SpiceTabletInterface, base);
+ sif->buttons(inputs_channel_get_tablet(inputs), RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
}
- } else if (inputs_channel_get_mouse(inputs_channel)) {
+ } else if (inputs_channel_get_mouse(inputs)) {
SpiceMouseInterface *sif;
- sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, SpiceMouseInterface, base);
- sif->buttons(inputs_channel_get_mouse(inputs_channel),
+ sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs)->base.sif, SpiceMouseInterface, base);
+ sif->buttons(inputs_channel_get_mouse(inputs),
RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
}
break;
@@ -396,7 +460,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
case SPICE_MSGC_INPUTS_KEY_MODIFIERS: {
SpiceMsgcKeyModifiers *modifiers = message;
uint8_t leds;
- SpiceKbdInstance *keyboard = inputs_channel_get_keyboard(inputs_channel);
+ SpiceKbdInstance *keyboard = inputs_channel_get_keyboard(inputs);
if (!keyboard) {
break;
@@ -520,17 +584,17 @@ static void inputs_connect(RedChannel *channel, RedClient *client,
static void inputs_migrate(RedChannelClient *rcc)
{
InputsChannel *inputs = (InputsChannel*)red_channel_client_get_channel(rcc);
- inputs->src_during_migrate = TRUE;
+ inputs->priv->src_during_migrate = TRUE;
red_channel_client_default_migrate(rcc);
}
static void inputs_channel_push_keyboard_modifiers(InputsChannel *inputs, uint8_t modifiers)
{
- if (!inputs || !red_channel_is_connected(&inputs->base) ||
- inputs->src_during_migrate) {
+ if (!inputs || !red_channel_is_connected(RED_CHANNEL(inputs)) ||
+ inputs->priv->src_during_migrate) {
return;
}
- red_channel_pipes_new_add_push(&inputs->base,
+ red_channel_pipes_new_add_push(RED_CHANNEL(inputs),
red_inputs_key_modifiers_item_new, (void*)&modifiers);
}
@@ -574,117 +638,113 @@ static int inputs_channel_handle_migrate_data(RedChannelClient *rcc,
return TRUE;
}
-InputsChannel* inputs_channel_new(RedsState *reds)
+static void
+inputs_channel_class_init(InputsChannelClass *klass)
{
- ChannelCbs channel_cbs = { NULL, };
- ClientCbs client_cbs = { NULL, };
- InputsChannel *inputs;
-
- channel_cbs.config_socket = inputs_channel_config_socket;
- channel_cbs.on_disconnect = inputs_channel_on_disconnect;
- channel_cbs.send_item = inputs_channel_send_item;
- channel_cbs.hold_item = inputs_channel_hold_pipe_item;
- channel_cbs.release_item = inputs_channel_release_pipe_item;
- channel_cbs.alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
- channel_cbs.release_recv_buf = inputs_channel_release_msg_rcv_buf;
- channel_cbs.handle_migrate_data = inputs_channel_handle_migrate_data;
- channel_cbs.handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
-
- inputs = (InputsChannel *)red_channel_create_parser(
- sizeof(InputsChannel),
- reds,
- reds_get_core_interface(reds),
- SPICE_CHANNEL_INPUTS, 0,
- FALSE, /* handle_acks */
- spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL),
- inputs_channel_handle_parsed,
- &channel_cbs,
- SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
-
- if (!inputs) {
- spice_error("failed to allocate Inputs Channel");
- }
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
- client_cbs.connect = inputs_connect;
- client_cbs.migrate = inputs_migrate;
- red_channel_register_client_cbs(&inputs->base, &client_cbs, NULL);
+ g_type_class_add_private(klass, sizeof(InputsChannelPrivate));
- red_channel_set_cap(&inputs->base, SPICE_INPUTS_CAP_KEY_SCANCODE);
- reds_register_channel(reds, &inputs->base);
+ object_class->get_property = inputs_channel_get_property;
+ object_class->set_property = inputs_channel_set_property;
+ object_class->constructed = inputs_channel_constructed;
+
+ channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
+ channel_class->handle_parsed = inputs_channel_handle_parsed;
+
+ /* channel callbacks */
+ channel_class->config_socket = inputs_channel_config_socket;
+ channel_class->on_disconnect = inputs_channel_on_disconnect;
+ channel_class->send_item = inputs_channel_send_item;
+ channel_class->hold_item = inputs_channel_hold_pipe_item;
+ channel_class->release_item = inputs_channel_release_pipe_item;
+ channel_class->alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
+ channel_class->release_recv_buf = inputs_channel_release_msg_rcv_buf;
+ channel_class->handle_migrate_data = inputs_channel_handle_migrate_data;
+ channel_class->handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
+}
+
+InputsChannel* inputs_channel_new(RedsState *reds)
+{
+ return g_object_new(TYPE_INPUTS_CHANNEL,
+ "spice-server", reds,
+ "core-interface", reds_get_core_interface(reds),
+ "channel-type", (int)SPICE_CHANNEL_INPUTS,
+ "id", 0,
+ "handle-acks", FALSE,
+ "migration-flags", (guint)(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
+ NULL);
- if (!(key_modifiers_timer = reds_core_timer_add(reds, key_modifiers_sender, inputs))) {
- spice_error("key modifiers timer create failed");
- }
- return inputs;
}
SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel *inputs)
{
- return inputs->keyboard;
+ return inputs->priv->keyboard;
}
int inputs_channel_set_keyboard(InputsChannel *inputs, SpiceKbdInstance *keyboard)
{
- if (inputs->keyboard) {
+ if (inputs->priv->keyboard) {
spice_printerr("already have keyboard");
return -1;
}
- inputs->keyboard = keyboard;
- inputs->keyboard->st = spice_kbd_state_new(red_channel_get_server(&inputs->base));
+ inputs->priv->keyboard = keyboard;
+ inputs->priv->keyboard->st = spice_kbd_state_new(red_channel_get_server(RED_CHANNEL(inputs)));
return 0;
}
SpiceMouseInstance* inputs_channel_get_mouse(InputsChannel *inputs)
{
- return inputs->mouse;
+ return inputs->priv->mouse;
}
int inputs_channel_set_mouse(InputsChannel *inputs, SpiceMouseInstance *mouse)
{
- if (inputs->mouse) {
+ if (inputs->priv->mouse) {
spice_printerr("already have mouse");
return -1;
}
- inputs->mouse = mouse;
- inputs->mouse->st = spice_mouse_state_new();
+ inputs->priv->mouse = mouse;
+ inputs->priv->mouse->st = spice_mouse_state_new();
return 0;
}
SpiceTabletInstance* inputs_channel_get_tablet(InputsChannel *inputs)
{
- return inputs->tablet;
+ return inputs->priv->tablet;
}
int inputs_channel_set_tablet(InputsChannel *inputs, SpiceTabletInstance *tablet, RedsState *reds)
{
- if (inputs->tablet) {
+ if (inputs->priv->tablet) {
spice_printerr("already have tablet");
return -1;
}
- inputs->tablet = tablet;
- inputs->tablet->st = spice_tablet_state_new();
- inputs->tablet->st->reds = reds;
+ inputs->priv->tablet = tablet;
+ inputs->priv->tablet->st = spice_tablet_state_new();
+ inputs->priv->tablet->st->reds = reds;
return 0;
}
int inputs_channel_has_tablet(InputsChannel *inputs)
{
- return inputs != NULL && inputs->tablet != NULL;
+ return inputs != NULL && inputs->priv->tablet != NULL;
}
void inputs_channel_detach_tablet(InputsChannel *inputs, SpiceTabletInstance *tablet)
{
spice_printerr("");
- inputs->tablet = NULL;
+ inputs->priv->tablet = NULL;
}
gboolean inputs_channel_is_src_during_migrate(InputsChannel *inputs)
{
- return inputs->src_during_migrate;
+ return inputs->priv->src_during_migrate;
}
void inputs_channel_set_src_during_migrate(InputsChannel *inputs,
gboolean value)
{
- inputs->src_during_migrate = value;
+ inputs->priv->src_during_migrate = value;
}
diff --git a/server/inputs-channel.h b/server/inputs-channel.h
index 5317578..1dbb3a2 100644
--- a/server/inputs-channel.h
+++ b/server/inputs-channel.h
@@ -21,14 +21,42 @@
// Inputs channel, dealing with keyboard, mouse, tablet.
// This include should only be used by reds.c and inputs-channel.c
+#include <glib-object.h>
#include <stdint.h>
#include <spice/vd_agent.h>
#include "red-channel.h"
+G_BEGIN_DECLS
+
+#define TYPE_INPUTS_CHANNEL inputs_channel_get_type()
+
+#define INPUTS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_INPUTS_CHANNEL, InputsChannel))
+#define INPUTS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_INPUTS_CHANNEL, InputsChannelClass))
+#define INPUTS_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_INPUTS_CHANNEL))
+#define INPUTS_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_INPUTS_CHANNEL))
+#define INPUTS_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_INPUTS_CHANNEL, InputsChannelClass))
+
typedef struct InputsChannel InputsChannel;
+typedef struct InputsChannelClass InputsChannelClass;
+typedef struct InputsChannelPrivate InputsChannelPrivate;
+
+struct InputsChannel
+{
+ RedChannel parent;
+
+ InputsChannelPrivate *priv;
+};
+
+struct InputsChannelClass
+{
+ RedChannelClass parent_class;
+};
+
+GType inputs_channel_get_type(void) G_GNUC_CONST;
InputsChannel* inputs_channel_new(RedsState *reds);
+
VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs);
void inputs_channel_on_keyboard_leds_change(InputsChannel *inputs, uint8_t leds);
void inputs_channel_set_tablet_logical_size(InputsChannel *inputs, int x_res, int y_res);
@@ -53,4 +81,6 @@ enum {
RED_PIPE_ITEM_MIGRATE_DATA,
};
+G_END_DECLS
+
#endif
diff --git a/server/main-channel-client.c b/server/main-channel-client.c
index 82cb5c3..f18be1c 100644
--- a/server/main-channel-client.c
+++ b/server/main-channel-client.c
@@ -101,16 +101,6 @@ static void main_channel_client_set_property(GObject *object,
}
}
-static void main_channel_client_dispose(GObject *object)
-{
- G_OBJECT_CLASS(main_channel_client_parent_class)->dispose(object);
-}
-
-static void main_channel_client_finalize(GObject *object)
-{
- G_OBJECT_CLASS(main_channel_client_parent_class)->finalize(object);
-}
-
static void ping_timer_cb(void *opaque);
static void main_channel_client_constructed(GObject *object)
{
@@ -135,8 +125,6 @@ static void main_channel_client_class_init(MainChannelClientClass *klass)
object_class->get_property = main_channel_client_get_property;
object_class->set_property = main_channel_client_set_property;
- object_class->dispose = main_channel_client_dispose;
- object_class->finalize = main_channel_client_finalize;
object_class->constructed = main_channel_client_constructed;
g_object_class_install_property(object_class,
@@ -341,15 +329,11 @@ void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
spice_printerr("client %p connected: %d seamless %d",
client, success, seamless);
if (mcc->priv->mig_wait_connect) {
- MainChannel *main_channel = SPICE_CONTAINEROF(channel, MainChannel, base);
+ MainChannel *main_channel = MAIN_CHANNEL(channel);
mcc->priv->mig_wait_connect = FALSE;
mcc->priv->mig_connect_ok = success;
- spice_assert(main_channel->num_clients_mig_wait);
- spice_assert(!seamless || main_channel->num_clients_mig_wait == 1);
- if (!--main_channel->num_clients_mig_wait) {
- reds_on_main_migrate_connected(channel->reds, seamless && success);
- }
+ main_channel_on_migrate_connected(main_channel, seamless && success);
} else {
if (success) {
spice_printerr("client %p MIGRATE_CANCEL", client);
@@ -362,7 +346,7 @@ void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
uint32_t src_version)
{
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
- if (reds_on_migrate_dst_set_seamless(channel->reds, mcc, src_version)) {
+ if (reds_on_migrate_dst_set_seamless(red_channel_get_server(channel), mcc, src_version)) {
mcc->priv->seamless_mig_dst = TRUE;
red_channel_client_pipe_add_empty_msg(RED_CHANNEL_CLIENT(mcc),
SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
@@ -429,7 +413,10 @@ void main_channel_client_handle_pong(MainChannelClient *mcc, SpiceMsgPing *ping,
red_channel_client_handle_message(rcc, size, SPICE_MSGC_PONG, ping);
}
#ifdef RED_STATISTICS
- stat_update_value(red_channel_client_get_channel(rcc)->reds, roundtrip);
+ {
+ RedChannel *channel = red_channel_client_get_channel(rcc);
+ stat_update_value(red_channel_get_server(channel), roundtrip);
+ }
#endif
}
@@ -470,7 +457,7 @@ void main_channel_client_migrate_dst_complete(MainChannelClient *mcc)
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
if (mcc->priv->mig_wait_prev_complete) {
if (mcc->priv->mig_wait_prev_try_seamless) {
- spice_assert(channel->clients_num == 1);
+ spice_assert(red_channel_get_n_clients(channel) == 1);
red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(mcc),
RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS);
} else {
@@ -528,9 +515,11 @@ static void do_ping_client(MainChannelClient *mcc,
if (has_interval && interval > 0) {
mcc->priv->ping_interval = interval * MSEC_PER_SEC;
}
- reds_core_timer_start(channel->reds, mcc->priv->ping_timer, mcc->priv->ping_interval);
+ reds_core_timer_start(red_channel_get_server(channel),
+ mcc->priv->ping_timer, mcc->priv->ping_interval);
} else if (!strcmp(opt, "off")) {
- reds_core_timer_cancel(channel->reds, mcc->priv->ping_timer);
+ reds_core_timer_cancel(red_channel_get_server(channel),
+ mcc->priv->ping_timer);
} else {
return;
}
@@ -543,11 +532,13 @@ static void ping_timer_cb(void *opaque)
if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(mcc))) {
spice_printerr("not connected to peer, ping off");
- reds_core_timer_cancel(channel->reds, mcc->priv->ping_timer);
+ reds_core_timer_cancel(red_channel_get_server(channel),
+ mcc->priv->ping_timer);
return;
}
do_ping_client(mcc, NULL, 0, 0);
- reds_core_timer_start(channel->reds, mcc->priv->ping_timer, mcc->priv->ping_interval);
+ reds_core_timer_start(red_channel_get_server(channel),
+ mcc->priv->ping_timer, mcc->priv->ping_interval);
}
#endif /* RED_STATISTICS */
@@ -611,15 +602,14 @@ uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc)
void main_channel_client_migrate(RedChannelClient *rcc)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
- reds_on_main_channel_migrate(channel->reds, MAIN_CHANNEL_CLIENT(rcc));
+ reds_on_main_channel_migrate(red_channel_get_server(channel),
+ MAIN_CHANNEL_CLIENT(rcc));
red_channel_client_default_migrate(rcc);
}
gboolean main_channel_client_connect_semi_seamless(MainChannelClient *mcc)
{
RedChannelClient *rcc = RED_CHANNEL_CLIENT(mcc);
- MainChannel* main_channel = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
- MainChannel, base);
if (red_channel_client_test_remote_cap(rcc,
SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) {
RedClient *client = red_channel_client_get_client(rcc);
@@ -633,7 +623,6 @@ gboolean main_channel_client_connect_semi_seamless(MainChannelClient *mcc)
mcc->priv->mig_wait_connect = TRUE;
}
mcc->priv->mig_connect_ok = FALSE;
- main_channel->num_clients_mig_wait++;
return TRUE;
}
return FALSE;
diff --git a/server/main-channel-client.h b/server/main-channel-client.h
index 5d284ad..50713ea 100644
--- a/server/main-channel-client.h
+++ b/server/main-channel-client.h
@@ -23,8 +23,6 @@
G_BEGIN_DECLS
-typedef struct MainChannel MainChannel;
-
#define TYPE_MAIN_CHANNEL_CLIENT main_channel_client_get_type()
#define MAIN_CHANNEL_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_MAIN_CHANNEL_CLIENT, MainChannelClient))
@@ -49,6 +47,8 @@ struct MainChannelClientClass
RedChannelClientClass parent_class;
};
+typedef struct MainChannel MainChannel;
+
GType main_channel_client_get_type(void) G_GNUC_CONST;
MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client,
diff --git a/server/main-channel.c b/server/main-channel.c
index e3d6c57..554c20d 100644
--- a/server/main-channel.c
+++ b/server/main-channel.c
@@ -50,15 +50,51 @@
#include "utils.h"
#define ZERO_BUF_SIZE 4096
+// approximate max receive message size for main channel
+#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
+ (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
static const uint8_t zero_page[ZERO_BUF_SIZE] = {0};
+
+G_DEFINE_TYPE(MainChannel, main_channel, RED_TYPE_CHANNEL)
+
+#define MAIN_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_MAIN_CHANNEL, MainChannelPrivate))
+
+struct MainChannelPrivate
+{
+ uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
+ RedsMigSpice mig_target; // TODO: add refs and release (afrer all clients completed migration in one way or the other?)
+ int num_clients_mig_wait;
+};
+
+static void
+main_channel_constructed(GObject *object)
+{
+ MainChannel *self = MAIN_CHANNEL(object);
+ ClientCbs client_cbs = { NULL, };
+
+ G_OBJECT_CLASS(main_channel_parent_class)->constructed(object);
+
+ red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
+ red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
+
+ client_cbs.migrate = main_channel_client_migrate;
+ red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
+}
+
+static void
+main_channel_init(MainChannel *self)
+{
+ self->priv = MAIN_CHANNEL_PRIVATE(self);
+}
+
static void main_channel_release_pipe_item(RedChannelClient *rcc,
RedPipeItem *base, int item_pushed);
int main_channel_is_connected(MainChannel *main_chan)
{
- return red_channel_is_connected(&main_chan->base);
+ return red_channel_is_connected(RED_CHANNEL(main_chan));
}
/*
@@ -78,7 +114,7 @@ RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t c
MainChannelClient *mcc;
RedChannelClient *rcc;
- for (link = main_chan->base.clients; link != NULL; link = link->next) {
+ for (link = red_channel_get_clients(RED_CHANNEL(main_chan)); link != NULL; link = link->next) {
rcc = link->data;
mcc = MAIN_CHANNEL_CLIENT(rcc);
if (main_channel_client_get_connection_id(mcc) == connection_id) {
@@ -134,7 +170,7 @@ static void main_channel_marshall_channels(RedChannelClient *rcc,
RedChannel *channel = red_channel_client_get_channel(rcc);
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item);
- channels_info = reds_msg_channels_new(channel->reds);
+ channels_info = reds_msg_channels_new(red_channel_get_server(channel));
spice_marshall_msg_main_channels_list(m, channels_info);
free(channels_info);
}
@@ -167,7 +203,7 @@ void main_channel_push_mouse_mode(MainChannel *main_chan, int current_mode,
.is_client_mouse_allowed=is_client_mouse_allowed,
};
- red_channel_pipes_new_add_push(&main_chan->base,
+ red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
main_mouse_mode_item_new, &info);
}
@@ -188,10 +224,10 @@ static void main_channel_marshall_mouse_mode(RedChannelClient *rcc,
void main_channel_push_agent_connected(MainChannel *main_chan)
{
- if (red_channel_test_remote_cap(&main_chan->base, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
- red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
+ if (red_channel_test_remote_cap(RED_CHANNEL(main_chan), SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
+ red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
} else {
- red_channel_pipes_add_empty_msg(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
+ red_channel_pipes_add_empty_msg(RED_CHANNEL(main_chan), SPICE_MSG_MAIN_AGENT_CONNECTED);
}
}
@@ -208,7 +244,7 @@ static void main_channel_marshall_agent_connected(SpiceMarshaller *m,
void main_channel_push_agent_disconnected(MainChannel *main_chan)
{
- red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
+ red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
}
static void main_channel_marshall_agent_disconnected(RedChannelClient *rcc,
@@ -242,7 +278,7 @@ static void main_channel_marshall_agent_data(RedChannelClient *rcc,
static void main_channel_push_migrate_data_item(MainChannel *main_chan)
{
- red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
+ red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
}
static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
@@ -251,7 +287,7 @@ static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
{
RedChannel *channel = red_channel_client_get_channel(rcc);
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
- reds_marshall_migrate_data(channel->reds, m); // TODO: from reds split. ugly separation.
+ reds_marshall_migrate_data(red_channel_get_server(channel), m); // TODO: from reds split. ugly separation.
}
static int main_channel_handle_migrate_data(RedChannelClient *rcc,
@@ -262,7 +298,7 @@ static int main_channel_handle_migrate_data(RedChannelClient *rcc,
SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message;
/* not supported with multi-clients */
- spice_assert(channel->clients_num == 1);
+ spice_assert(red_channel_get_n_clients(channel) == 1);
if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataMain)) {
spice_printerr("bad message size %u", size);
@@ -274,7 +310,9 @@ static int main_channel_handle_migrate_data(RedChannelClient *rcc,
spice_error("bad header");
return FALSE;
}
- return reds_handle_migrate_data(channel->reds, mcc, (SpiceMigrateDataMain *)(header + 1), size);
+ return reds_handle_migrate_data(red_channel_get_server(channel), mcc,
+ (SpiceMigrateDataMain *)(header + 1),
+ size);
}
static void main_channel_marshall_init(RedChannelClient *rcc,
@@ -292,7 +330,7 @@ static void main_channel_marshall_init(RedChannelClient *rcc,
if (item->is_client_mouse_allowed) {
init.supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
}
- init.agent_connected = reds_has_vdagent(channel->reds);
+ init.agent_connected = reds_has_vdagent(red_channel_get_server(channel));
init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
init.multi_media_time = item->multi_media_time;
init.ram_hint = item->ram_hint;
@@ -317,7 +355,7 @@ static void main_channel_marshall_notify(RedChannelClient *rcc,
static void main_channel_fill_migrate_dst_info(MainChannel *main_channel,
SpiceMigrationDstInfo *dst_info)
{
- RedsMigSpice *mig_dst = &main_channel->mig_target;
+ RedsMigSpice *mig_dst = &main_channel->priv->mig_target;
dst_info->port = mig_dst->port;
dst_info->sport = mig_dst->sport;
dst_info->host_size = strlen(mig_dst->host) + 1;
@@ -336,11 +374,9 @@ static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelCl
{
RedChannel *channel = red_channel_client_get_channel(rcc);
SpiceMsgMainMigrationBegin migrate;
- MainChannel *main_ch;
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN, item);
- main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
- main_channel_fill_migrate_dst_info(main_ch, &migrate.dst_info);
+ main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel), &migrate.dst_info);
spice_marshall_msg_main_migrate_begin(m, &migrate);
}
@@ -350,11 +386,9 @@ static void main_channel_marshall_migrate_begin_seamless(SpiceMarshaller *m,
{
RedChannel *channel = red_channel_client_get_channel(rcc);
SpiceMsgMainMigrateBeginSeamless migrate_seamless;
- MainChannel *main_ch;
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS, item);
- main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
- main_channel_fill_migrate_dst_info(main_ch, &migrate_seamless.dst_info);
+ main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel), &migrate_seamless.dst_info);
migrate_seamless.src_mig_version = SPICE_MIGRATION_PROTOCOL_VERSION;
spice_marshall_msg_main_migrate_begin_seamless(m, &migrate_seamless);
}
@@ -365,29 +399,29 @@ void main_channel_push_multi_media_time(MainChannel *main_chan, int time)
.time = time,
};
- red_channel_pipes_new_add_push(&main_chan->base,
+ red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
main_multi_media_time_item_new, &info);
}
static void main_channel_fill_mig_target(MainChannel *main_channel, RedsMigSpice *mig_target)
{
spice_assert(mig_target);
- free(main_channel->mig_target.host);
- main_channel->mig_target.host = spice_strdup(mig_target->host);
- free(main_channel->mig_target.cert_subject);
+ free(main_channel->priv->mig_target.host);
+ main_channel->priv->mig_target.host = spice_strdup(mig_target->host);
+ free(main_channel->priv->mig_target.cert_subject);
if (mig_target->cert_subject) {
- main_channel->mig_target.cert_subject = spice_strdup(mig_target->cert_subject);
+ main_channel->priv->mig_target.cert_subject = spice_strdup(mig_target->cert_subject);
} else {
- main_channel->mig_target.cert_subject = NULL;
+ main_channel->priv->mig_target.cert_subject = NULL;
}
- main_channel->mig_target.port = mig_target->port;
- main_channel->mig_target.sport = mig_target->sport;
+ main_channel->priv->mig_target.port = mig_target->port;
+ main_channel->priv->mig_target.sport = mig_target->sport;
}
void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_target)
{
main_channel_fill_mig_target(main_chan, mig_target);
- red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
+ red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
}
static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelClient *rcc,
@@ -395,18 +429,18 @@ static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelC
{
RedChannel *channel = red_channel_client_get_channel(rcc);
SpiceMsgMainMigrationSwitchHost migrate;
- MainChannel *main_ch;
+ MainChannel *main_chan;
spice_printerr("");
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item);
- main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
- migrate.port = main_ch->mig_target.port;
- migrate.sport = main_ch->mig_target.sport;
- migrate.host_size = strlen(main_ch->mig_target.host) + 1;
- migrate.host_data = (uint8_t *)main_ch->mig_target.host;
- if (main_ch->mig_target.cert_subject) {
- migrate.cert_subject_size = strlen(main_ch->mig_target.cert_subject) + 1;
- migrate.cert_subject_data = (uint8_t *)main_ch->mig_target.cert_subject;
+ main_chan = MAIN_CHANNEL(channel);
+ migrate.port = main_chan->priv->mig_target.port;
+ migrate.sport = main_chan->priv->mig_target.sport;
+ migrate.host_size = strlen(main_chan->priv->mig_target.host) + 1;
+ migrate.host_data = (uint8_t *)main_chan->priv->mig_target.host;
+ if (main_chan->priv->mig_target.cert_subject) {
+ migrate.cert_subject_size = strlen(main_chan->priv->mig_target.cert_subject) + 1;
+ migrate.cert_subject_data = (uint8_t *)main_chan->priv->mig_target.cert_subject;
} else {
migrate.cert_subject_size = 0;
migrate.cert_subject_data = NULL;
@@ -536,8 +570,9 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
void *message)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
- MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
+ MainChannel *main_chan = MAIN_CHANNEL(channel);
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
+ RedsState *reds = red_channel_get_server(channel);
switch (type) {
case SPICE_MSGC_MAIN_AGENT_START: {
@@ -548,18 +583,18 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
return FALSE;
}
tokens = (SpiceMsgcMainAgentStart *)message;
- reds_on_main_agent_start(channel->reds, mcc, tokens->num_tokens);
+ reds_on_main_agent_start(reds, mcc, tokens->num_tokens);
break;
}
case SPICE_MSGC_MAIN_AGENT_DATA: {
- reds_on_main_agent_data(channel->reds, mcc, message, size);
+ reds_on_main_agent_data(reds, mcc, message, size);
break;
}
case SPICE_MSGC_MAIN_AGENT_TOKEN: {
SpiceMsgcMainAgentTokens *tokens;
tokens = (SpiceMsgcMainAgentTokens *)message;
- reds_on_main_agent_tokens(channel->reds, mcc, tokens->num_tokens);
+ reds_on_main_agent_tokens(reds, mcc, tokens->num_tokens);
break;
}
case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
@@ -583,7 +618,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
((SpiceMsgcMainMigrateDstDoSeamless *)message)->src_version);
break;
case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
- reds_on_main_mouse_mode_request(channel->reds, message, size);
+ reds_on_main_mouse_mode_request(reds, message, size);
break;
case SPICE_MSGC_PONG: {
main_channel_client_handle_pong(mcc, (SpiceMsgPing *)message, size);
@@ -605,13 +640,13 @@ static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
uint32_t size)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
- MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
+ MainChannel *main_chan = MAIN_CHANNEL(channel);
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
- return reds_get_agent_data_buffer(channel->reds, mcc, size);
+ return reds_get_agent_data_buffer(red_channel_get_server(channel), mcc, size);
} else {
- return main_chan->recv_buf;
+ return main_chan->priv->recv_buf;
}
}
@@ -622,7 +657,7 @@ static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc,
{
RedChannel *channel = red_channel_client_get_channel(rcc);
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
- reds_release_agent_data_buffer(channel->reds, msg);
+ reds_release_agent_data_buffer(red_channel_get_server(channel), msg);
}
}
@@ -639,8 +674,7 @@ static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
spice_debug(NULL);
- main_channel_push_migrate_data_item(SPICE_CONTAINEROF(channel,
- MainChannel, base));
+ main_channel_push_migrate_data_item(MAIN_CHANNEL(channel));
return TRUE;
}
@@ -665,12 +699,12 @@ MainChannelClient *main_channel_link(MainChannel *channel, RedClient *client,
int main_channel_getsockname(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
{
- return main_chan ? getsockname(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
+ return main_chan ? getsockname(red_channel_get_first_socket(RED_CHANNEL(main_chan)), sa, salen) : -1;
}
int main_channel_getpeername(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
{
- return main_chan ? getpeername(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
+ return main_chan ? getpeername(red_channel_get_first_socket(RED_CHANNEL(main_chan)), sa, salen) : -1;
}
// TODO: ? shouldn't it disonnect all clients? or shutdown all main_channels?
@@ -678,79 +712,57 @@ void main_channel_close(MainChannel *main_chan)
{
int socketfd;
- if (main_chan && (socketfd = red_channel_get_first_socket(&main_chan->base)) != -1) {
+ if (main_chan && (socketfd = red_channel_get_first_socket(RED_CHANNEL(main_chan))) != -1) {
close(socketfd);
}
}
MainChannel* main_channel_new(RedsState *reds)
{
- RedChannel *channel;
- ChannelCbs channel_cbs = { NULL, };
- ClientCbs client_cbs = {NULL, };
-
- channel_cbs.config_socket = main_channel_config_socket;
- channel_cbs.on_disconnect = main_channel_client_on_disconnect;
- channel_cbs.send_item = main_channel_send_item;
- channel_cbs.hold_item = main_channel_hold_pipe_item;
- channel_cbs.release_item = main_channel_release_pipe_item;
- channel_cbs.alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
- channel_cbs.release_recv_buf = main_channel_release_msg_rcv_buf;
- channel_cbs.handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
- channel_cbs.handle_migrate_data = main_channel_handle_migrate_data;
-
// TODO: set the migration flag of the channel
- channel = red_channel_create_parser(sizeof(MainChannel), reds,
- reds_get_core_interface(reds),
- SPICE_CHANNEL_MAIN, 0,
- FALSE, /* handle_acks */
- spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL),
- main_channel_handle_parsed,
- &channel_cbs,
- SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
- spice_assert(channel);
- red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
- red_channel_set_cap(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
-
- client_cbs.migrate = main_channel_client_migrate;
- red_channel_register_client_cbs(channel, &client_cbs, NULL);
-
- return (MainChannel *)channel;
+ return g_object_new(TYPE_MAIN_CHANNEL,
+ "spice-server", reds,
+ "core-interface", reds_get_core_interface(reds),
+ "channel-type", (gint)SPICE_CHANNEL_MAIN,
+ "id", 0,
+ "handle-acks", FALSE, /* handle_acks */
+ "migration-flags", (SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
+ NULL);
}
static int main_channel_connect_semi_seamless(MainChannel *main_channel)
{
GList *link;
- for (link = main_channel->base.clients; link != NULL; link = link->next) {
+ for (link = red_channel_get_clients(RED_CHANNEL(main_channel)); link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
if (main_channel_client_connect_semi_seamless(mcc))
- main_channel->num_clients_mig_wait++;
+ main_channel->priv->num_clients_mig_wait++;
}
- return main_channel->num_clients_mig_wait;
+ return main_channel->priv->num_clients_mig_wait;
}
static int main_channel_connect_seamless(MainChannel *main_channel)
{
GList *link;
- spice_assert(g_list_length(main_channel->base.clients) == 1);
+ spice_assert(red_channel_get_n_clients(RED_CHANNEL(main_channel)) == 1);
- for (link = main_channel->base.clients; link != NULL; link = link->next) {
+ for (link = red_channel_get_clients(RED_CHANNEL(main_channel)); link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
main_channel_client_connect_seamless(mcc);
- main_channel->num_clients_mig_wait++;
+ main_channel->priv->num_clients_mig_wait++;
}
- return main_channel->num_clients_mig_wait;
+ return main_channel->priv->num_clients_mig_wait;
}
int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_target,
int try_seamless)
{
main_channel_fill_mig_target(main_channel, mig_target);
- main_channel->num_clients_mig_wait = 0;
+ main_channel->priv->num_clients_mig_wait = 0;
if (!main_channel_is_connected(main_channel)) {
return 0;
@@ -760,8 +772,10 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
return main_channel_connect_semi_seamless(main_channel);
} else {
RedChannelClient *rcc;
+ GList *clients = red_channel_get_clients(RED_CHANNEL(main_channel));
- rcc = main_channel->base.clients->data;
+ /* just test the first one */
+ rcc = clients->data;
if (!red_channel_client_test_remote_cap(rcc,
SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
@@ -777,27 +791,28 @@ void main_channel_migrate_cancel_wait(MainChannel *main_chan)
{
GList *link;
- for (link = main_chan->base.clients; link != NULL; link = link->next) {
+ for (link = red_channel_get_clients(RED_CHANNEL(main_chan)); link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
main_channel_client_migrate_cancel_wait(mcc);
}
- main_chan->num_clients_mig_wait = 0;
+ main_chan->priv->num_clients_mig_wait = 0;
}
int main_channel_migrate_src_complete(MainChannel *main_chan, int success)
{
GList *link;
+ GList *clients = red_channel_get_clients(RED_CHANNEL(main_chan));
int semi_seamless_count = 0;
spice_printerr("");
- if (!main_chan->base.clients) {
+ if (!clients) {
spice_printerr("no peer connected");
return 0;
}
- for (link = main_chan->base.clients; link != NULL; link = link->next) {
+ for (link = clients; link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
if (main_channel_client_migrate_src_complete(mcc, success))
@@ -805,3 +820,39 @@ int main_channel_migrate_src_complete(MainChannel *main_chan, int success)
}
return semi_seamless_count;
}
+
+void main_channel_on_migrate_connected(MainChannel *main_channel, gboolean seamless)
+{
+ g_return_if_fail(main_channel->priv->num_clients_mig_wait);
+ g_warn_if_fail(!seamless || main_channel->priv->num_clients_mig_wait == 1);
+ if (!--main_channel->priv->num_clients_mig_wait) {
+ reds_on_main_migrate_connected(red_channel_get_server(RED_CHANNEL(main_channel)),
+ seamless);
+ }
+}
+
+static void
+main_channel_class_init(MainChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(MainChannelPrivate));
+
+ object_class->constructed = main_channel_constructed;
+
+ channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
+ channel_class->handle_parsed = main_channel_handle_parsed;
+
+ /* channel callbacks */
+ channel_class->config_socket = main_channel_config_socket;
+ channel_class->on_disconnect = main_channel_client_on_disconnect;
+ channel_class->send_item = main_channel_send_item;
+ channel_class->hold_item = main_channel_hold_pipe_item;
+ channel_class->release_item = main_channel_release_pipe_item;
+ channel_class->alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
+ channel_class->release_recv_buf = main_channel_release_msg_rcv_buf;
+ channel_class->handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
+ channel_class->handle_migrate_data = main_channel_handle_migrate_data;
+}
+
diff --git a/server/main-channel.h b/server/main-channel.h
index 43a2679..ce67241 100644
--- a/server/main-channel.h
+++ b/server/main-channel.h
@@ -18,21 +18,47 @@
#ifndef __MAIN_CHANNEL_H__
#define __MAIN_CHANNEL_H__
+#include <glib-object.h>
#include <stdint.h>
#include <spice/vd_agent.h>
+
#include "common/marshaller.h"
#include "red-channel.h"
#include "main-channel-client.h"
+G_BEGIN_DECLS
+
+#define TYPE_MAIN_CHANNEL main_channel_get_type()
+
+#define MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_MAIN_CHANNEL, MainChannel))
+#define MAIN_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_MAIN_CHANNEL, MainChannelClass))
+#define IS_MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_MAIN_CHANNEL))
+#define IS_MAIN_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_MAIN_CHANNEL))
+#define MAIN_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_MAIN_CHANNEL, MainChannelClass))
+
+typedef struct MainChannel MainChannel;
+typedef struct MainChannelClass MainChannelClass;
+typedef struct MainChannelPrivate MainChannelPrivate;
+
+struct MainChannel
+{
+ RedChannel parent;
+
+ MainChannelPrivate *priv;
+};
+
+struct MainChannelClass
+{
+ RedChannelClass parent_class;
+};
+
+GType main_channel_get_type(void) G_GNUC_CONST;
+
// TODO: Defines used to calculate receive buffer size, and also by reds.c
// other options: is to make a reds_main_consts.h, to duplicate defines.
#define REDS_AGENT_WINDOW_SIZE 10
#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
-// approximate max receive message size for main channel
-#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
- (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
-
struct RedsMigSpice {
char *host;
char *cert_subject;
@@ -41,13 +67,6 @@ struct RedsMigSpice {
};
typedef struct RedsMigSpice RedsMigSpice;
-typedef struct MainChannel {
- RedChannel base;
- uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
- RedsMigSpice mig_target; // TODO: add refs and release (afrer all clients completed migration in one way or the other?)
- int num_clients_mig_wait;
-} MainChannel;
-
MainChannel *main_channel_new(RedsState *reds);
RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t link_id);
@@ -77,5 +96,8 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
void main_channel_migrate_cancel_wait(MainChannel *main_chan);
/* returns the number of clients for which SPICE_MSG_MAIN_MIGRATE_END was sent*/
int main_channel_migrate_src_complete(MainChannel *main_chan, int success);
+void main_channel_on_migrate_connected(MainChannel *main_channel, gboolean seamless);
+
+G_END_DECLS
#endif
diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index c7009fe..7fe54d0 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -21,6 +21,25 @@
#include "red-channel-client.h"
#include "red-channel.h"
+typedef struct RedChannelClientLatencyMonitor {
+ int state;
+ uint64_t last_pong_time;
+ SpiceTimer *timer;
+ uint32_t id;
+ int tcp_nodelay;
+ int warmup_was_sent;
+
+ int64_t roundtrip;
+} RedChannelClientLatencyMonitor;
+
+typedef struct RedChannelClientConnectivityMonitor {
+ int state;
+ uint32_t out_bytes;
+ uint32_t in_bytes;
+ uint32_t timeout;
+ SpiceTimer *timer;
+} RedChannelClientConnectivityMonitor;
+
struct RedChannelClientPrivate {
RedChannel *channel;
RedClient *client;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 1c0339b..5e937b6 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -158,6 +158,8 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMini
static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t timeout)
{
+ SpiceCoreInterfaceInternal *core;
+
if (!rcc->priv->latency_monitor.timer) {
return;
}
@@ -165,11 +167,15 @@ static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t
return;
}
rcc->priv->latency_monitor.state = PING_STATE_TIMER;
- rcc->priv->channel->core->timer_start(rcc->priv->latency_monitor.timer, timeout);
+
+ core = red_channel_get_core_interface(rcc->priv->channel);
+ core->timer_start(rcc->priv->latency_monitor.timer, timeout);
}
static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
{
+ SpiceCoreInterfaceInternal *core;
+
if (!rcc->priv->latency_monitor.timer) {
return;
}
@@ -177,7 +183,8 @@ static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
return;
}
- rcc->priv->channel->core->timer_cancel(rcc->priv->latency_monitor.timer);
+ core = red_channel_get_core_interface(rcc->priv->channel);
+ core->timer_cancel(rcc->priv->latency_monitor.timer);
rcc->priv->latency_monitor.state = PING_STATE_NONE;
}
@@ -252,10 +259,10 @@ red_channel_client_set_property(GObject *object,
break;
case PROP_CHANNEL:
if (self->priv->channel)
- red_channel_unref(self->priv->channel);
+ g_object_unref(self->priv->channel);
self->priv->channel = g_value_get_pointer(value);
if (self->priv->channel)
- red_channel_ref(self->priv->channel);
+ g_object_ref(self->priv->channel);
break;
case PROP_CLIENT:
self->priv->client = g_value_get_pointer(value);
@@ -312,7 +319,7 @@ red_channel_client_finalize(GObject *object)
red_channel_client_destroy_remote_caps(self);
if (self->priv->channel) {
- red_channel_unref(self->priv->channel);
+ g_object_unref(self->priv->channel);
}
G_OBJECT_CLASS(red_channel_client_parent_class)->finalize(object);
@@ -438,7 +445,6 @@ void red_channel_client_on_output(void *opaque, int n)
if (rcc->priv->connectivity_monitor.timer) {
rcc->priv->connectivity_monitor.out_bytes += n;
}
- stat_inc_counter(reds, rcc->priv->channel->out_bytes_counter, n);
}
void red_channel_client_on_input(void *opaque, int n)
@@ -468,12 +474,14 @@ void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
void red_channel_client_on_out_block(void *opaque)
{
+ SpiceCoreInterfaceInternal *core;
RedChannelClient *rcc = (RedChannelClient *)opaque;
rcc->priv->send_data.blocked = TRUE;
- rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
- SPICE_WATCH_EVENT_READ |
- SPICE_WATCH_EVENT_WRITE);
+ core = red_channel_get_core_interface(rcc->priv->channel);
+ core->watch_update_mask(rcc->priv->stream->watch,
+ SPICE_WATCH_EVENT_READ |
+ SPICE_WATCH_EVENT_WRITE);
}
static inline int red_channel_client_urgent_marshaller_is_active(RedChannelClient *rcc)
@@ -533,9 +541,9 @@ static void red_channel_client_send_migrate(RedChannelClient *rcc)
SpiceMsgMigrate migrate;
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
- migrate.flags = rcc->priv->channel->migration_flags;
+ g_object_get(rcc->priv->channel, "migration-flags", &migrate.flags, NULL);
spice_marshall_msg_migrate(rcc->priv->send_data.marshaller, &migrate);
- if (rcc->priv->channel->migration_flags & SPICE_MIGRATE_NEED_FLUSH) {
+ if (migrate.flags & SPICE_MIGRATE_NEED_FLUSH) {
rcc->priv->wait_migrate_flush_mark = TRUE;
}
@@ -607,7 +615,7 @@ static void red_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *ite
red_channel_client_send_ping(rcc);
break;
default:
- rcc->priv->channel->channel_cbs.send_item(rcc, item);
+ red_channel_send_item(rcc->priv->channel, rcc, item);
return;
}
free(item);
@@ -625,7 +633,7 @@ static void red_channel_client_release_item(RedChannelClient *rcc,
free(item);
break;
default:
- rcc->priv->channel->channel_cbs.release_item(rcc, item, item_pushed);
+ red_channel_release_item(rcc->priv->channel, rcc, item, item_pushed);
}
}
@@ -670,9 +678,10 @@ void red_channel_client_on_out_msg_done(void *opaque)
red_channel_client_release_sent_item(rcc);
if (rcc->priv->send_data.blocked) {
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
rcc->priv->send_data.blocked = FALSE;
- rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
- SPICE_WATCH_EVENT_READ);
+ core->watch_update_mask(rcc->priv->stream->watch,
+ SPICE_WATCH_EVENT_READ);
}
if (red_channel_client_urgent_marshaller_is_active(rcc)) {
@@ -750,8 +759,13 @@ static void red_channel_client_ping_timer(void *opaque)
static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
{
- return (rcc->priv->channel->handle_acks &&
- (rcc->priv->ack_data.messages_window > rcc->priv->ack_data.client_window * 2));
+ gboolean handle_acks;
+ g_object_get(rcc->priv->channel,
+ "handle-acks", &handle_acks,
+ NULL);
+
+ return (handle_acks && (rcc->priv->ack_data.messages_window >
+ rcc->priv->ack_data.client_window * 2));
}
/*
@@ -792,6 +806,7 @@ static void red_channel_client_connectivity_timer(void *opaque)
}
if (is_alive) {
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
monitor->in_bytes = 0;
monitor->out_bytes = 0;
if (rcc->priv->send_data.blocked || red_channel_client_waiting_for_ack(rcc)) {
@@ -802,18 +817,24 @@ static void red_channel_client_connectivity_timer(void *opaque)
} else {
monitor->state = CONNECTIVITY_STATE_CONNECTED;
}
- rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
+ core->timer_start(rcc->priv->connectivity_monitor.timer,
rcc->priv->connectivity_monitor.timeout);
} else {
+ uint32_t type, id;
+ g_object_get(rcc->priv->channel,
+ "channel-type", &type,
+ "id", &id,
+ NULL);
monitor->state = CONNECTIVITY_STATE_DISCONNECTED;
spice_warning("rcc %p on channel %d:%d has been unresponsive for more than %u ms, disconnecting",
- rcc, rcc->priv->channel->type, rcc->priv->channel->id, monitor->timeout);
+ rcc, type, id, monitor->timeout);
red_channel_client_disconnect(rcc);
}
}
void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms)
{
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
if (!red_channel_client_is_connected(rcc)) {
return;
}
@@ -826,8 +847,8 @@ void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
* on this channel.
*/
if (rcc->priv->latency_monitor.timer == NULL) {
- rcc->priv->latency_monitor.timer = rcc->priv->channel->core->timer_add(
- rcc->priv->channel->core, red_channel_client_ping_timer, rcc);
+ rcc->priv->latency_monitor.timer = core->timer_add(
+ core, red_channel_client_ping_timer, rcc);
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
}
@@ -835,12 +856,12 @@ void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
}
if (rcc->priv->connectivity_monitor.timer == NULL) {
rcc->priv->connectivity_monitor.state = CONNECTIVITY_STATE_CONNECTED;
- rcc->priv->connectivity_monitor.timer = rcc->priv->channel->core->timer_add(
- rcc->priv->channel->core, red_channel_client_connectivity_timer, rcc);
+ rcc->priv->connectivity_monitor.timer = core->timer_add(
+ core, red_channel_client_connectivity_timer, rcc);
rcc->priv->connectivity_monitor.timeout = timeout_ms;
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
- rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
- rcc->priv->connectivity_monitor.timeout);
+ core->timer_start(rcc->priv->connectivity_monitor.timer,
+ rcc->priv->connectivity_monitor.timeout);
}
}
}
@@ -861,9 +882,11 @@ static void red_channel_client_event(int fd, int event, void *data)
static int red_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
{
- if (red_client_get_channel(client, channel->type, channel->id)) {
+ uint32_t type, id;
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ if (red_client_get_channel(client, type, id)) {
spice_printerr("Error client %p: duplicate channel type %d id %d",
- client, channel->type, channel->id);
+ client, type, id);
return FALSE;
}
return TRUE;
@@ -874,24 +897,28 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
GError **error)
{
GError *local_error = NULL;
+ SpiceCoreInterfaceInternal *core;
RedChannelClient *self = RED_CHANNEL_CLIENT(initable);
pthread_mutex_lock(&self->priv->client->lock);
if (!red_channel_client_pre_create_validate(self->priv->channel, self->priv->client)) {
+ uint32_t id, type;
+ g_object_get(self->priv->channel,
+ "channel-type", &type,
+ "id", &id,
+ NULL);
g_set_error(&local_error,
SPICE_SERVER_ERROR,
SPICE_SERVER_ERROR_FAILED,
"Client %p: duplicate channel type %d id %d",
- self->priv->client, self->priv->channel->type,
- self->priv->channel->id);
+ self->priv->client, type, id);
goto cleanup;
}
+ core = red_channel_get_core_interface(self->priv->channel);
if (self->priv->monitor_latency
&& reds_stream_get_family(self->priv->stream) != AF_UNIX) {
self->priv->latency_monitor.timer =
- self->priv->channel->core->timer_add(self->priv->channel->core,
- red_channel_client_ping_timer,
- self);
+ core->timer_add(core, red_channel_client_ping_timer, self);
if (!self->priv->client->during_target_migrate) {
red_channel_client_start_ping_timer(self,
@@ -901,27 +928,26 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
}
self->incoming.opaque = self;
- self->incoming.cb = &self->priv->channel->incoming_cb;
+ self->incoming.cb = red_channel_get_incoming_handler(self->priv->channel);
self->incoming.header.data = self->incoming.header_buf;
self->incoming.serial = 1;
self->outgoing.opaque = self;
- self->outgoing.cb = &self->priv->channel->outgoing_cb;
+ self->outgoing.cb = red_channel_get_outgoing_handler(self->priv->channel);
self->outgoing.pos = 0;
self->outgoing.size = 0;
if (self->priv->stream)
self->priv->stream->watch =
- self->priv->channel->core->watch_add(self->priv->channel->core,
- self->priv->stream->socket,
- SPICE_WATCH_EVENT_READ,
- red_channel_client_event,
- self);
- self->priv->id = self->priv->channel->clients_num;
+ core->watch_add(core, self->priv->stream->socket,
+ SPICE_WATCH_EVENT_READ,
+ red_channel_client_event,
+ self);
+ self->priv->id = red_channel_get_n_clients(self->priv->channel);
red_channel_add_client(self->priv->channel, self);
red_client_add_channel(self->priv->client, self);
- if (!self->priv->channel->channel_cbs.config_socket(self)) {
+ if (!red_channel_config_socket(self->priv->channel, self)) {
g_set_error_literal(&local_error,
SPICE_SERVER_ERROR,
SPICE_SERVER_ERROR_FAILED,
@@ -981,8 +1007,9 @@ void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
}
if (rcc->priv->connectivity_monitor.timer) {
- rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
- rcc->priv->connectivity_monitor.timeout);
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
+ core->timer_start(rcc->priv->connectivity_monitor.timer,
+ rcc->priv->connectivity_monitor.timeout);
}
}
}
@@ -1001,13 +1028,14 @@ int red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc)
void red_channel_client_default_migrate(RedChannelClient *rcc)
{
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
if (rcc->priv->latency_monitor.timer) {
red_channel_client_cancel_ping_timer(rcc);
- rcc->priv->channel->core->timer_remove(rcc->priv->latency_monitor.timer);
+ core->timer_remove(rcc->priv->latency_monitor.timer);
rcc->priv->latency_monitor.timer = NULL;
}
if (rcc->priv->connectivity_monitor.timer) {
- rcc->priv->channel->core->timer_remove(rcc->priv->connectivity_monitor.timer);
+ core->timer_remove(rcc->priv->connectivity_monitor.timer);
rcc->priv->connectivity_monitor.timer = NULL;
}
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_MIGRATE);
@@ -1024,7 +1052,8 @@ void red_channel_client_destroy(RedChannelClient *rcc)
void red_channel_client_shutdown(RedChannelClient *rcc)
{
if (rcc->priv->stream && !rcc->priv->stream->shutdown) {
- rcc->priv->channel->core->watch_remove(rcc->priv->stream->watch);
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
+ core->watch_remove(rcc->priv->stream->watch);
rcc->priv->stream->watch = NULL;
shutdown(rcc->priv->stream->socket, SHUT_RDWR);
rcc->priv->stream->shutdown = TRUE;
@@ -1259,8 +1288,10 @@ void red_channel_client_push(RedChannelClient *rcc)
}
if (red_channel_client_no_item_being_sent(rcc) && ring_is_empty(&rcc->priv->pipe)
&& rcc->priv->stream->watch) {
- rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
- SPICE_WATCH_EVENT_READ);
+ SpiceCoreInterfaceInternal *core;
+ core = red_channel_get_core_interface(rcc->priv->channel);
+ core->watch_update_mask(rcc->priv->stream->watch,
+ SPICE_WATCH_EVENT_READ);
}
rcc->priv->during_send = FALSE;
g_object_unref(rcc);
@@ -1331,11 +1362,12 @@ static void red_channel_client_handle_pong(RedChannelClient *rcc, SpiceMsgPing *
red_channel_client_start_ping_timer(rcc, PING_TEST_TIMEOUT_MS);
}
-static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
+static void red_channel_client_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);
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
+ if (klass->handle_migrate_flush_mark) {
+ klass->handle_migrate_flush_mark(rcc);
}
}
@@ -1346,23 +1378,30 @@ static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
// 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)
+static void red_channel_client_handle_migrate_data(RedChannelClient *rcc,
+ uint32_t size,
+ void
+ *message)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
+ uint32_t type, id;
+
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
spice_debug("channel type %d id %d rcc %p size %u",
- channel->type, channel->id, rcc, size);
- if (!channel->channel_cbs.handle_migrate_data) {
+ type, id, rcc, size);
+ if (!klass->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) {
+ if (klass->handle_migrate_data_get_serial) {
red_channel_client_set_message_serial(rcc,
- channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
+ klass->handle_migrate_data_get_serial(rcc, size, message));
}
- if (!channel->channel_cbs.handle_migrate_data(rcc, size, message)) {
+ if (!klass->handle_migrate_data(rcc, size, message)) {
spice_channel_client_error(rcc, "handle_migrate_data failed");
return;
}
@@ -1394,11 +1433,11 @@ int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
spice_error("unexpected flush mark");
return FALSE;
}
- red_channel_handle_migrate_flush_mark(rcc);
+ red_channel_client_handle_migrate_flush_mark(rcc);
rcc->priv->wait_migrate_flush_mark = FALSE;
break;
case SPICE_MSGC_MIGRATE_DATA:
- red_channel_handle_migrate_data(rcc, size, message);
+ red_channel_client_handle_migrate_data(rcc, size, message);
break;
case SPICE_MSGC_PONG:
red_channel_client_handle_pong(rcc, message);
@@ -1417,7 +1456,7 @@ void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type,
rcc->priv->send_data.header.set_msg_type(&rcc->priv->send_data.header, msg_type);
rcc->priv->send_data.item = item;
if (item) {
- rcc->priv->channel->channel_cbs.hold_item(rcc, item);
+ red_channel_hold_item(rcc->priv->channel, rcc, item);
}
}
@@ -1477,9 +1516,10 @@ static inline gboolean client_pipe_add(RedChannelClient *rcc, RedPipeItem *item,
return FALSE;
}
if (ring_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
- rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
- SPICE_WATCH_EVENT_READ |
- SPICE_WATCH_EVENT_WRITE);
+ SpiceCoreInterfaceInternal *core;
+ core = red_channel_get_core_interface(rcc->priv->channel);
+ core->watch_update_mask(rcc->priv->stream->watch,
+ SPICE_WATCH_EVENT_READ | SPICE_WATCH_EVENT_WRITE);
}
rcc->priv->pipe_size++;
ring_add(pos, &item->link);
@@ -1558,7 +1598,7 @@ uint32_t red_channel_client_get_pipe_size(RedChannelClient *rcc)
static gboolean red_channel_client_default_is_connected(RedChannelClient *rcc)
{
return rcc->priv->channel
- && (g_list_find(rcc->priv->channel->clients, rcc) != NULL);
+ && (g_list_find(red_channel_get_clients(rcc->priv->channel), rcc) != NULL);
}
gboolean red_channel_client_is_connected(RedChannelClient *rcc)
@@ -1611,27 +1651,30 @@ void red_channel_client_push_set_ack(RedChannelClient *rcc)
static void red_channel_client_default_disconnect(RedChannelClient *rcc)
{
RedChannel *channel = rcc->priv->channel;
+ SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(channel);
+ uint32_t type, id;
if (!red_channel_client_is_connected(rcc)) {
return;
}
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
- channel->type, channel->id);
+ type, id);
red_channel_client_pipe_clear(rcc);
if (rcc->priv->stream->watch) {
- channel->core->watch_remove(rcc->priv->stream->watch);
+ core->watch_remove(rcc->priv->stream->watch);
rcc->priv->stream->watch = NULL;
}
if (rcc->priv->latency_monitor.timer) {
- channel->core->timer_remove(rcc->priv->latency_monitor.timer);
+ core->timer_remove(rcc->priv->latency_monitor.timer);
rcc->priv->latency_monitor.timer = NULL;
}
if (rcc->priv->connectivity_monitor.timer) {
- channel->core->timer_remove(rcc->priv->connectivity_monitor.timer);
+ core->timer_remove(rcc->priv->connectivity_monitor.timer);
rcc->priv->connectivity_monitor.timer = NULL;
}
red_channel_remove_client(channel, rcc);
- channel->channel_cbs.on_disconnect(rcc);
+ red_channel_on_disconnect(channel, rcc);
}
void red_channel_client_disconnect(RedChannelClient *rcc)
@@ -1688,7 +1731,7 @@ int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
end_time = UINT64_MAX;
}
- rcc->priv->channel->channel_cbs.hold_item(rcc, item);
+ red_channel_hold_item(rcc->priv->channel, rcc, item);
if (red_channel_client_is_blocked(rcc)) {
red_channel_client_receive(rcc);
@@ -1771,13 +1814,19 @@ void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc,
gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc)
{
gboolean ret = FALSE;
-
- if (rcc->priv->channel->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
+ uint32_t type, id, flags;
+
+ g_object_get(rcc->priv->channel,
+ "channel-type", &type,
+ "id", &id,
+ "migration-flags", &flags,
+ NULL);
+ if (flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
rcc->priv->wait_migrate_data = TRUE;
ret = TRUE;
}
- spice_debug("channel type %d id %d rcc %p wait data %d", rcc->priv->channel->type, rcc->priv->channel->id, rcc,
- rcc->priv->wait_migrate_data);
+ spice_debug("channel type %d id %d rcc %p wait data %d", type, id, rcc,
+ rcc->priv->wait_migrate_data);
return ret;
}
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index d8cc317..6649485 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -46,10 +46,10 @@ G_BEGIN_DECLS
#define RED_IS_CHANNEL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHANNEL_CLIENT))
#define RED_CHANNEL_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHANNEL_CLIENT, RedChannelClientClass))
-typedef struct RedChannel RedChannel;
typedef struct RedClient RedClient;
typedef struct IncomingHandler IncomingHandler;
+typedef struct RedChannel RedChannel;
typedef struct RedChannelClient RedChannelClient;
typedef struct RedChannelClientClass RedChannelClientClass;
typedef struct RedChannelClientPrivate RedChannelClientPrivate;
@@ -161,8 +161,10 @@ GType red_channel_client_get_type(void) G_GNUC_CONST;
#define spice_channel_client_error(rcc, format, ...) \
do { \
RedChannel *_ch = red_channel_client_get_channel(rcc); \
+ uint32_t _type, _id; \
+ g_object_get(_ch, "channel-type", &_type, "id", &_id, NULL); \
spice_warning("rcc %p type %u id %u: " format, rcc, \
- _ch->type, _ch->id, ## __VA_ARGS__); \
+ type, id, ## __VA_ARGS__); \
red_channel_client_shutdown(rcc); \
} while (0)
diff --git a/server/red-channel.c b/server/red-channel.c
index c714d90..df865f0 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -65,9 +65,135 @@
* from the channel's thread.
*/
-void red_channel_receive(RedChannel *channel)
+G_DEFINE_ABSTRACT_TYPE(RedChannel, red_channel, G_TYPE_OBJECT)
+
+#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_CHANNEL, RedChannelPrivate))
+
+struct RedChannelPrivate
+{
+ uint32_t type;
+ uint32_t id;
+
+ SpiceCoreInterfaceInternal *core;
+ gboolean handle_acks;
+
+ // RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there
+ // is no need to go over disconnect clients)
+ // . While client will hold the channel clients till it is destroyed
+ // and then it will destroy them as well.
+ // However RCC still holds a reference to the Channel.
+ // Maybe replace these logic with ref count?
+ // TODO: rename to 'connected_clients'?
+ GList *clients;
+
+ RedChannelCapabilities local_caps;
+ uint32_t migration_flags;
+
+ void *data;
+
+ OutgoingHandlerInterface outgoing_cb;
+ IncomingHandlerInterface incoming_cb;
+
+ ClientCbs client_cbs;
+ // TODO: when different channel_clients are in different threads from Channel -> need to protect!
+ pthread_t thread_id;
+ RedsState *reds;
+#ifdef RED_STATISTICS
+ StatNodeRef stat;
+ uint64_t *out_bytes_counter;
+#endif
+};
+
+enum {
+ PROP0,
+ PROP_SPICE_SERVER,
+ PROP_CORE_INTERFACE,
+ PROP_TYPE,
+ PROP_ID,
+ PROP_HANDLE_ACKS,
+ PROP_MIGRATION_FLAGS
+};
+
+static void
+red_channel_get_property(GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- g_list_foreach(channel->clients, (GFunc)red_channel_client_receive, NULL);
+ RedChannel *self = RED_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_SPICE_SERVER:
+ g_value_set_pointer(value, self->priv->reds);
+ break;
+ case PROP_CORE_INTERFACE:
+ g_value_set_pointer(value, self->priv->core);
+ break;
+ case PROP_TYPE:
+ g_value_set_int(value, self->priv->type);
+ break;
+ case PROP_ID:
+ g_value_set_uint(value, self->priv->id);
+ break;
+ case PROP_HANDLE_ACKS:
+ g_value_set_boolean(value, self->priv->handle_acks);
+ break;
+ case PROP_MIGRATION_FLAGS:
+ g_value_set_uint(value, self->priv->migration_flags);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+red_channel_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ RedChannel *self = RED_CHANNEL(object);
+
+ switch (property_id)
+ {
+ case PROP_SPICE_SERVER:
+ self->priv->reds = g_value_get_pointer(value);
+ break;
+ case PROP_CORE_INTERFACE:
+ self->priv->core = g_value_get_pointer(value);
+ break;
+ case PROP_TYPE:
+ self->priv->type = g_value_get_int(value);
+ break;
+ case PROP_ID:
+ self->priv->id = g_value_get_uint(value);
+ break;
+ case PROP_HANDLE_ACKS:
+ self->priv->handle_acks = g_value_get_boolean(value);
+ break;
+ case PROP_MIGRATION_FLAGS:
+ self->priv->migration_flags = g_value_get_uint(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+red_channel_finalize(GObject *object)
+{
+ RedChannel *self = RED_CHANNEL(object);
+
+ if (self->priv->local_caps.num_common_caps) {
+ free(self->priv->local_caps.common_caps);
+ }
+
+ if (self->priv->local_caps.num_caps) {
+ free(self->priv->local_caps.caps);
+ }
+
+ G_OBJECT_CLASS(red_channel_parent_class)->finalize(object);
}
static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
@@ -75,17 +201,170 @@ static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
red_channel_client_disconnect(rcc);
}
+static void red_channel_on_output(void *opaque, int n)
+{
+ RedChannelClient *rcc = opaque;
+ RedChannel *self = red_channel_client_get_channel(rcc);;
+
+ red_channel_client_on_output(opaque, n);
+
+ stat_inc_counter(self->priv->reds, self->priv->out_bytes_counter, n);
+}
+
+static void
+red_channel_constructed(GObject *object)
+{
+ RedChannel *self = RED_CHANNEL(object);
+ spice_debug("%p: channel type %d id %d thread_id 0x%lx", self,
+ self->priv->type, self->priv->id, self->priv->thread_id);
+
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ self->priv->incoming_cb.alloc_msg_buf =
+ (alloc_msg_recv_buf_proc)klass->alloc_recv_buf;
+ self->priv->incoming_cb.release_msg_buf =
+ (release_msg_recv_buf_proc)klass->release_recv_buf;
+ self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message;
+ self->priv->incoming_cb.handle_parsed = (handle_parsed_proc)klass->handle_parsed;
+ self->priv->incoming_cb.parser = klass->parser;
+
+ G_OBJECT_CLASS(red_channel_parent_class)->constructed(object);
+}
+
+static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
+ RedsStream *stream,
+ int migration,
+ int num_common_caps, uint32_t *common_caps,
+ int num_caps, uint32_t *caps)
+{
+ spice_error("not implemented");
+}
+
+static void red_channel_client_default_disconnect(RedChannelClient *base)
+{
+ red_channel_client_disconnect(base);
+}
+
+static void
+red_channel_class_init(RedChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof (RedChannelPrivate));
+
+ object_class->get_property = red_channel_get_property;
+ object_class->set_property = red_channel_set_property;
+ object_class->finalize = red_channel_finalize;
+ object_class->constructed = red_channel_constructed;
+
+ g_object_class_install_property(object_class,
+ PROP_SPICE_SERVER,
+ g_param_spec_pointer("spice-server",
+ "spice-server",
+ "The spice server associated with this channel",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property(object_class,
+ PROP_CORE_INTERFACE,
+ g_param_spec_pointer("core-interface",
+ "core-interface",
+ "The SpiceCoreInterface server associated with this channel",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /* FIXME: generate enums for this in spice-common? */
+ g_object_class_install_property(object_class,
+ PROP_TYPE,
+ g_param_spec_int("channel-type",
+ "channel type",
+ "Type of this channel",
+ 0,
+ SPICE_END_CHANNEL,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property(object_class,
+ PROP_ID,
+ g_param_spec_uint("id",
+ "id",
+ "ID of this channel",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property(object_class,
+ PROP_HANDLE_ACKS,
+ g_param_spec_boolean("handle-acks",
+ "Handle ACKs",
+ "Whether this channel handles ACKs",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property(object_class,
+ PROP_MIGRATION_FLAGS,
+ g_param_spec_uint("migration-flags",
+ "migration flags",
+ "Migration flags for this channel",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+red_channel_init(RedChannel *self)
+{
+ self->priv = CHANNEL_PRIVATE(self);
+
+ red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER);
+ self->priv->thread_id = pthread_self();
+ self->priv->out_bytes_counter = 0;
+
+ // TODO: send incoming_cb as parameters instead of duplicating?
+ self->priv->incoming_cb.on_error =
+ (on_incoming_error_proc)red_channel_client_default_peer_on_error;
+ self->priv->incoming_cb.on_input = red_channel_client_on_input;
+ self->priv->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size;
+ self->priv->outgoing_cb.prepare = red_channel_client_prepare_out_msg;
+ self->priv->outgoing_cb.on_block = red_channel_client_on_out_block;
+ self->priv->outgoing_cb.on_error =
+ (on_outgoing_error_proc)red_channel_client_default_peer_on_error;
+ self->priv->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
+ self->priv->outgoing_cb.on_output = red_channel_on_output;
+
+ self->priv->client_cbs.connect = red_channel_client_default_connect;
+ self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
+ self->priv->client_cbs.migrate = red_channel_client_default_migrate;
+}
+
+
+void red_channel_receive(RedChannel *channel)
+{
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_receive, NULL);
+}
+
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
{
spice_assert(rcc);
- channel->clients = g_list_append(channel->clients, rcc);
+ channel->priv->clients = g_list_append(channel->priv->clients, rcc);
}
int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap)
{
GList *link;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
if (!red_channel_client_test_remote_common_cap(rcc, cap)) {
@@ -99,7 +378,7 @@ int red_channel_test_remote_cap(RedChannel *channel, uint32_t cap)
{
GList *link;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
RedChannelClient *rcc = link->data;
if (!red_channel_client_test_remote_cap(rcc, cap)) {
@@ -136,7 +415,7 @@ gboolean red_client_seamless_migration_done_for_channel(RedClient *client,
int red_channel_is_waiting_for_migrate_data(RedChannel *channel)
{
RedChannelClient *rcc;
- guint n_clients = g_list_length(channel->clients);
+ guint n_clients = g_list_length(channel->priv->clients);
if (!red_channel_is_connected(channel)) {
return FALSE;
@@ -146,190 +425,42 @@ int red_channel_is_waiting_for_migrate_data(RedChannel *channel)
return FALSE;
}
spice_assert(n_clients == 1);
- rcc = channel->clients->data;
+ rcc = channel->priv->clients->data;
return red_channel_client_is_waiting_for_migrate_data(rcc);
}
-static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
- RedsStream *stream,
- int migration,
- int num_common_caps, uint32_t *common_caps,
- int num_caps, uint32_t *caps)
-{
- spice_error("not implemented");
-}
-
-static void red_channel_client_default_disconnect(RedChannelClient *base)
-{
- red_channel_client_disconnect(base);
-}
-
-RedChannel *red_channel_create(int size,
- RedsState *reds,
- const SpiceCoreInterfaceInternal *core,
- uint32_t type, uint32_t id,
- int handle_acks,
- channel_handle_message_proc handle_message,
- const ChannelCbs *channel_cbs,
- uint32_t migration_flags)
-{
- RedChannel *channel;
- ClientCbs client_cbs = { NULL, };
-
- spice_assert(size >= sizeof(*channel));
- spice_assert(channel_cbs->config_socket && channel_cbs->on_disconnect && handle_message &&
- channel_cbs->alloc_recv_buf && channel_cbs->release_item);
- spice_assert(channel_cbs->handle_migrate_data ||
- !(migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
- channel = spice_malloc0(size);
- channel->type = type;
- channel->id = id;
- channel->refs = 1;
- channel->handle_acks = handle_acks;
- channel->migration_flags = migration_flags;
- memcpy(&channel->channel_cbs, channel_cbs, sizeof(ChannelCbs));
-
- channel->reds = reds;
- channel->core = core;
-
- // TODO: send incoming_cb as parameters instead of duplicating?
- channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)channel_cbs->alloc_recv_buf;
- channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)channel_cbs->release_recv_buf;
- channel->incoming_cb.handle_message = (handle_message_proc)handle_message;
- channel->incoming_cb.on_error =
- (on_incoming_error_proc)red_channel_client_default_peer_on_error;
- channel->incoming_cb.on_input = red_channel_client_on_input;
- channel->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size;
- channel->outgoing_cb.prepare = red_channel_client_prepare_out_msg;
- channel->outgoing_cb.on_block = red_channel_client_on_out_block;
- channel->outgoing_cb.on_error =
- (on_outgoing_error_proc)red_channel_client_default_peer_on_error;
- channel->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
- channel->outgoing_cb.on_output = red_channel_client_on_output;
-
- client_cbs.connect = red_channel_client_default_connect;
- client_cbs.disconnect = red_channel_client_default_disconnect;
- client_cbs.migrate = red_channel_client_default_migrate;
-
- red_channel_register_client_cbs(channel, &client_cbs, NULL);
- red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
-
- channel->thread_id = pthread_self();
-
- channel->out_bytes_counter = 0;
-
- spice_debug("channel type %d id %d thread_id 0x%lx",
- channel->type, channel->id, channel->thread_id);
- return channel;
-}
-
-// TODO: red_worker can use this one
-static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask)
-{
-}
-
-static SpiceWatch *dummy_watch_add(const SpiceCoreInterfaceInternal *iface,
- int fd, int event_mask, SpiceWatchFunc func, void *opaque)
-{
- return NULL; // apparently allowed?
-}
-
-static void dummy_watch_remove(SpiceWatch *watch)
-{
-}
-
-// TODO: actually, since I also use channel_client_dummy, no need for core. Can be NULL
-static const SpiceCoreInterfaceInternal dummy_core = {
- .watch_update_mask = dummy_watch_update_mask,
- .watch_add = dummy_watch_add,
- .watch_remove = dummy_watch_remove,
-};
-
-RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t type, uint32_t id)
-{
- RedChannel *channel;
- ClientCbs client_cbs = { NULL, };
-
- spice_assert(size >= sizeof(*channel));
- channel = spice_malloc0(size);
- channel->type = type;
- channel->id = id;
- channel->refs = 1;
- channel->reds = reds;
- channel->core = &dummy_core;
- client_cbs.connect = red_channel_client_default_connect;
- client_cbs.disconnect = red_channel_client_default_disconnect;
- client_cbs.migrate = red_channel_client_default_migrate;
-
- red_channel_register_client_cbs(channel, &client_cbs, NULL);
- red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
-
- channel->thread_id = pthread_self();
- spice_debug("channel type %d id %d thread_id 0x%lx",
- channel->type, channel->id, channel->thread_id);
-
- channel->out_bytes_counter = 0;
-
- return channel;
-}
-
-static int do_nothing_handle_message(RedChannelClient *rcc,
- uint16_t type,
- uint32_t size,
- uint8_t *msg)
-{
- return TRUE;
-}
-
-RedChannel *red_channel_create_parser(int size,
- RedsState *reds,
- const SpiceCoreInterfaceInternal *core,
- uint32_t type, uint32_t id,
- int handle_acks,
- spice_parse_channel_func_t parser,
- channel_handle_parsed_proc handle_parsed,
- const ChannelCbs *channel_cbs,
- uint32_t migration_flags)
+void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat)
{
- RedChannel *channel = red_channel_create(size, reds, core, type, id,
- handle_acks,
- do_nothing_handle_message,
- channel_cbs,
- migration_flags);
-
- if (channel == NULL) {
- return NULL;
- }
- channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed;
- channel->incoming_cb.parser = parser;
+ spice_return_if_fail(channel != NULL);
+ spice_return_if_fail(channel->priv->stat == 0);
- return channel;
+#ifdef RED_STATISTICS
+ channel->priv->stat = stat;
+ channel->priv->out_bytes_counter = stat_add_counter(channel->priv->reds, stat, "out_bytes", TRUE);
+#endif
}
-void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat)
+StatNodeRef red_channel_get_stat_node(RedChannel *channel)
{
- spice_return_if_fail(channel != NULL);
- spice_return_if_fail(channel->stat == 0);
-
#ifdef RED_STATISTICS
- channel->stat = stat;
- channel->out_bytes_counter = stat_add_counter(channel->reds, stat, "out_bytes", TRUE);
+ return channel->priv->stat;
#endif
+ return 0;
}
void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs, gpointer cbs_data)
{
- spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN);
- channel->client_cbs.connect = client_cbs->connect;
+ spice_assert(client_cbs->connect || channel->priv->type == SPICE_CHANNEL_MAIN);
+ channel->priv->client_cbs.connect = client_cbs->connect;
if (client_cbs->disconnect) {
- channel->client_cbs.disconnect = client_cbs->disconnect;
+ channel->priv->client_cbs.disconnect = client_cbs->disconnect;
}
if (client_cbs->migrate) {
- channel->client_cbs.migrate = client_cbs->migrate;
+ channel->priv->client_cbs.migrate = client_cbs->migrate;
}
- channel->data = cbs_data;
+ channel->priv->data = cbs_data;
}
int test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
@@ -356,32 +487,12 @@ static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap)
{
- add_capability(&channel->local_caps.common_caps, &channel->local_caps.num_common_caps, cap);
+ add_capability(&channel->priv->local_caps.common_caps, &channel->priv->local_caps.num_common_caps, cap);
}
void red_channel_set_cap(RedChannel *channel, uint32_t cap)
{
- add_capability(&channel->local_caps.caps, &channel->local_caps.num_caps, cap);
-}
-
-void red_channel_ref(RedChannel *channel)
-{
- channel->refs++;
-}
-
-void red_channel_unref(RedChannel *channel)
-{
- if (--channel->refs == 0) {
- if (channel->local_caps.num_common_caps) {
- free(channel->local_caps.common_caps);
- }
-
- if (channel->local_caps.num_caps) {
- free(channel->local_caps.caps);
- }
-
- free(channel);
- }
+ add_capability(&channel->priv->local_caps.caps, &channel->priv->local_caps.num_caps, cap);
}
void red_channel_destroy(RedChannel *channel)
@@ -390,13 +501,13 @@ void red_channel_destroy(RedChannel *channel)
return;
}
- g_list_foreach(channel->clients, (GFunc)red_channel_client_destroy, NULL);
- red_channel_unref(channel);
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_destroy, NULL);
+ g_object_unref(channel);
}
void red_channel_send(RedChannel *channel)
{
- g_list_foreach(channel->clients, (GFunc)red_channel_client_send, NULL);
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_send, NULL);
}
void red_channel_push(RedChannel *channel)
@@ -405,14 +516,14 @@ void red_channel_push(RedChannel *channel)
return;
}
- g_list_foreach(channel->clients, (GFunc)red_channel_client_push, NULL);
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_push, NULL);
}
// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
// specific
void red_channel_init_outgoing_messages_window(RedChannel *channel)
{
- g_list_foreach(channel->clients, (GFunc)red_channel_client_init_outgoing_messages_window, NULL);
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_init_outgoing_messages_window, NULL);
}
static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_data)
@@ -423,7 +534,7 @@ static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_
void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
{
- g_list_foreach(channel->clients, red_channel_client_pipe_add_type_proxy,
+ g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_type_proxy,
GINT_TO_POINTER(pipe_item_type));
}
@@ -435,12 +546,12 @@ static void red_channel_client_pipe_add_empty_msg_proxy(gpointer data, gpointer
void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type)
{
- g_list_foreach(channel->clients, red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type));
+ g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type));
}
int red_channel_is_connected(RedChannel *channel)
{
- return channel && channel->clients;
+ return channel && channel->priv->clients;
}
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc)
@@ -448,19 +559,19 @@ void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc)
GList *link;
g_return_if_fail(channel == red_channel_client_get_channel(rcc));
- if (!pthread_equal(pthread_self(), channel->thread_id)) {
+ if (!pthread_equal(pthread_self(), channel->priv->thread_id)) {
spice_warning("channel type %d id %d - "
"channel->thread_id (0x%lx) != pthread_self (0x%lx)."
"If one of the threads is != io-thread && != vcpu-thread, "
"this might be a BUG",
- channel->type, channel->id,
- channel->thread_id, pthread_self());
+ channel->priv->type, channel->priv->id,
+ channel->priv->thread_id, pthread_self());
}
spice_return_if_fail(channel);
- link = g_list_find(channel->clients, rcc);
+ link = g_list_find(channel->priv->clients, rcc);
spice_return_if_fail(link != NULL);
- channel->clients = g_list_remove_link(channel->clients, link);
+ channel->priv->clients = g_list_remove_link(channel->priv->clients, link);
// TODO: should we set rcc->channel to NULL???
}
@@ -474,17 +585,35 @@ void red_client_remove_channel(RedChannelClient *rcc)
void red_channel_disconnect(RedChannel *channel)
{
- g_list_foreach(channel->clients, (GFunc)red_channel_client_disconnect, NULL);
+ g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_disconnect, NULL);
+}
+
+void red_channel_connect(RedChannel *channel, RedClient *client,
+ RedsStream *stream, int migration, int num_common_caps,
+ uint32_t *common_caps, int num_caps, uint32_t *caps)
+{
+ channel->priv->client_cbs.connect(channel, client, stream, migration,
+ num_common_caps, common_caps, num_caps,
+ caps);
}
void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb)
{
- g_list_foreach(channel->clients, (GFunc)cb, NULL);
+ g_list_foreach(channel->priv->clients, (GFunc)cb, NULL);
}
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data cb, void *data)
{
- g_list_foreach(channel->clients, (GFunc)cb, data);
+ g_list_foreach(channel->priv->clients, (GFunc)cb, data);
+}
+
+GList *red_channel_get_clients(RedChannel *channel)
+{
+ return channel->priv->clients;
+}
+guint red_channel_get_n_clients(RedChannel *channel)
+{
+ return g_list_length(channel->priv->clients);
}
int red_channel_all_blocked(RedChannel *channel)
@@ -492,10 +621,10 @@ int red_channel_all_blocked(RedChannel *channel)
GList *link;
RedChannelClient *rcc;
- if (!channel || !channel->clients) {
+ if (!channel || !channel->priv->clients) {
return FALSE;
}
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
rcc = link->data;
if (!red_channel_client_is_blocked(rcc)) {
return FALSE;
@@ -509,7 +638,7 @@ int red_channel_any_blocked(RedChannel *channel)
GList *link;
RedChannelClient *rcc;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
rcc = link->data;
if (red_channel_client_is_blocked(rcc)) {
return TRUE;
@@ -523,10 +652,10 @@ int red_channel_get_first_socket(RedChannel *channel)
RedChannelClient *rcc;
RedsStream *stream;
- if (!channel || !channel->clients) {
+ if (!channel || !channel->priv->clients) {
return -1;
}
- rcc = channel->clients->data;
+ rcc = channel->priv->clients->data;
stream = red_channel_client_get_stream(rcc);
return stream->socket;
@@ -537,7 +666,7 @@ int red_channel_no_item_being_sent(RedChannel *channel)
GList *link;
RedChannelClient *rcc;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
rcc = link->data;
if (!red_channel_client_no_item_being_sent(rcc)) {
return FALSE;
@@ -617,7 +746,7 @@ void red_client_migrate(RedClient *client)
rcc = link->data;
channel = red_channel_client_get_channel(rcc);
if (red_channel_client_is_connected(rcc)) {
- channel->client_cbs.migrate(rcc);
+ channel->priv->client_cbs.migrate(rcc);
}
link = next;
}
@@ -650,7 +779,7 @@ void red_client_destroy(RedClient *client)
// to wait for disconnection)
// TODO: should we go back to async. For this we need to use
// ref count for channel clients.
- channel->client_cbs.disconnect(rcc);
+ channel->priv->client_cbs.disconnect(rcc);
spice_assert(red_channel_client_pipe_is_empty(rcc));
spice_assert(red_channel_client_no_item_being_sent(rcc));
red_channel_client_destroy(rcc);
@@ -670,7 +799,7 @@ RedChannelClient *red_client_get_channel(RedClient *client, int type, int id)
RedChannel *channel;
rcc = link->data;
channel = red_channel_client_get_channel(rcc);
- if (channel->type == type && channel->id == id) {
+ if (channel->priv->type == type && channel->priv->id == id) {
ret = rcc;
break;
}
@@ -763,7 +892,7 @@ static int red_channel_pipes_create_batch(RedChannel *channel,
spice_assert(creator != NULL);
spice_assert(pipe_add != NULL);
- link = channel->clients;
+ link = channel->priv->clients;
while (link != NULL) {
next = link->next;
rcc = link->data;
@@ -806,7 +935,7 @@ uint32_t red_channel_max_pipe_size(RedChannel *channel)
RedChannelClient *rcc;
uint32_t pipe_size = 0;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
uint32_t new_size;
rcc = link->data;
new_size = red_channel_client_get_pipe_size(rcc);
@@ -821,7 +950,7 @@ uint32_t red_channel_min_pipe_size(RedChannel *channel)
RedChannelClient *rcc;
uint32_t pipe_size = ~0;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
uint32_t new_size;
rcc = link->data;
new_size = red_channel_client_get_pipe_size(rcc);
@@ -836,7 +965,7 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel)
RedChannelClient *rcc;
uint32_t sum = 0;
- for (link = channel->clients; link != NULL; link = link->next) {
+ for (link = channel->priv->clients; link != NULL; link = link->next) {
rcc = link->data;
sum += red_channel_client_get_pipe_size(rcc);
}
@@ -879,5 +1008,116 @@ int red_channel_wait_all_sent(RedChannel *channel,
RedsState* red_channel_get_server(RedChannel *channel)
{
- return channel->reds;
+ return channel->priv->reds;
+}
+
+SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel)
+{
+ return channel->priv->core;
+}
+
+int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_val_if_fail(klass->config_socket, FALSE);
+
+ return klass->config_socket(rcc);
+}
+
+void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_if_fail(klass->on_disconnect);
+
+ klass->on_disconnect(rcc);
+}
+
+void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_if_fail(klass->send_item);
+
+ klass->send_item(rcc, item);
+}
+
+void red_channel_hold_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_if_fail(klass->hold_item);
+
+ klass->hold_item(rcc, item);
+}
+
+void red_channel_release_item(RedChannel *self, RedChannelClient *rcc,
+ RedPipeItem *item, int item_pushed)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_if_fail(klass->release_item);
+
+ klass->release_item(rcc, item, item_pushed);
+}
+
+uint8_t* red_channel_alloc_recv_buf(RedChannel *self, RedChannelClient *rcc,
+ uint16_t type, uint32_t size)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_val_if_fail(klass->alloc_recv_buf, NULL);
+
+ return klass->alloc_recv_buf(rcc, type, size);
+}
+
+void red_channel_release_recv_buf(RedChannel *self, RedChannelClient *rcc,
+ uint16_t type, uint32_t size, uint8_t *msg)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_if_fail(klass->release_recv_buf);
+
+ klass->release_recv_buf(rcc, type, size, msg);
+}
+
+int red_channel_handle_migrate_flush_mark(RedChannel *self, RedChannelClient *rcc)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_val_if_fail(klass->handle_migrate_flush_mark, FALSE);
+
+ return klass->handle_migrate_flush_mark(rcc);
+}
+
+int red_channel_handle_migrate_data(RedChannel *self, RedChannelClient *rcc,
+ uint32_t size, void *message)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_val_if_fail(klass->handle_migrate_data, FALSE);
+
+ return klass->handle_migrate_data(rcc, size, message);
+}
+
+uint64_t red_channel_handle_migrate_data_get_serial(RedChannel *self,
+ RedChannelClient *rcc,
+ uint32_t size, void *message)
+{
+ RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
+ g_return_val_if_fail(klass->handle_migrate_data_get_serial, 0);
+
+ return klass->handle_migrate_data_get_serial(rcc, size, message);
+}
+
+IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self)
+{
+ return &self->priv->incoming_cb;
+}
+
+OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self)
+{
+ return &self->priv->outgoing_cb;
+}
+
+void red_channel_reset_thread_id(RedChannel *self)
+{
+ self->priv->thread_id = pthread_self();
+}
+
+RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self)
+{
+ return &self->priv->local_caps;
}
diff --git a/server/red-channel.h b/server/red-channel.h
index 5c1d555..1b8abce 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -36,9 +36,10 @@
#include "red-pipe-item.h"
#include "red-channel-client.h"
-/* Red Channel interface */
+#include <glib-object.h>
+
+G_BEGIN_DECLS
-typedef struct RedChannel RedChannel;
typedef struct RedClient RedClient;
typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
@@ -71,13 +72,53 @@ typedef void (*channel_client_connect_proc)(RedChannel *channel, RedClient *clie
typedef void (*channel_client_disconnect_proc)(RedChannelClient *base);
typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
-// TODO: add ASSERTS for thread_id in client and channel calls
-//
+
/*
- * callbacks that are triggered from channel client stream events.
- * They are called from the thread that listen to the stream events.
+ * callbacks that are triggered from client events.
+ * They should be called from the thread that handles the RedClient
*/
typedef struct {
+ channel_client_connect_proc connect;
+ channel_client_disconnect_proc disconnect;
+ channel_client_migrate_proc migrate;
+} ClientCbs;
+
+int test_capability(const uint32_t *caps, int num_caps, uint32_t cap);
+
+#define RED_TYPE_CHANNEL red_channel_get_type()
+
+#define RED_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHANNEL, RedChannel))
+#define RED_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHANNEL, RedChannelClass))
+#define RED_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHANNEL))
+#define RED_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHANNEL))
+#define RED_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHANNEL, RedChannelClass))
+
+typedef struct RedChannel RedChannel;
+typedef struct RedChannelClass RedChannelClass;
+typedef struct RedChannelPrivate RedChannelPrivate;
+
+struct RedChannel
+{
+ GObject parent;
+
+ RedChannelPrivate *priv;
+};
+
+struct RedChannelClass
+{
+ GObjectClass parent_class;
+
+ /* subclasses must implement either handle_message(), or both parser() and
+ * handle_parsed() */
+ channel_handle_message_proc handle_message;
+ spice_parse_channel_func_t parser;
+ channel_handle_parsed_proc handle_parsed;
+
+ // TODO: add ASSERTS for thread_id in client and channel calls
+ /*
+ * callbacks that are triggered from channel client stream events.
+ * They are called from the thread that listen to the stream events.
+ */
channel_configure_socket_proc config_socket;
channel_disconnect_proc on_disconnect;
channel_send_pipe_item_proc send_item;
@@ -88,18 +129,9 @@ typedef struct {
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark;
channel_handle_migrate_data_proc handle_migrate_data;
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial;
-} ChannelCbs;
-
+};
-/*
- * callbacks that are triggered from client events.
- * They should be called from the thread that handles the RedClient
- */
-typedef struct {
- channel_client_connect_proc connect;
- channel_client_disconnect_proc disconnect;
- channel_client_migrate_proc migrate;
-} ClientCbs;
+/* Red Channel interface */
typedef struct RedChannelCapabilities {
int num_common_caps;
@@ -108,94 +140,20 @@ typedef struct RedChannelCapabilities {
uint32_t *caps;
} RedChannelCapabilities;
-int test_capability(const uint32_t *caps, int num_caps, uint32_t cap);
-
-typedef struct RedChannelClientLatencyMonitor {
- int state;
- uint64_t last_pong_time;
- SpiceTimer *timer;
- uint32_t id;
- int tcp_nodelay;
- int warmup_was_sent;
-
- int64_t roundtrip;
-} RedChannelClientLatencyMonitor;
-
-typedef struct RedChannelClientConnectivityMonitor {
- int state;
- uint32_t out_bytes;
- uint32_t in_bytes;
- uint32_t timeout;
- SpiceTimer *timer;
-} RedChannelClientConnectivityMonitor;
-
-struct RedChannel {
- uint32_t type;
- uint32_t id;
-
- uint32_t refs;
-
- RingItem link; // channels link for reds
-
- const SpiceCoreInterfaceInternal *core;
- int handle_acks;
-
- // RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there
- // is no need to go over disconnect clients)
- // . While client will hold the channel clients till it is destroyed
- // and then it will destroy them as well.
- // However RCC still holds a reference to the Channel.
- // Maybe replace these logic with ref count?
- // TODO: rename to 'connected_clients'?
- GList *clients;
- uint32_t clients_num;
-
- OutgoingHandlerInterface outgoing_cb;
- IncomingHandlerInterface incoming_cb;
-
- ChannelCbs channel_cbs;
- ClientCbs client_cbs;
-
- RedChannelCapabilities local_caps;
- uint32_t migration_flags;
-
- void *data;
-
- // TODO: when different channel_clients are in different threads from Channel -> need to protect!
- pthread_t thread_id;
- RedsState *reds;
-#ifdef RED_STATISTICS
- StatNodeRef stat;
- uint64_t *out_bytes_counter;
-#endif
-};
-
-#define RED_CHANNEL(Channel) ((RedChannel *)(Channel))
-
-/* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
- * explicitly destroy the channel */
-RedChannel *red_channel_create(int size,
- RedsState *reds,
- const SpiceCoreInterfaceInternal *core,
- uint32_t type, uint32_t id,
- int handle_acks,
- channel_handle_message_proc handle_message,
- const ChannelCbs *channel_cbs,
- uint32_t migration_flags);
+GType red_channel_get_type(void) G_GNUC_CONST;
/* alternative constructor, meant for marshaller based (inputs,main) channels,
* will become default eventually */
+/*
RedChannel *red_channel_create_parser(int size,
RedsState *reds,
const SpiceCoreInterfaceInternal *core,
uint32_t type, uint32_t id,
- int handle_acks,
+ gboolean handle_acks,
spice_parse_channel_func_t parser,
channel_handle_parsed_proc handle_parsed,
- const ChannelCbs *channel_cbs,
uint32_t migration_flags);
-void red_channel_ref(RedChannel *channel);
-void red_channel_unref(RedChannel *channel);
+ */
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc);
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc);
@@ -206,11 +164,6 @@ void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *clien
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
void red_channel_set_cap(RedChannel *channel, uint32_t cap);
-// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd channel), but
-// do use the client callbacks. So the channel clients are not connected (the channel doesn't
-// have list of them, but they do have a link to the channel, and the client has a list of them)
-RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t type, uint32_t id);
-
int red_channel_is_connected(RedChannel *channel);
/* seamless migration is supported for only one client. This routine
@@ -274,6 +227,9 @@ void red_channel_receive(RedChannel *channel);
void red_channel_send(RedChannel *channel);
// For red_worker
void red_channel_disconnect(RedChannel *channel);
+void red_channel_connect(RedChannel *channel, RedClient *client,
+ RedsStream *stream, int migration, int num_common_caps,
+ uint32_t *common_caps, int num_caps, uint32_t *caps);
/* return the sum of all the rcc pipe size */
uint32_t red_channel_max_pipe_size(RedChannel *channel);
@@ -286,8 +242,38 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel);
typedef void (*channel_client_callback)(RedChannelClient *rcc);
typedef void (*channel_client_callback_data)(RedChannelClient *rcc, void *data);
void red_channel_apply_clients(RedChannel *channel, channel_client_callback v);
-void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data v, void * data);
+void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data v, void *data);
+GList *red_channel_get_clients(RedChannel *channel);
+guint red_channel_get_n_clients(RedChannel *channel);
struct RedsState* red_channel_get_server(RedChannel *channel);
+SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel);
+
+/* channel callback function */
+int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc);
+void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc);
+void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item);
+void red_channel_hold_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item);
+void red_channel_release_item(RedChannel *channel, RedChannelClient *rcc,
+ RedPipeItem *item, int item_pushed);
+uint8_t* red_channel_alloc_recv_buf(RedChannel *self, RedChannelClient *rcc,
+ uint16_t type, uint32_t size);
+void red_channel_release_recv_buf(RedChannel *self, RedChannelClient *rcc,
+ uint16_t type, uint32_t size, uint8_t *msg);
+int red_channel_handle_migrate_flush_mark(RedChannel *self, RedChannelClient *rcc);
+int red_channel_handle_migrate_data(RedChannel *self, RedChannelClient *rcc,
+ uint32_t size, void *message);
+uint64_t red_channel_handle_migrate_data_get_serial(RedChannel *self,
+ RedChannelClient *rcc,
+ uint32_t size, void *message);
+void red_channel_reset_thread_id(RedChannel *self);
+StatNodeRef red_channel_get_stat_node(RedChannel *channel);
+
+/* FIXME: do these even need to be in RedChannel? It's really only used in
+ * RedChannelClient. Needs refactoring */
+IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self);
+OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self);
+
+RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self);
struct RedClient {
RedsState *reds;
@@ -362,4 +348,6 @@ int red_channel_wait_all_sent(RedChannel *channel,
#define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro
+G_END_DECLS
+
#endif
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index 9c30572..5da6916 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -64,6 +64,8 @@ static inline RedDrawable *red_drawable_ref(RedDrawable *drawable)
return drawable;
}
+void red_drawable_unref(RedDrawable *red_drawable);
+
typedef struct RedUpdateCmd {
QXLReleaseInfoExt release_info_ext;
SpiceRect area;
diff --git a/server/red-qxl.c b/server/red-qxl.c
index ef39f0e..d255eb6 100644
--- a/server/red-qxl.c
+++ b/server/red-qxl.c
@@ -81,7 +81,7 @@ static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
Dispatcher *dispatcher;
spice_debug("%s", "");
- dispatcher = (Dispatcher *)channel->data;
+ dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
payload.client = client;
payload.stream = stream;
payload.migration = migration;
@@ -108,7 +108,7 @@ static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
return;
}
- dispatcher = (Dispatcher *)channel->data;
+ dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
spice_printerr("");
payload.rcc = rcc;
@@ -125,11 +125,14 @@ static void red_qxl_display_migrate(RedChannelClient *rcc)
RedWorkerMessageDisplayMigrate payload;
Dispatcher *dispatcher;
RedChannel *channel = red_channel_client_get_channel(rcc);
+ uint32_t type, id;
+
if (!channel) {
return;
}
- dispatcher = (Dispatcher *)channel->data;
- spice_printerr("channel type %u id %u", channel->type, channel->id);
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
+ spice_printerr("channel type %u id %u", type, id);
payload.rcc = rcc;
dispatcher_send_message(dispatcher,
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
@@ -142,7 +145,7 @@ static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client, Reds
uint32_t *caps)
{
RedWorkerMessageCursorConnect payload = {0,};
- Dispatcher *dispatcher = (Dispatcher *)channel->data;
+ Dispatcher *dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
spice_printerr("");
payload.client = client;
payload.stream = stream;
@@ -170,7 +173,7 @@ static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
return;
}
- dispatcher = (Dispatcher *)channel->data;
+ dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
spice_printerr("");
payload.rcc = rcc;
@@ -184,12 +187,14 @@ static void red_qxl_cursor_migrate(RedChannelClient *rcc)
RedWorkerMessageCursorMigrate payload;
Dispatcher *dispatcher;
RedChannel *channel = red_channel_client_get_channel(rcc);
+ uint32_t type, id;
if (!channel) {
return;
}
- dispatcher = (Dispatcher *)channel->data;
- spice_printerr("channel type %u id %u", channel->type, channel->id);
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
+ spice_printerr("channel type %u id %u", type, id);
payload.rcc = rcc;
dispatcher_send_message(dispatcher,
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
diff --git a/server/red-replay-qxl.c b/server/red-replay-qxl.c
index 281bc7a..a64d438 100644
--- a/server/red-replay-qxl.c
+++ b/server/red-replay-qxl.c
@@ -24,7 +24,7 @@
#include <zlib.h>
#include <pthread.h>
#include "reds.h"
-#include "red-worker.h"
+#include "red-qxl.h"
#include "red-common.h"
#include "memslot.h"
#include "red-parse-qxl.h"
diff --git a/server/red-worker.c b/server/red-worker.c
index 5be29aa..0d462b5 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -23,16 +23,12 @@
#include <stdio.h>
#include <stdarg.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
-#include <netinet/tcp.h>
#include <openssl/ssl.h>
#include <inttypes.h>
#include <glib.h>
@@ -97,33 +93,8 @@ static RedsState* red_worker_get_server(RedWorker *worker);
static int display_is_connected(RedWorker *worker)
{
- return (worker->display_channel && red_channel_is_connected(
- &worker->display_channel->common.base));
-}
-
-static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
-{
- RedChannel *channel = red_channel_client_get_channel(rcc);
- CommonGraphicsChannel *common = SPICE_CONTAINEROF(channel, CommonGraphicsChannel, base);
-
- /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */
- if (type == SPICE_MSGC_MIGRATE_DATA) {
- return spice_malloc(size);
- }
-
- if (size > CHANNEL_RECEIVE_BUF_SIZE) {
- spice_critical("unexpected message size %u (max is %d)", size, CHANNEL_RECEIVE_BUF_SIZE);
- return NULL;
- }
- return common->recv_buf;
-}
-
-static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size,
- uint8_t* msg)
-{
- if (type == SPICE_MSGC_MIGRATE_DATA) {
- free(msg);
- }
+ return worker->display_channel &&
+ red_channel_is_connected(RED_CHANNEL(worker->display_channel));
}
void red_drawable_unref(RedDrawable *red_drawable)
@@ -244,7 +215,7 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
&update, ext_cmd.cmd.data)) {
break;
}
- if (!validate_surface(worker->display_channel, update.surface_id)) {
+ if (!display_channel_validate_surface(worker->display_channel, update.surface_id)) {
spice_warning("Invalid surface in QXL_CMD_UPDATE");
} else {
display_channel_draw(worker->display_channel, &update.area, update.surface_id);
@@ -285,7 +256,7 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
spice_error("bad command type");
}
n++;
- if (red_channel_all_blocked(&worker->display_channel->common.base)
+ if (red_channel_all_blocked(RED_CHANNEL(worker->display_channel))
|| spice_get_monotonic_time_ns() - start > NSEC_PER_SEC / 100) {
worker->event_timeout = 0;
return n;
@@ -398,80 +369,6 @@ static void flush_all_qxl_commands(RedWorker *worker)
flush_cursor_commands(worker);
}
-static int common_channel_config_socket(RedChannelClient *rcc)
-{
- RedClient *client = red_channel_client_get_client(rcc);
- MainChannelClient *mcc = red_client_get_main(client);
- RedsStream *stream = red_channel_client_get_stream(rcc);
- CommonGraphicsChannelClient *ccc = COMMON_GRAPHICS_CHANNEL_CLIENT(rcc);
- int flags;
- int delay_val;
- gboolean low_bw;
-
- if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
- spice_warning("accept failed, %s", strerror(errno));
- return FALSE;
- }
-
- if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
- spice_warning("accept failed, %s", strerror(errno));
- return FALSE;
- }
-
- // TODO - this should be dynamic, not one time at channel creation
- low_bw = main_channel_client_is_low_bandwidth(mcc);
- common_graphics_channel_client_set_low_bandwidth(ccc, low_bw);
- delay_val = low_bw ? 0 : 1;
- /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending
- * on the delayed ack timeout on the other side.
- * Instead of using Nagle's, we need to implement message buffering on
- * the application level.
- * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/
- */
- if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
- sizeof(delay_val)) == -1) {
- if (errno != ENOTSUP) {
- spice_warning("setsockopt failed, %s", strerror(errno));
- }
- }
- return TRUE;
-}
-
-CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size,
- const char *name,
- uint32_t channel_type, int migration_flags,
- ChannelCbs *channel_cbs,
- channel_handle_parsed_proc handle_parsed)
-{
- RedChannel *channel = NULL;
- CommonGraphicsChannel *common;
-
- spice_return_val_if_fail(worker, NULL);
- spice_return_val_if_fail(channel_cbs, NULL);
- spice_return_val_if_fail(!channel_cbs->config_socket, NULL);
- spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL);
- spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL);
-
- channel_cbs->config_socket = common_channel_config_socket;
- channel_cbs->alloc_recv_buf = common_alloc_recv_buf;
- channel_cbs->release_recv_buf = common_release_recv_buf;
-
- channel = red_channel_create_parser(size, red_worker_get_server(worker),
- &worker->core, channel_type,
- worker->qxl->id, TRUE /* handle_acks */,
- spice_get_client_channel_parser(channel_type, NULL),
- handle_parsed,
- channel_cbs,
- migration_flags);
- spice_return_val_if_fail(channel, NULL);
- red_channel_set_stat_node(channel, stat_add_node(red_worker_get_server(worker),
- worker->stat, name, TRUE));
-
- common = (CommonGraphicsChannel *)channel;
- common->qxl = worker->qxl;
- return common;
-}
-
static void guest_set_client_capabilities(RedWorker *worker)
{
int i;
@@ -503,7 +400,7 @@ static void guest_set_client_capabilities(RedWorker *worker)
return;
}
if ((worker->display_channel == NULL) ||
- (RED_CHANNEL(worker->display_channel)->clients_num == 0)) {
+ (red_channel_get_n_clients(RED_CHANNEL(worker->display_channel)) == 0)) {
red_qxl_set_client_capabilities(worker->qxl, FALSE, caps);
} else {
// Take least common denominator
@@ -542,7 +439,7 @@ static void cursor_connect(RedWorker *worker, RedClient *client, RedsStream *str
red_channel_client_ack_zero_messages_window(rcc);
red_channel_client_push_set_ack(rcc);
- cursor_channel_init(channel, ccc);
+ cursor_channel_do_init(channel, ccc);
}
static void handle_dev_update_async(void *opaque, void *payload)
@@ -608,18 +505,6 @@ static void handle_dev_destroy_surfaces(void *opaque, void *payload)
cursor_channel_reset(worker->cursor_channel);
}
-static void display_update_monitors_config(DisplayChannel *display,
- QXLMonitorsConfig *config,
- uint16_t count, uint16_t max_allowed)
-{
-
- if (display->monitors_config)
- monitors_config_unref(display->monitors_config);
-
- display->monitors_config =
- monitors_config_new(config->heads, count, max_allowed);
-}
-
static void red_worker_push_monitors_config(RedWorker *worker)
{
DisplayChannelClient *dcc;
@@ -630,21 +515,6 @@ static void red_worker_push_monitors_config(RedWorker *worker)
}
}
-static void set_monitors_config_to_primary(DisplayChannel *display)
-{
- DrawContext *context = &display->surfaces[0].context;
- QXLHead head = { 0, };
-
- spice_return_if_fail(display->surfaces[0].context.canvas);
-
- if (display->monitors_config)
- monitors_config_unref(display->monitors_config);
-
- head.width = context->width;
- head.height = context->height;
- display->monitors_config = monitors_config_new(&head, 1, 1);
-}
-
static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
QXLDevSurfaceCreate surface)
{
@@ -675,20 +545,22 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
display_channel_create_surface(display, 0, surface.width, surface.height, surface.stride, surface.format,
line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
- set_monitors_config_to_primary(display);
+ display_channel_set_monitors_config_to_primary(display);
- if (display_is_connected(worker) && !worker->display_channel->common.during_target_migrate) {
+ if (display_is_connected(worker) &&
+ !common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->display_channel)))
+ {
/* guest created primary, so it will (hopefully) send a monitors_config
* now, don't send our own temporary one */
if (!worker->driver_cap_monitors_config) {
red_worker_push_monitors_config(worker);
}
- red_pipes_add_verb(&worker->display_channel->common.base,
+ red_pipes_add_verb(RED_CHANNEL(worker->display_channel),
SPICE_MSG_DISPLAY_MARK);
- red_channel_push(&worker->display_channel->common.base);
+ red_channel_push(RED_CHANNEL(worker->display_channel));
}
- cursor_channel_init(worker->cursor_channel, NULL);
+ cursor_channel_do_init(worker->cursor_channel, NULL);
}
static void handle_dev_create_primary_surface(void *opaque, void *payload)
@@ -703,12 +575,12 @@ static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
{
DisplayChannel *display = worker->display_channel;
- if (!validate_surface(display, surface_id))
+ if (!display_channel_validate_surface(display, surface_id))
return;
spice_warn_if_fail(surface_id == 0);
spice_debug(NULL);
- if (!display->surfaces[surface_id].context.canvas) {
+ if (!display_channel_surface_has_canvas(display, surface_id)) {
spice_warning("double destroy of primary surface");
return;
}
@@ -717,8 +589,10 @@ static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
display_channel_destroy_surface_wait(display, 0);
display_channel_surface_unref(display, 0);
+ /* FIXME: accessing private date only for warning purposes...
spice_warn_if_fail(ring_is_empty(&display->streams));
- spice_warn_if_fail(!display->surfaces[surface_id].context.canvas);
+ */
+ spice_warn_if_fail(!display_channel_surface_has_canvas(display, surface_id));
cursor_channel_reset(worker->cursor_channel);
}
@@ -784,10 +658,10 @@ static void handle_dev_start(void *opaque, void *payload)
spice_assert(!worker->running);
if (worker->cursor_channel) {
- COMMON_GRAPHICS_CHANNEL(worker->cursor_channel)->during_target_migrate = FALSE;
+ common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->cursor_channel), FALSE);
}
if (worker->display_channel) {
- worker->display_channel->common.during_target_migrate = FALSE;
+ common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->display_channel), FALSE);
display_channel_wait_for_migrate_data(worker->display_channel);
}
worker->running = TRUE;
@@ -807,16 +681,18 @@ static void handle_dev_oom(void *opaque, void *payload)
RedWorker *worker = opaque;
DisplayChannel *display = worker->display_channel;
- RedChannel *display_red_channel = &display->common.base;
+ RedChannel *display_red_channel = RED_CHANNEL(display);
int ring_is_empty;
spice_return_if_fail(worker->running);
// streams? but without streams also leak
+#if FIXME
spice_debug("OOM1 #draw=%u, #glz_draw=%u current %u pipes %u",
display->drawable_count,
display->glz_drawable_count,
display->current_size,
red_channel_sum_pipes_size(display_red_channel));
+#endif
while (red_process_display(worker, &ring_is_empty)) {
red_channel_push(display_red_channel);
}
@@ -824,12 +700,14 @@ static void handle_dev_oom(void *opaque, void *payload)
display_channel_free_some(worker->display_channel);
red_qxl_flush_resources(worker->qxl);
}
+#if FIXME
spice_debug("OOM2 #draw=%u, #glz_draw=%u current %u pipes %u",
display->drawable_count,
display->glz_drawable_count,
display->current_size,
red_channel_sum_pipes_size(display_red_channel));
red_qxl_clear_pending(worker->qxl->st, RED_DISPATCHER_PENDING_OOM);
+#endif
}
static void handle_dev_reset_cursor(void *opaque, void *payload)
@@ -842,9 +720,7 @@ static void handle_dev_reset_cursor(void *opaque, void *payload)
static void handle_dev_reset_image_cache(void *opaque, void *payload)
{
RedWorker *worker = opaque;
- DisplayChannel *display = worker->display_channel;
-
- image_cache_reset(&display->image_cache);
+ display_channel_reset_image_cache(worker->display_channel);
}
static void handle_dev_destroy_surface_wait_async(void *opaque, void *payload)
@@ -964,7 +840,7 @@ static void handle_dev_monitors_config_async(void *opaque, void *payload)
/* TODO: raise guest bug (requires added QXL interface) */
return;
}
- display_update_monitors_config(worker->display_channel, dev_monitors_config,
+ display_channel_update_monitors_config(worker->display_channel, dev_monitors_config,
MIN(count, msg->max_monitors),
MIN(max_allowed, msg->max_monitors));
red_worker_push_monitors_config(worker);
@@ -1509,17 +1385,28 @@ RedWorker* red_worker_new(QXLInstance *qxl,
worker->event_timeout = INF_EVENT_WAIT;
- worker->cursor_channel = cursor_channel_new(worker);
+ worker->cursor_channel = cursor_channel_new(reds, worker->qxl, &worker->core);
+ red_channel_set_stat_node(RED_CHANNEL(worker->cursor_channel),
+ stat_add_node(red_worker_get_server(worker),
+ worker->stat,
+ "cursor_channel", TRUE));
channel = RED_CHANNEL(worker->cursor_channel);
red_channel_register_client_cbs(channel, client_cursor_cbs, dispatcher);
+ g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
reds_register_channel(reds, channel);
// TODO: handle seemless migration. Temp, setting migrate to FALSE
- worker->display_channel = display_channel_new(reds, worker, FALSE, reds_get_streaming_video(reds),
+ worker->display_channel = display_channel_new(reds, worker->qxl, &worker->core,
+ FALSE, reds_get_streaming_video(reds),
init_info.n_surfaces);
+ red_channel_set_stat_node(RED_CHANNEL(worker->display_channel),
+ stat_add_node(red_worker_get_server(worker),
+ worker->stat,
+ "display_channel", TRUE));
channel = RED_CHANNEL(worker->display_channel);
red_channel_register_client_cbs(channel, client_display_cbs, dispatcher);
+ g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
@@ -1536,8 +1423,8 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message
- RED_CHANNEL(worker->cursor_channel)->thread_id = pthread_self();
- RED_CHANNEL(worker->display_channel)->thread_id = pthread_self();
+ red_channel_reset_thread_id(RED_CHANNEL(worker->cursor_channel));
+ red_channel_reset_thread_id(RED_CHANNEL(worker->display_channel));
GMainLoop *loop = g_main_loop_new(worker->core.main_context, FALSE);
g_main_loop_run(loop);
diff --git a/server/red-worker.h b/server/red-worker.h
index 501128b..ebc5a97 100644
--- a/server/red-worker.h
+++ b/server/red-worker.h
@@ -25,73 +25,9 @@
typedef struct RedWorker RedWorker;
-#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30)
-
-#define CHANNEL_RECEIVE_BUF_SIZE 1024
-typedef struct CommonGraphicsChannel {
- RedChannel base; // Must be the first thing
-
- QXLInstance *qxl;
- uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE];
- uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
- int during_target_migrate; /* TRUE when the client that is associated with the channel
- is during migration. Turned off when the vm is started.
- The flag is used to avoid sending messages that are artifacts
- of the transition from stopped vm to loaded vm (e.g., recreation
- of the primary surface) */
-} CommonGraphicsChannel;
-
-#define COMMON_GRAPHICS_CHANNEL(Channel) ((CommonGraphicsChannel*)(Channel))
-
-enum {
- RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
- RED_PIPE_ITEM_TYPE_INVAL_ONE,
-
- RED_PIPE_ITEM_TYPE_COMMON_LAST
-};
-
-typedef struct RedVerbItem {
- RedPipeItem base;
- uint16_t verb;
-} RedVerbItem;
-
-static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem *item)
-{
- red_channel_client_init_send_data(rcc, item->verb, NULL);
-}
-
-static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
-{
- RedVerbItem *item = spice_new(RedVerbItem, 1);
-
- red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB);
- item->verb = verb;
- red_channel_client_pipe_add(rcc, &item->base);
-}
-
-static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer data)
-{
- uint16_t verb = GPOINTER_TO_UINT(data);
- red_pipe_add_verb(rcc, verb);
-}
-
-
-static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
-{
- red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb));
-}
-
RedWorker* red_worker_new(QXLInstance *qxl,
const ClientCbs *client_cursor_cbs,
const ClientCbs *client_display_cbs);
bool red_worker_run(RedWorker *worker);
-void red_drawable_unref(RedDrawable *red_drawable);
-
-CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size,
- const char *name,
- uint32_t channel_type, int migration_flags,
- ChannelCbs *channel_cbs,
- channel_handle_parsed_proc handle_parsed);
-
#endif
diff --git a/server/reds-private.h b/server/reds-private.h
index 74a251b..4b86d2d 100644
--- a/server/reds-private.h
+++ b/server/reds-private.h
@@ -120,8 +120,7 @@ struct RedsState {
Ring mig_target_clients;
int num_mig_target_clients;
- int num_of_channels;
- Ring channels;
+ GList *channels;
int mouse_mode;
int is_client_mouse_allowed;
int dispatcher_allows_client_mouse;
diff --git a/server/reds.c b/server/reds.c
index 9f5551e..27fc5da 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -463,15 +463,13 @@ void stat_update_value(RedsState *reds, uint32_t value)
void reds_register_channel(RedsState *reds, RedChannel *channel)
{
spice_assert(reds);
- ring_add(&reds->channels, &channel->link);
- reds->num_of_channels++;
+ reds->channels = g_list_append(reds->channels, channel);
}
void reds_unregister_channel(RedsState *reds, RedChannel *channel)
{
- if (ring_item_is_linked(&channel->link)) {
- ring_remove(&channel->link);
- reds->num_of_channels--;
+ if (g_list_find(reds->channels, channel)) {
+ reds->channels = g_list_remove(reds->channels, channel);
} else {
spice_warning("not found");
}
@@ -479,11 +477,13 @@ void reds_unregister_channel(RedsState *reds, RedChannel *channel)
static RedChannel *reds_find_channel(RedsState *reds, uint32_t type, uint32_t id)
{
- RingItem *now;
+ GList *l;
- RING_FOREACH(now, &reds->channels) {
- RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
- if (channel->type == type && channel->id == id) {
+ for (l = reds->channels; l != NULL; l = l->next) {
+ RedChannel *channel = l->data;
+ uint32_t this_type, this_id;
+ g_object_get(channel, "channel-type", &this_type, "id", &this_id, NULL);
+ if (this_type == type && this_id == id) {
return channel;
}
}
@@ -552,7 +552,7 @@ static void reds_reset_vdp(RedsState *reds)
* In addition, there used to be a misshandling of AGENT_TOKENS message in spice-gtk: it
* overrides the amount of tokens, instead of adding the given amount.
*/
- if (red_channel_test_remote_cap(&reds->main_channel->base,
+ if (red_channel_test_remote_cap(RED_CHANNEL(reds->main_channel),
SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
dev->priv->agent_attached = FALSE;
} else {
@@ -743,7 +743,7 @@ static void reds_agent_remove(RedsState *reds)
reds->vdagent = NULL;
reds_update_mouse_mode(reds);
if (reds_main_channel_connected(reds) &&
- !red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) {
+ !red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds->main_channel))) {
main_channel_push_agent_disconnected(reds->main_channel);
}
}
@@ -995,7 +995,9 @@ SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *reds)
static int channel_supports_multiple_clients(RedChannel *channel)
{
- switch (channel->type) {
+ uint32_t type;
+ g_object_get(channel, "channel-type", &type, NULL);
+ switch (type) {
case SPICE_CHANNEL_MAIN:
case SPICE_CHANNEL_DISPLAY:
case SPICE_CHANNEL_CURSOR:
@@ -1007,23 +1009,25 @@ static int channel_supports_multiple_clients(RedChannel *channel)
static void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info)
{
- RingItem *now;
+ GList *l;
int used_channels = 0;
- RING_FOREACH(now, &reds->channels) {
- RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
+ for (l = reds->channels; l != NULL; l = l->next) {
+ uint32_t type, id;
+ RedChannel *channel = l->data;
if (reds->num_clients > 1 &&
!channel_supports_multiple_clients(channel)) {
continue;
}
- channels_info->channels[used_channels].type = channel->type;
- channels_info->channels[used_channels].id = channel->id;
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ channels_info->channels[used_channels].type = type;
+ channels_info->channels[used_channels].id = id;
used_channels++;
}
channels_info->num_of_channels = used_channels;
- if (used_channels != reds->num_of_channels) {
- spice_warning("sent %d out of %d", used_channels, reds->num_of_channels);
+ if (used_channels != g_list_length(reds->channels)) {
+ spice_warning("sent %d out of %d", used_channels, g_list_length(reds->channels));
}
}
@@ -1034,7 +1038,7 @@ SpiceMsgChannels *reds_msg_channels_new(RedsState *reds)
spice_assert(reds != NULL);
channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels)
- + reds->num_of_channels * sizeof(SpiceChannelId));
+ + g_list_length(reds->channels) * sizeof(SpiceChannelId));
reds_fill_channels(reds, channels_info);
@@ -1546,12 +1550,12 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
return FALSE;
}
spice_assert(reds->main_channel);
- channel = &reds->main_channel->base;
+ channel = RED_CHANNEL(reds->main_channel);
}
reds_channel_init_auth_caps(link, channel); /* make sure common caps are set */
- channel_caps = &channel->local_caps;
+ channel_caps = red_channel_get_local_capabilities(channel);
ack.num_common_caps = GUINT32_TO_LE(channel_caps->num_common_caps);
ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
hdr_size += channel_caps->num_common_caps * sizeof(uint32_t);
@@ -1888,13 +1892,13 @@ static void reds_channel_do_link(RedChannel *channel, RedClient *client,
spice_assert(stream);
caps = (uint32_t *)((uint8_t *)link_msg + link_msg->caps_offset);
- channel->client_cbs.connect(channel, client, stream,
- red_client_during_migrate_at_target(client),
- link_msg->num_common_caps,
- link_msg->num_common_caps ? caps : NULL,
- link_msg->num_channel_caps,
- link_msg->num_channel_caps ?
- caps + link_msg->num_common_caps : NULL);
+ red_channel_connect(channel, client, stream,
+ red_client_during_migrate_at_target(client),
+ link_msg->num_common_caps,
+ link_msg->num_common_caps ? caps : NULL,
+ link_msg->num_channel_caps,
+ link_msg->num_channel_caps ?
+ caps + link_msg->num_common_caps : NULL);
}
/*
@@ -3123,7 +3127,7 @@ static RedCharDevice *attach_to_red_agent(RedsState *reds, SpiceCharDeviceInstan
dev->priv->plug_generation++;
if (dev->priv->mig_data ||
- red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) {
+ red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds->main_channel))) {
/* Migration in progress (code is running on the destination host):
* 1. Add the client to spice char device, if it was not already added.
* 2.a If this (qemu-kvm state load side of migration) happens first
@@ -3442,7 +3446,6 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
ring_init(&reds->clients);
reds->num_clients = 0;
reds->main_dispatcher = main_dispatcher_new(reds, reds->core);
- ring_init(&reds->channels);
ring_init(&reds->mig_target_clients);
reds->char_devices = NULL;
reds->mig_wait_disconnect_clients = NULL;
@@ -3986,7 +3989,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *reds, const cha
* be valid (see reds_reset_vdp for more details).
*/
try_seamless = reds->seamless_migration_enabled &&
- red_channel_test_remote_cap(&reds->main_channel->base,
+ red_channel_test_remote_cap(RED_CHANNEL(reds->main_channel),
SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
/* main channel will take care of clients that are still during migration (at target)*/
if (main_channel_migrate_connect(reds->main_channel, reds->config->mig_spice,
diff --git a/server/smartcard.c b/server/smartcard.c
index ec42960..c681d39 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -49,6 +49,61 @@
// Maximal length of APDU
#define APDUBufSize 270
+#define RED_TYPE_SMARTCARD_CHANNEL red_smartcard_channel_get_type()
+
+#define RED_SMARTCARD_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannel))
+#define RED_SMARTCARD_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannelClass))
+#define RED_IS_SMARTCARD_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_SMARTCARD_CHANNEL))
+#define RED_IS_SMARTCARD_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_SMARTCARD_CHANNEL))
+#define RED_SMARTCARD_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannelClass))
+
+typedef struct RedSmartcardChannel RedSmartcardChannel;
+typedef struct RedSmartcardChannelClass RedSmartcardChannelClass;
+typedef struct RedSmartcardChannelPrivate RedSmartcardChannelPrivate;
+
+struct RedSmartcardChannel
+{
+ RedChannel parent;
+
+ RedSmartcardChannelPrivate *priv;
+};
+
+struct RedSmartcardChannelClass
+{
+ RedChannelClass parent_class;
+};
+
+GType red_smartcard_channel_get_type(void) G_GNUC_CONST;
+
+G_DEFINE_TYPE(RedSmartcardChannel, red_smartcard_channel, RED_TYPE_CHANNEL)
+
+#define SMARTCARD_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannelPrivate))
+
+struct RedSmartcardChannelPrivate
+{
+ gpointer padding;
+};
+
+static void
+red_smartcard_channel_init(RedSmartcardChannel *self)
+{
+ self->priv = SMARTCARD_CHANNEL_PRIVATE(self);
+}
+
+RedSmartcardChannel *
+red_smartcard_channel_new(RedsState *reds)
+{
+ return g_object_new(RED_TYPE_SMARTCARD_CHANNEL,
+ "spice-server", reds,
+ "core-interface", reds_get_core_interface(reds),
+ "channel-type", SPICE_CHANNEL_SMARTCARD,
+ "id", 0,
+ "handle-acks", FALSE /* handle_acks */,
+ "migration-flags", (SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
+ NULL);
+}
+
+
G_DEFINE_TYPE(RedCharDeviceSmartcard, red_char_device_smartcard, RED_TYPE_CHAR_DEVICE)
#define RED_CHAR_DEVICE_SMARTCARD_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SMARTCARD, RedCharDeviceSmartcardPrivate))
@@ -74,10 +129,6 @@ typedef struct RedMsgItem {
static RedMsgItem *smartcard_get_vsc_msg_item(RedChannelClient *rcc, VSCMsgHeader *vheader);
static void smartcard_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item);
-typedef struct SmartCardChannel {
- RedChannel base;
-} SmartCardChannel;
-
static struct Readers {
uint32_t num;
SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
@@ -531,43 +582,53 @@ static void smartcard_connect_client(RedChannel *channel, RedClient *client,
}
}
-SmartCardChannel *g_smartcard_channel;
-
-static void smartcard_init(RedsState *reds)
+static void
+red_smartcard_channel_constructed(GObject *object)
{
- ChannelCbs channel_cbs = { NULL, };
+ RedSmartcardChannel *self = RED_SMARTCARD_CHANNEL(object);
+ RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
ClientCbs client_cbs = { NULL, };
- uint32_t migration_flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
-
- spice_assert(!g_smartcard_channel);
- channel_cbs.config_socket = smartcard_channel_client_config_socket;
- channel_cbs.on_disconnect = smartcard_channel_client_on_disconnect;
- channel_cbs.send_item = smartcard_channel_send_item;
- channel_cbs.hold_item = smartcard_channel_hold_pipe_item;
- channel_cbs.release_item = smartcard_channel_release_pipe_item;
- channel_cbs.alloc_recv_buf = smartcard_channel_client_alloc_msg_rcv_buf;
- channel_cbs.release_recv_buf = smartcard_channel_client_release_msg_rcv_buf;
- channel_cbs.handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
- channel_cbs.handle_migrate_data = smartcard_channel_client_handle_migrate_data;
-
- g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
- reds,
- reds_get_core_interface(reds),
- SPICE_CHANNEL_SMARTCARD, 0,
- FALSE /* handle_acks */,
- smartcard_channel_client_handle_message,
- &channel_cbs,
- migration_flags);
-
- if (!g_smartcard_channel) {
- spice_error("failed to allocate Smartcard Channel");
- }
+ G_OBJECT_CLASS(red_smartcard_channel_parent_class)->constructed(object);
client_cbs.connect = smartcard_connect_client;
- red_channel_register_client_cbs(&g_smartcard_channel->base, &client_cbs, NULL);
+ red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
+
+ reds_register_channel(reds, RED_CHANNEL(self));
+}
+
+static void
+red_smartcard_channel_class_init(RedSmartcardChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(RedSmartcardChannelPrivate));
+
+ object_class->constructed = red_smartcard_channel_constructed;
+
+ channel_class->handle_message = smartcard_channel_client_handle_message,
+
+ channel_class->config_socket = smartcard_channel_client_config_socket;
+ channel_class->on_disconnect = smartcard_channel_client_on_disconnect;
+ channel_class->send_item = smartcard_channel_send_item;
+ channel_class->hold_item = smartcard_channel_hold_pipe_item;
+ channel_class->release_item = smartcard_channel_release_pipe_item;
+ channel_class->alloc_recv_buf = smartcard_channel_client_alloc_msg_rcv_buf;
+ channel_class->release_recv_buf = smartcard_channel_client_release_msg_rcv_buf;
+ channel_class->handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
+ channel_class->handle_migrate_data = smartcard_channel_client_handle_migrate_data;
+
+}
+
+/* FIXME: remove global */
+RedSmartcardChannel *g_smartcard_channel;
+
+static void smartcard_init(RedsState *reds)
+{
+ spice_assert(!g_smartcard_channel);
- reds_register_channel(reds, &g_smartcard_channel->base);
+ g_smartcard_channel = red_smartcard_channel_new(reds);
}
diff --git a/server/sound.c b/server/sound.c
index e87428f..6982be3 100644
--- a/server/sound.c
+++ b/server/sound.c
@@ -31,6 +31,7 @@
#include "spice.h"
#include "red-common.h"
+#include "dummy-channel.h"
#include "dummy-channel-client.h"
#include "main-channel.h"
#include "main-channel-client.h"
@@ -218,6 +219,7 @@ static void snd_disconnect_channel(SndChannel *channel)
SndWorker *worker;
RedsState *reds;
RedChannel *red_channel;
+ uint32_t type;
if (!channel || !channel->stream) {
spice_debug("not connected");
@@ -225,8 +227,9 @@ static void snd_disconnect_channel(SndChannel *channel)
}
red_channel = red_channel_client_get_channel(channel->channel_client);
reds = snd_channel_get_server(channel);
+ g_object_get(red_channel, "channel-type", &type, NULL);
spice_debug("SndChannel=%p rcc=%p type=%d",
- channel, channel->channel_client, red_channel->type);
+ channel, channel->channel_client, type);
worker = channel->worker;
channel->cleanup(channel);
red_channel_client_disconnect(worker->connection->channel_client);
@@ -999,12 +1002,14 @@ static void snd_disconnect_channel_client(RedChannelClient *rcc)
{
SndWorker *worker;
RedChannel *channel = red_channel_client_get_channel(rcc);
+ uint32_t type;
spice_assert(channel);
- spice_assert(channel->data);
- worker = (SndWorker *)channel->data;
+ worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
+ spice_assert(worker);
+ g_object_get(channel, "channel-type", &type, NULL);
- spice_debug("channel-type=%d", channel->type);
+ spice_debug("channel-type=%d", type);
if (worker->connection) {
spice_assert(worker->connection->channel_client == rcc);
snd_disconnect_channel(worker->connection);
@@ -1059,6 +1064,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_start(SpicePlaybackInstance *sin)
sin->st->worker.active = 1;
if (!channel)
return;
+
spice_assert(!playback_channel->base.active);
reds_disable_mm_time(snd_channel_get_server(channel));
playback_channel->base.active = TRUE;
@@ -1078,6 +1084,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_stop(SpicePlaybackInstance *sin)
sin->st->worker.active = 0;
if (!channel)
return;
+
spice_assert(playback_channel->base.active);
reds_enable_mm_time(snd_channel_get_server(channel));
playback_channel->base.active = FALSE;
@@ -1146,7 +1153,9 @@ void snd_set_playback_latency(RedClient *client, uint32_t latency)
SndWorker *now = workers;
for (; now; now = now->next) {
- if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection &&
+ uint32_t type;
+ g_object_get(now->base_channel, "channel-type", &type, NULL);
+ if (type == SPICE_CHANNEL_PLAYBACK && now->connection &&
red_channel_client_get_client(now->connection->channel_client) == client) {
if (red_channel_client_test_remote_cap(now->connection->channel_client,
@@ -1214,7 +1223,7 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
int migration, int num_common_caps, uint32_t *common_caps,
int num_caps, uint32_t *caps)
{
- SndWorker *worker = channel->data;
+ SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-worker");
PlaybackChannel *playback_channel;
SpicePlaybackState *st = SPICE_CONTAINEROF(worker, SpicePlaybackState, worker);
@@ -1243,7 +1252,7 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
SPICE_PLAYBACK_CAP_CELT_0_5_1);
int client_can_opus = red_channel_client_test_remote_cap(playback_channel->base.channel_client,
SPICE_PLAYBACK_CAP_OPUS);
- int playback_compression = reds_config_get_playback_compression(channel->reds);
+ int playback_compression = reds_config_get_playback_compression(red_channel_get_server(channel));
int desired_mode = snd_desired_audio_mode(playback_compression, st->frequency,
client_can_celt, client_can_opus);
playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW;
@@ -1272,8 +1281,8 @@ static void snd_record_migrate_channel_client(RedChannelClient *rcc)
spice_debug(NULL);
spice_assert(channel);
- spice_assert(channel->data);
- worker = (SndWorker *)channel->data;
+ worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
+ spice_assert(worker);
if (worker->connection) {
spice_assert(worker->connection->channel_client == rcc);
@@ -1463,7 +1472,7 @@ static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStre
int migration, int num_common_caps, uint32_t *common_caps,
int num_caps, uint32_t *caps)
{
- SndWorker *worker = channel->data;
+ SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-worker");
RecordChannel *record_channel;
SpiceRecordState *st = SPICE_CONTAINEROF(worker, SpiceRecordState, worker);
@@ -1501,8 +1510,8 @@ static void snd_playback_migrate_channel_client(RedChannelClient *rcc)
RedChannel *channel = red_channel_client_get_channel(rcc);
spice_assert(channel);
- spice_assert(channel->data);
- worker = (SndWorker *)channel->data;
+ worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
+ spice_assert(worker);
spice_debug(NULL);
if (worker->connection) {
@@ -1543,8 +1552,9 @@ void snd_attach_playback(RedsState *reds, SpicePlaybackInstance *sin)
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
- channel = red_channel_create_dummy(sizeof(RedChannel), reds, SPICE_CHANNEL_PLAYBACK, 0);
+ channel = dummy_channel_new(reds, SPICE_CHANNEL_PLAYBACK, 0);
+ g_object_set_data(G_OBJECT(channel), "sound-worker", playback_worker);
client_cbs.connect = snd_set_playback_peer;
client_cbs.disconnect = snd_disconnect_channel_client;
client_cbs.migrate = snd_playback_migrate_channel_client;
@@ -1572,8 +1582,9 @@ void snd_attach_record(RedsState *reds, SpiceRecordInstance *sin)
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
- channel = red_channel_create_dummy(sizeof(RedChannel), reds, SPICE_CHANNEL_RECORD, 0);
+ channel = dummy_channel_new(reds, SPICE_CHANNEL_RECORD, 0);
+ g_object_set_data(G_OBJECT(channel), "sound-worker", record_worker);
client_cbs.connect = snd_set_record_peer;
client_cbs.disconnect = snd_disconnect_channel_client;
client_cbs.migrate = snd_record_migrate_channel_client;
@@ -1629,7 +1640,9 @@ void snd_set_playback_compression(int on)
SndWorker *now = workers;
for (; now; now = now->next) {
- if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection) {
+ uint32_t type;
+ g_object_get(now->base_channel, "channel-type", &type, NULL);
+ if (type == SPICE_CHANNEL_PLAYBACK && now->connection) {
PlaybackChannel* playback = (PlaybackChannel*)now->connection;
SpicePlaybackState *st = SPICE_CONTAINEROF(now, SpicePlaybackState, worker);
int client_can_celt = red_channel_client_test_remote_cap(playback->base.channel_client,
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 0b37b4a..6441542 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -52,16 +52,6 @@ typedef struct RedVmcPipeItem {
uint32_t buf_used;
} RedVmcPipeItem;
-typedef struct SpiceVmcState {
- RedChannel channel; /* Must be the first item */
- RedChannelClient *rcc;
- RedCharDevice *chardev;
- SpiceCharDeviceInstance *chardev_sin;
- RedVmcPipeItem *pipe_item;
- RedCharDeviceWriteBuffer *recv_from_client_buf;
- uint8_t port_opened;
-} SpiceVmcState;
-
#define RED_TYPE_CHAR_DEVICE_SPICEVMC red_char_device_spicevmc_get_type()
#define RED_CHAR_DEVICE_SPICEVMC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmc))
@@ -89,6 +79,133 @@ static RedCharDevice *red_char_device_spicevmc_new(SpiceCharDeviceInstance *sin,
G_DEFINE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc, RED_TYPE_CHAR_DEVICE)
+#define RED_CHAR_DEVICE_SPICEVMC_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcPrivate))
+
+#define SPICE_TYPE_VMC_STATE spice_vmc_state_get_type()
+
+#define SPICE_VMC_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_VMC_STATE, SpiceVmcState))
+#define SPICE_VMC_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_VMC_STATE, SpiceVmcStateClass))
+#define SPICE_IS_VMC_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SPICE_TYPE_VMC_STATE))
+#define SPICE_IS_VMC_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_VMC_STATE))
+#define SPICE_VMC_STATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_VMC_STATE, SpiceVmcStateClass))
+
+typedef struct SpiceVmcState SpiceVmcState;
+typedef struct SpiceVmcStateClass SpiceVmcStateClass;
+typedef struct SpiceVmcStatePrivate SpiceVmcStatePrivate;
+
+struct SpiceVmcState
+{
+ RedChannel parent;
+
+ SpiceVmcStatePrivate *priv;
+};
+
+struct SpiceVmcStateClass
+{
+ RedChannelClass parent_class;
+};
+
+GType spice_vmc_state_get_type(void) G_GNUC_CONST;
+
+G_DEFINE_TYPE(SpiceVmcState, spice_vmc_state, RED_TYPE_CHANNEL)
+
+#define VMC_STATE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_VMC_STATE, SpiceVmcStatePrivate))
+
+struct SpiceVmcStatePrivate
+{
+ RedChannelClient *rcc;
+ RedCharDevice *chardev;
+ SpiceCharDeviceInstance *chardev_sin;
+ RedVmcPipeItem *pipe_item;
+ RedCharDeviceWriteBuffer *recv_from_client_buf;
+ uint8_t port_opened;
+};
+
+enum {
+ PROP0,
+ PROP_DEVICE_INSTANCE
+};
+
+static void
+spice_vmc_state_get_property(GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SpiceVmcState *self = SPICE_VMC_STATE(object);
+
+ switch (property_id)
+ {
+ case PROP_DEVICE_INSTANCE:
+ g_value_set_pointer(value, self->priv->chardev_sin);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+spice_vmc_state_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SpiceVmcState *self = SPICE_VMC_STATE(object);
+
+ switch (property_id)
+ {
+ case PROP_DEVICE_INSTANCE:
+ self->priv->chardev_sin = g_value_get_pointer(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void spicevmc_connect(RedChannel *channel, RedClient *client,
+ RedsStream *stream, int migration, int num_common_caps,
+ uint32_t *common_caps, int num_caps, uint32_t *caps);
+
+static void
+spice_vmc_state_constructed(GObject *object)
+{
+ SpiceVmcState *self = SPICE_VMC_STATE(object);
+ ClientCbs client_cbs = { NULL, };
+ RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
+
+ G_OBJECT_CLASS(spice_vmc_state_parent_class)->constructed(object);
+
+ client_cbs.connect = spicevmc_connect;
+ red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
+
+ red_channel_init_outgoing_messages_window(RED_CHANNEL(self));
+
+ self->priv->chardev = red_char_device_spicevmc_new(self->priv->chardev_sin,
+ reds, self);
+
+ reds_register_channel(reds, RED_CHANNEL(self));
+}
+
+static void
+spice_vmc_state_init(SpiceVmcState *self)
+{
+ self->priv = VMC_STATE_PRIVATE(self);
+}
+
+SpiceVmcState *spice_vmc_state_new(RedsState *reds, uint8_t channel_type, SpiceCharDeviceInstance *sin)
+{
+ static uint8_t id[256] = { 0, };
+ return g_object_new(SPICE_TYPE_VMC_STATE,
+ "spice-server", reds,
+ "core-interface", reds_get_core_interface(reds),
+ "channel-type", channel_type,
+ "id", id[channel_type]++,
+ "handle-acks", FALSE,
+ "migration-flags", (SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
+ "device-instance", sin,
+ NULL);
+}
+
typedef struct RedPortInitPipeItem {
RedPipeItem base;
char* name;
@@ -117,17 +234,17 @@ static RedPipeItem *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance *
sif = spice_char_device_get_interface(sin);
- if (!state->rcc) {
+ if (!state->priv->rcc) {
return NULL;
}
- if (!state->pipe_item) {
+ if (!state->priv->pipe_item) {
msg_item = spice_new0(RedVmcPipeItem, 1);
- red_pipe_item_init(&msg_item->base, RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
+ red_pipe_item_init_full(&msg_item->base, RED_PIPE_ITEM_TYPE_SPICEVMC_DATA, free);
} else {
- spice_assert(state->pipe_item->buf_used == 0);
- msg_item = state->pipe_item;
- state->pipe_item = NULL;
+ spice_assert(state->priv->pipe_item->buf_used == 0);
+ msg_item = state->priv->pipe_item;
+ state->priv->pipe_item = NULL;
}
n = sif->read(sin, msg_item->buf,
@@ -137,7 +254,7 @@ static RedPipeItem *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance *
msg_item->buf_used = n;
return (RedPipeItem *)msg_item;
} else {
- state->pipe_item = msg_item;
+ state->priv->pipe_item = msg_item;
return NULL;
}
}
@@ -149,21 +266,21 @@ static void spicevmc_chardev_send_msg_to_client(RedPipeItem *msg,
SpiceVmcState *state = opaque;
RedVmcPipeItem *vmc_msg = (RedVmcPipeItem *)msg;
- spice_assert(red_channel_client_get_client(state->rcc) == client);
+ spice_assert(red_channel_client_get_client(state->priv->rcc) == client);
red_pipe_item_ref(vmc_msg);
- red_channel_client_pipe_add_push(state->rcc, (RedPipeItem *)vmc_msg);
+ red_channel_client_pipe_add_push(state->priv->rcc, (RedPipeItem *)vmc_msg);
}
static void spicevmc_port_send_init(RedChannelClient *rcc)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
- SpiceVmcState *state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
- SpiceCharDeviceInstance *sin = state->chardev_sin;
+ SpiceVmcState *state = SPICE_VMC_STATE(channel);
+ SpiceCharDeviceInstance *sin = state->priv->chardev_sin;
RedPortInitPipeItem *item = spice_malloc(sizeof(RedPortInitPipeItem));
red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_PORT_INIT);
item->name = strdup(sin->portname);
- item->opened = state->port_opened;
+ item->opened = state->priv->port_opened;
red_channel_client_pipe_add_push(rcc, &item->base);
}
@@ -188,10 +305,10 @@ static void spicevmc_char_dev_remove_client(RedClient *client, void *opaque)
SpiceVmcState *state = opaque;
spice_printerr("vmc state %p, client %p", state, client);
- spice_assert(state->rcc &&
- red_channel_client_get_client(state->rcc) == client);
+ spice_assert(state->priv->rcc &&
+ red_channel_client_get_client(state->priv->rcc) == client);
- red_channel_client_shutdown(state->rcc);
+ red_channel_client_shutdown(state->priv->rcc);
}
static int spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
@@ -199,8 +316,10 @@ static int spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
int delay_val = 1;
RedsStream *stream = red_channel_client_get_stream(rcc);
RedChannel *channel = red_channel_client_get_channel(rcc);
+ uint32_t type;
- if (channel->type == SPICE_CHANNEL_USBREDIR) {
+ g_object_get(channel, "channel-type", &type, NULL);
+ if (type == SPICE_CHANNEL_USBREDIR) {
if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
&delay_val, sizeof(delay_val)) != 0) {
if (errno != ENOTSUP && errno != ENOPROTOOPT) {
@@ -224,19 +343,19 @@ static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
return;
}
- state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
+ state = SPICE_VMC_STATE(channel);
- if (state->recv_from_client_buf) { /* partial message which wasn't pushed to device */
- red_char_device_write_buffer_release(state->chardev, state->recv_from_client_buf);
- state->recv_from_client_buf = NULL;
+ if (state->priv->recv_from_client_buf) { /* partial message which wasn't pushed to device */
+ red_char_device_write_buffer_release(state->priv->chardev, state->priv->recv_from_client_buf);
+ state->priv->recv_from_client_buf = NULL;
}
- if (state->chardev) {
- if (red_char_device_client_exists(state->chardev, client)) {
- red_char_device_client_remove(state->chardev, client);
+ if (state->priv->chardev) {
+ if (red_char_device_client_exists(state->priv->chardev, client)) {
+ red_char_device_client_remove(state->priv->chardev, client);
} else {
spice_printerr("client %p have already been removed from char dev %p",
- client, state->chardev);
+ client, state->priv->chardev);
}
}
@@ -245,17 +364,17 @@ static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
if (!red_channel_client_is_destroying(rcc))
red_channel_client_destroy(rcc);
- state->rcc = NULL;
- sif = spice_char_device_get_interface(state->chardev_sin);
+ state->priv->rcc = NULL;
+ sif = spice_char_device_get_interface(state->priv->chardev_sin);
if (sif->state) {
- sif->state(state->chardev_sin, 0);
+ sif->state(state->priv->chardev_sin, 0);
}
}
static SpiceVmcState *spicevmc_red_channel_client_get_state(RedChannelClient *rcc)
{
RedChannel *channel = red_channel_client_get_channel(rcc);
- return SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
+ return SPICE_VMC_STATE(channel);
}
static int spicevmc_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
@@ -283,7 +402,7 @@ static int spicevmc_channel_client_handle_migrate_data(RedChannelClient *rcc,
spice_error("bad header");
return FALSE;
}
- return red_char_device_restore(state->chardev, &mig_data->base);
+ return red_char_device_restore(state->priv->chardev, &mig_data->base);
}
static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
@@ -295,14 +414,14 @@ static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
SpiceCharDeviceInterface *sif;
state = spicevmc_red_channel_client_get_state(rcc);
- sif = spice_char_device_get_interface(state->chardev_sin);
+ sif = spice_char_device_get_interface(state->priv->chardev_sin);
switch (type) {
case SPICE_MSGC_SPICEVMC_DATA:
- spice_assert(state->recv_from_client_buf->buf == msg);
- state->recv_from_client_buf->buf_used = size;
- red_char_device_write_buffer_add(state->chardev, state->recv_from_client_buf);
- state->recv_from_client_buf = NULL;
+ spice_assert(state->priv->recv_from_client_buf->buf == msg);
+ state->priv->recv_from_client_buf->buf_used = size;
+ red_char_device_write_buffer_add(state->priv->chardev, state->priv->recv_from_client_buf);
+ state->priv->recv_from_client_buf = NULL;
break;
case SPICE_MSGC_PORT_EVENT:
if (size != sizeof(uint8_t)) {
@@ -310,7 +429,7 @@ static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
return FALSE;
}
if (sif->base.minor_version >= 2 && sif->event != NULL)
- sif->event(state->chardev_sin, *msg);
+ sif->event(state->priv->chardev_sin, *msg);
break;
default:
return red_channel_client_handle_message(rcc, size, type, msg);
@@ -327,20 +446,20 @@ static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
RedChannel *channel = red_channel_client_get_channel(rcc);
RedClient *client = red_channel_client_get_client(rcc);
- state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
+ state = SPICE_VMC_STATE(channel);
switch (type) {
case SPICE_MSGC_SPICEVMC_DATA:
- assert(!state->recv_from_client_buf);
+ assert(!state->priv->recv_from_client_buf);
- state->recv_from_client_buf = red_char_device_write_buffer_get(state->chardev,
- client,
- size);
- if (!state->recv_from_client_buf) {
+ state->priv->recv_from_client_buf = red_char_device_write_buffer_get(state->priv->chardev,
+ client,
+ size);
+ if (!state->priv->recv_from_client_buf) {
spice_error("failed to allocate write buffer");
return NULL;
}
- return state->recv_from_client_buf->buf;
+ return state->priv->recv_from_client_buf->buf;
default:
return spice_malloc(size);
@@ -356,13 +475,14 @@ static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc,
SpiceVmcState *state;
RedChannel *channel = red_channel_client_get_channel(rcc);
- state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
+ state = SPICE_VMC_STATE(channel);
switch (type) {
case SPICE_MSGC_SPICEVMC_DATA:
- if (state->recv_from_client_buf) { /* buffer wasn't pushed to device */
- red_char_device_write_buffer_release(state->chardev, state->recv_from_client_buf);
- state->recv_from_client_buf = NULL;
+ if (state->priv->recv_from_client_buf) { /* buffer wasn't pushed to device */
+ red_char_device_write_buffer_release(state->priv->chardev,
+ state->priv->recv_from_client_buf);
+ state->priv->recv_from_client_buf = NULL;
}
break;
default:
@@ -393,12 +513,12 @@ static void spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc,
SpiceVmcState *state;
RedChannel *channel = red_channel_client_get_channel(rcc);
- state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
+ state = SPICE_VMC_STATE(channel);
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_MAGIC);
spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_VERSION);
- red_char_device_migrate_data_marshall(state->chardev, m);
+ red_char_device_migrate_data_marshall(state->priv->chardev, m);
}
static void spicevmc_red_channel_send_port_init(RedChannelClient *rcc,
@@ -464,6 +584,40 @@ static void spicevmc_red_channel_release_pipe_item(RedChannelClient *rcc,
}
}
+static void
+spice_vmc_state_class_init(SpiceVmcStateClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(SpiceVmcStatePrivate));
+
+ object_class->get_property = spice_vmc_state_get_property;
+ object_class->set_property = spice_vmc_state_set_property;
+ object_class->constructed = spice_vmc_state_constructed;
+
+ channel_class->handle_message = spicevmc_red_channel_client_handle_message;
+
+ channel_class->config_socket = spicevmc_red_channel_client_config_socket;
+ channel_class->on_disconnect = spicevmc_red_channel_client_on_disconnect;
+ channel_class->send_item = spicevmc_red_channel_send_item;
+ channel_class->hold_item = spicevmc_red_channel_hold_pipe_item;
+ channel_class->release_item = spicevmc_red_channel_release_pipe_item;
+ channel_class->alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
+ channel_class->release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
+ channel_class->handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
+ channel_class->handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
+
+ g_object_class_install_property(object_class,
+ PROP_DEVICE_INSTANCE,
+ g_param_spec_pointer("device-instance",
+ "device instance",
+ "Device instance for this channel",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
static void spicevmc_connect(RedChannel *channel, RedClient *client,
RedsStream *stream, int migration, int num_common_caps,
uint32_t *common_caps, int num_caps, uint32_t *caps)
@@ -472,13 +626,15 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
SpiceVmcState *state;
SpiceCharDeviceInstance *sin;
SpiceCharDeviceInterface *sif;
+ uint32_t type, id;
- state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
- sin = state->chardev_sin;
+ state = SPICE_VMC_STATE(channel);
+ sin = state->priv->chardev_sin;
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
- if (state->rcc) {
+ if (state->priv->rcc) {
spice_printerr("channel client %d:%d (%p) already connected, refusing second connection",
- channel->type, channel->id, state->rcc);
+ type, id, state->priv->rcc);
// TODO: notify client in advance about the in use channel using
// SPICE_MSG_MAIN_CHANNEL_IN_USE (for example)
reds_stream_free(stream);
@@ -490,21 +646,21 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
if (!rcc) {
return;
}
- state->rcc = rcc;
+ state->priv->rcc = rcc;
red_channel_client_ack_zero_messages_window(rcc);
if (strcmp(sin->subtype, "port") == 0) {
spicevmc_port_send_init(rcc);
}
- if (!red_char_device_client_add(state->chardev, client, FALSE, 0, ~0, ~0,
+ if (!red_char_device_client_add(state->priv->chardev, client, FALSE, 0, ~0, ~0,
red_channel_client_is_waiting_for_migrate_data(rcc))) {
spice_warning("failed to add client to spicevmc");
red_channel_client_disconnect(rcc);
return;
}
- sif = spice_char_device_get_interface(state->chardev_sin);
+ sif = spice_char_device_get_interface(state->priv->chardev_sin);
if (sif->state) {
sif->state(sin, 1);
}
@@ -514,37 +670,9 @@ RedCharDevice *spicevmc_device_connect(RedsState *reds,
SpiceCharDeviceInstance *sin,
uint8_t channel_type)
{
- static uint8_t id[256] = { 0, };
- SpiceVmcState *state;
- ChannelCbs channel_cbs = { NULL, };
- ClientCbs client_cbs = { NULL, };
-
- channel_cbs.config_socket = spicevmc_red_channel_client_config_socket;
- channel_cbs.on_disconnect = spicevmc_red_channel_client_on_disconnect;
- channel_cbs.send_item = spicevmc_red_channel_send_item;
- channel_cbs.hold_item = spicevmc_red_channel_hold_pipe_item;
- channel_cbs.release_item = spicevmc_red_channel_release_pipe_item;
- channel_cbs.alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
- channel_cbs.release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
- channel_cbs.handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
- channel_cbs.handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
-
- state = (SpiceVmcState*)red_channel_create(sizeof(SpiceVmcState), reds,
- reds_get_core_interface(reds), channel_type, id[channel_type]++,
- FALSE /* handle_acks */,
- spicevmc_red_channel_client_handle_message,
- &channel_cbs,
- SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
- red_channel_init_outgoing_messages_window(&state->channel);
-
- client_cbs.connect = spicevmc_connect;
- red_channel_register_client_cbs(&state->channel, &client_cbs, NULL);
-
- state->chardev = red_char_device_spicevmc_new(sin, reds, state);
- state->chardev_sin = sin;
+ SpiceVmcState *state = spice_vmc_state_new(reds, channel_type, sin);
- reds_register_channel(reds, &state->channel);
- return state->chardev;
+ return state->priv->chardev;
}
/* Must be called from RedClient handling thread. */
@@ -555,17 +683,18 @@ void spicevmc_device_disconnect(RedsState *reds, SpiceCharDeviceInstance *sin)
/* FIXME */
state = (SpiceVmcState *)red_char_device_opaque_get((RedCharDevice*)sin->st);
- if (state->recv_from_client_buf) {
- red_char_device_write_buffer_release(state->chardev, state->recv_from_client_buf);
+ if (state->priv->recv_from_client_buf) {
+ red_char_device_write_buffer_release(state->priv->chardev,
+ state->priv->recv_from_client_buf);
}
/* FIXME */
red_char_device_destroy((RedCharDevice*)sin->st);
- state->chardev = NULL;
+ state->priv->chardev = NULL;
sin->st = NULL;
- reds_unregister_channel(reds, &state->channel);
- free(state->pipe_item);
- red_channel_destroy(&state->channel);
+ reds_unregister_channel(reds, RED_CHANNEL(state));
+ free(state->priv->pipe_item);
+ red_channel_destroy(RED_CHANNEL(state));
}
SPICE_GNUC_VISIBLE void spice_server_port_event(SpiceCharDeviceInstance *sin, uint8_t event)
@@ -580,16 +709,16 @@ SPICE_GNUC_VISIBLE void spice_server_port_event(SpiceCharDeviceInstance *sin, ui
/* FIXME */
state = (SpiceVmcState *)red_char_device_opaque_get((RedCharDevice*)sin->st);
if (event == SPICE_PORT_EVENT_OPENED) {
- state->port_opened = TRUE;
+ state->priv->port_opened = TRUE;
} else if (event == SPICE_PORT_EVENT_CLOSED) {
- state->port_opened = FALSE;
+ state->priv->port_opened = FALSE;
}
- if (state->rcc == NULL) {
+ if (state->priv->rcc == NULL) {
return;
}
- spicevmc_port_send_event(state->rcc, event);
+ spicevmc_port_send_event(state->priv->rcc, event);
}
static void
diff --git a/server/stream.c b/server/stream.c
index 47a6924..004e886 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -20,13 +20,14 @@
#include "stream.h"
#include "display-channel.h"
+#include "display-channel-private.h"
#include "main-channel-client.h"
#define FPS_TEST_INTERVAL 1
#define FOREACH_STREAMS(display, item) \
- for (item = ring_get_head(&(display)->streams); \
+ for (item = ring_get_head(&(display)->priv->streams); \
item != NULL; \
- item = ring_next(&(display)->streams, item))
+ item = ring_next(&(display)->priv->streams, item))
void stream_agent_stats_print(StreamAgent *agent)
{
@@ -72,11 +73,11 @@ void stream_stop(DisplayChannel *display, Stream *stream)
spice_return_if_fail(ring_item_is_linked(&stream->link));
spice_return_if_fail(!stream->current);
- spice_debug("stream %d", get_stream_id(display, stream));
+ spice_debug("stream %d", display_channel_get_stream_id(display, stream));
FOREACH_DCC(display, link, next, dcc) {
StreamAgent *stream_agent;
- stream_agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+ stream_agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
region_clear(&stream_agent->vis_region);
region_clear(&stream_agent->clip);
spice_assert(!red_pipe_item_is_linked(&stream_agent->destroy_item));
@@ -94,25 +95,25 @@ void stream_stop(DisplayChannel *display, Stream *stream)
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &stream_agent->destroy_item);
stream_agent_stats_print(stream_agent);
}
- display->streams_size_total -= stream->width * stream->height;
+ display->priv->streams_size_total -= stream->width * stream->height;
ring_remove(&stream->link);
stream_unref(display, stream);
}
static void stream_free(DisplayChannel *display, Stream *stream)
{
- stream->next = display->free_streams;
- display->free_streams = stream;
+ stream->next = display->priv->free_streams;
+ display->priv->free_streams = stream;
}
void display_channel_init_streams(DisplayChannel *display)
{
int i;
- ring_init(&display->streams);
- display->free_streams = NULL;
+ ring_init(&display->priv->streams);
+ display->priv->free_streams = NULL;
for (i = 0; i < NUM_STREAMS; i++) {
- Stream *stream = &display->streams_buf[i];
+ Stream *stream = &display->priv->streams_buf[i];
ring_item_init(&stream->link);
stream_free(display, stream);
}
@@ -126,7 +127,7 @@ void stream_unref(DisplayChannel *display, Stream *stream)
spice_warn_if_fail(!ring_item_is_linked(&stream->link));
stream_free(display, stream);
- display->stream_count--;
+ display->priv->stream_count--;
}
void stream_agent_unref(DisplayChannel *display, StreamAgent *agent)
@@ -169,7 +170,7 @@ static void update_copy_graduality(DisplayChannel *display, Drawable *drawable)
SpiceBitmap *bitmap;
spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
- if (display->stream_video != SPICE_STREAM_VIDEO_FILTER) {
+ if (display_channel_get_stream_video(display) != SPICE_STREAM_VIDEO_FILTER) {
drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
return;
}
@@ -284,7 +285,7 @@ static void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *s
StreamAgent *agent;
QRegion clip_in_draw_dest;
- agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+ agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
region_or(&agent->vis_region, &drawable->tree_item.base.rgn);
region_init(&clip_in_draw_dest);
@@ -335,7 +336,7 @@ static void before_reattach_stream(DisplayChannel *display,
return;
}
- index = get_stream_id(display, stream);
+ index = display_channel_get_stream_id(display, stream);
DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) {
dcc = dpi->dcc;
agent = dcc_get_stream_agent(dcc, index);
@@ -392,11 +393,11 @@ static void before_reattach_stream(DisplayChannel *display,
static Stream *display_channel_stream_try_new(DisplayChannel *display)
{
Stream *stream;
- if (!display->free_streams) {
+ if (!display->priv->free_streams) {
return NULL;
}
- stream = display->free_streams;
- display->free_streams = display->free_streams->next;
+ stream = display->priv->free_streams;
+ display->priv->free_streams = display->priv->free_streams->next;
return stream;
}
@@ -416,7 +417,7 @@ static void display_channel_create_stream(DisplayChannel *display, Drawable *dra
spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY);
src_rect = &drawable->red_drawable->u.copy.src_area;
- ring_add(&display->streams, &stream->link);
+ ring_add(&display->priv->streams, &stream->link);
stream->current = drawable;
stream->last_time = drawable->creation_time;
stream->width = src_rect->right - src_rect->left;
@@ -438,13 +439,13 @@ static void display_channel_create_stream(DisplayChannel *display, Drawable *dra
}
stream->num_input_frames = 0;
stream->input_fps_start_time = drawable->creation_time;
- display->streams_size_total += stream->width * stream->height;
- display->stream_count++;
+ display->priv->streams_size_total += stream->width * stream->height;
+ display->priv->stream_count++;
FOREACH_DCC(display, link, next, dcc) {
dcc_create_stream(dcc, stream);
}
spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps",
- (int)(stream - display->streams_buf), stream->width,
+ (int)(stream - display->priv->streams_buf), stream->width,
stream->height, stream->dest_area.left, stream->dest_area.top,
stream->dest_area.right, stream->dest_area.bottom,
stream->input_fps);
@@ -520,7 +521,7 @@ void stream_trace_update(DisplayChannel *display, Drawable *drawable)
}
}
- trace = display->items_trace;
+ trace = display->priv->items_trace;
trace_end = trace + NUM_TRACE_ITEMS;
for (; trace < trace_end; trace++) {
if (is_next_stream_frame(display, drawable, trace->width, trace->height,
@@ -591,7 +592,7 @@ static void dcc_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgen
}
dcc_set_max_stream_latency(dcc, 0);
- if (DCC_TO_DC(dcc)->stream_count == 1) {
+ if (DCC_TO_DC(dcc)->priv->stream_count == 1) {
return;
}
for (i = 0; i < NUM_STREAMS; i++) {
@@ -650,7 +651,7 @@ static uint64_t get_initial_bit_rate(DisplayChannelClient *dcc, Stream *stream)
/* dividing the available bandwidth among the active streams, and saving
* (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */
return (RED_STREAM_CHANNEL_CAPACITY * bit_rate *
- stream->width * stream->height) / DCC_TO_DC(dcc)->streams_size_total;
+ stream->width * stream->height) / DCC_TO_DC(dcc)->priv->streams_size_total;
}
static uint32_t get_roundtrip_ms(void *opaque)
@@ -703,7 +704,7 @@ static void update_client_playback_delay(void *opaque, uint32_t delay_ms)
void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
{
- StreamAgent *agent = dcc_get_stream_agent(dcc, get_stream_id(DCC_TO_DC(dcc), stream));
+ StreamAgent *agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(DCC_TO_DC(dcc), stream));
spice_return_if_fail(region_is_empty(&agent->vis_region));
@@ -741,7 +742,7 @@ void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
agent->report_id = rand();
red_pipe_item_init(&report_pipe_item->pipe_item,
RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
- report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc), stream);
+ report_pipe_item->stream_id = display_channel_get_stream_id(DCC_TO_DC(dcc), stream);
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &report_pipe_item->pipe_item);
}
#ifdef STREAM_STATS
@@ -782,7 +783,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
Drawable *update_area_limit)
{
DisplayChannel *display = DCC_TO_DC(dcc);
- int stream_id = get_stream_id(display, stream);
+ int stream_id = display_channel_get_stream_id(display, stream);
StreamAgent *agent = dcc_get_stream_agent(dcc, stream_id);
/* stopping the client from playing older frames at once*/
@@ -868,7 +869,7 @@ static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
*/
void stream_detach_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
{
- Ring *ring = &display->streams;
+ Ring *ring = &display->priv->streams;
RingItem *item = ring_get_head(ring);
GList *link, *next;
DisplayChannelClient *dcc;
@@ -880,12 +881,12 @@ void stream_detach_behind(DisplayChannel *display, QRegion *region, Drawable *dr
item = ring_next(ring, item);
FOREACH_DCC(display, link, next, dcc) {
- StreamAgent *agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+ StreamAgent *agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
if (region_intersects(&agent->vis_region, region)) {
dcc_detach_stream_gracefully(dcc, stream, drawable);
detach = 1;
- spice_debug("stream %d", get_stream_id(display, stream));
+ spice_debug("stream %d", display_channel_get_stream_id(display, stream));
}
}
if (detach && stream->current) {
@@ -904,7 +905,7 @@ void stream_detach_and_stop(DisplayChannel *display)
RingItem *stream_item;
spice_debug(NULL);
- while ((stream_item = ring_get_head(&display->streams))) {
+ while ((stream_item = ring_get_head(&display->priv->streams))) {
Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
detach_stream_gracefully(display, stream, NULL);
@@ -914,7 +915,7 @@ void stream_detach_and_stop(DisplayChannel *display)
void stream_timeout(DisplayChannel *display)
{
- Ring *ring = &display->streams;
+ Ring *ring = &display->priv->streams;
RingItem *item;
red_time_t now = spice_get_monotonic_time_ns();
@@ -937,7 +938,7 @@ void stream_trace_add_drawable(DisplayChannel *display, Drawable *item)
return;
}
- trace = &display->items_trace[display->next_item_trace++ & ITEMS_TRACE_MASK];
+ trace = &display->priv->items_trace[display->priv->next_item_trace++ & ITEMS_TRACE_MASK];
trace->time = item->creation_time;
trace->first_frame_time = item->first_frame_time;
trace->frames_count = item->frames_count;
diff --git a/server/stream.h b/server/stream.h
index 29071f5..f337059 100644
--- a/server/stream.h
+++ b/server/stream.h
@@ -41,9 +41,6 @@
#define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // 2.5Mbps
#define MAX_FPS 30
-/* move back to display_channel once struct private */
-typedef struct DisplayChannel DisplayChannel;
-
typedef struct Stream Stream;
typedef struct RedStreamActivateReportItem {
--
2.4.11
More information about the Spice-devel
mailing list